minecraft_manager/views.py

476 lines
21 KiB
Python

from __future__ import absolute_import
import json, datetime, pytz, os
from django.utils import timezone
from itertools import chain
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render, reverse, redirect
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
from django.conf import settings
from django.views.generic import View
from django.contrib.auth.models import User
from minecraft_manager.models import Application as AppModel, Player as PlayerModel, Ticket as TicketModel, TicketNote as TicketNoteModel, Note as NoteModel, IP as IPModel, Alert as AlertModel, UserSettings as UserSettingsModel, Attachment as AttachmentModel, RefModels
from minecraft_manager.forms import TicketNoteForm, NoteForm
from minecraft_manager.overview import overview_data
from minecraft_manager.utils import resolve_player, build_note, full_reverse
import minecraft_manager.api.api as API
class Overview(View):
def get(self, request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
user_ip = x_forwarded_for.split(',')[0]
else:
user_ip = request.META.get('REMOTE_ADDR')
try:
request.user.usersettings.last_ip = user_ip
except:
request.user.usersettings = UserSettingsModel(auth_user=request.user)
request.user.usersettings.last_ip = user_ip
request.user.usersettings.save()
return render(request, 'minecraft_manager/overview.html', {'current_app': 'overview', 'data': overview_data()})
class CoreProtect(View):
def get(self, request):
return render(request, 'minecraft_manager/coreprotect.html', {'current_app': 'coreprotect'})
class Activity(View):
def get(self, request):
return render(request, 'minecraft_manager/activity.html', {'current_app': 'activity'})
class Ban(View):
def get(self, request):
ban_file = os.path.join(settings.MINECRAFT_BASE_DIR, 'banned-players.json')
with open(ban_file, encoding='utf-8') as f:
bans = json.load(f)
for idx, ban in enumerate(bans):
ban['source'] = API.strip_format(ban['source'])
if PlayerModel.objects.filter(uuid=ban['uuid']).exists():
ban['id'] = PlayerModel.objects.get(uuid=ban['uuid']).id
else:
ban['id'] = 0
ban['source'] = API.strip_format(ban['source'])
if ban['expires'] == "forever":
ban['expires'] = "Permanent"
else:
dt = datetime.datetime.strptime(ban['expires'], "%Y-%m-%d %H:%M:%S %z")
dt = dt.astimezone(pytz.timezone(request.user.usersettings.default_timezone))
ban['expires'] = dt.strftime("%m/%d/%y %I:%M %p")
dt = datetime.datetime.strptime(ban['created'], "%Y-%m-%d %H:%M:%S %z")
dt = dt.astimezone(pytz.timezone(request.user.usersettings.default_timezone))
ban['created'] = dt.strftime("%m/%d/%y %I:%M %p")
bans[idx] = ban
bans = sorted(bans, key=lambda ban: ban['created'], reverse=True)
return render(request, 'minecraft_manager/ban.html', {'current_app': 'ban', 'bans': bans})
class Alert(View):
def get(self, request):
alerts = AlertModel.objects.filter(user=request.user).order_by('seen', '-id')
unseen_alerts = AlertModel.objects.filter(user=request.user, seen=False)
return render(request, 'minecraft_manager/alert.html',
{'current_app': 'alert', 'alerts': alerts, 'unseen': len(unseen_alerts)})
def post(self, request):
post = request.POST
if 'action' in post:
if post['action'] == 'mar':
AlertModel.objects.filter(user=request.user).update(seen=True)
alerts = AlertModel.objects.filter(user=request.user).order_by('seen', '-id')
return render(request, 'minecraft_manager/alert.html',
{'current_app': 'alert', 'alerts': alerts, 'unseen': 0})
class AlertInfo(View):
def get(self, request, alert_id):
alert = AlertModel.objects.get(id=alert_id)
alert.seen = True
alert.save()
return render(request, 'minecraft_manager/alert_info.html',
{'current_app': 'alert', 'alert': alert})
def post(self, request, alert_id):
post = request.POST
alert = AlertModel.objects.get(id=alert_id)
if 'action' in post:
if post['action'] == 'mu':
alert.seen = False
alert.save()
return render(request, 'minecraft_manager/alert_info.html',
{'current_app': 'alert', 'alert': alert})
class Application(View):
def get(self, request):
get = request.GET
if 'accepted' in get:
if get['accepted'].lower() == 'true':
applications = AppModel.objects.filter(accepted=True)
elif get['accepted'].lower() == 'false':
applications = AppModel.objects.filter(accepted=False)
else:
applications = AppModel.objects.filter(accepted__isnull=True)
else:
applications1 = AppModel.objects.filter(accepted__isnull=True)
applications2 = AppModel.objects.filter(accepted__isnull=False)
applications = list(chain(applications1, applications2))
return render(request, 'minecraft_manager/application.html', {'current_app': 'application', 'applications': applications})
class Reference(View):
def get(self, request):
applications = AppModel.objects.all()
return render(request, 'minecraft_manager/reference.html', {'current_app': 'application', 'applications': applications})
class ApplicationInfo(View):
@method_decorator(csrf_protect)
def get(self, request, application_id):
application = AppModel.objects.get(id=application_id)
return render(request, 'minecraft_manager/application_info.html', {'current_app': 'application', 'application': application})
def post(self, request, application_id):
post = request.POST
application = AppModel.objects.get(id=application_id)
if post['accept']:
if post['accept'] == 'accept':
application.accepted = True
if post['accept'] == 'deny':
application.accepted = False
application.save()
API.plugin(post['accept'], application.username)
link = full_reverse('application_info', application_id)
API.discord_mcm("[Application #**{0}**]({3}) was **{1}** by **{2}**".format(application.id, "Accepted" if application.accepted else "Denied", request.user.player.username, link))
return render(request, 'minecraft_manager/application_info.html',
{'current_app': 'application', 'application': application})
class Player(View):
def get(self, request):
get = request.GET
if 'search' in get:
search = get['search']
player = resolve_player(search)
if player:
return redirect('{}{}/'.format(reverse('player'), player.id))
else:
players = PlayerModel.objects.filter(username__icontains=search)
else:
players = PlayerModel.objects.all()
ban_file = os.path.join(settings.MINECRAFT_BASE_DIR, 'banned-players.json')
with open(ban_file, encoding='utf-8') as f:
ban_list = json.load(f)
bans = []
for ban in ban_list:
bans.append(ban['uuid'])
return render(request, 'minecraft_manager/player.html', {'current_app': 'player', 'players': players, 'bans': bans})
class PlayerInfo(View):
def _info(self, request, player_id):
player = PlayerModel.objects.get(id=player_id)
ips = IPModel.api.filter(player=player)
tickets = TicketModel.objects.filter(player=player)
notes = NoteModel.objects.filter(player=player)
form = {'ips': ips, 'tickets': tickets, 'notes': notes}
return render(request, 'minecraft_manager/player_info.html',
{'current_app': 'player', 'player': player, 'form': form})
def get(self, request, player_id):
return self._info(request, player_id)
def post(self, request, player_id):
return self._info(request, player_id)
class Ticket(View):
def get(self, request):
tickets1 = TicketModel.objects.filter(resolved=False).order_by('-id')
tickets2 = TicketModel.objects.filter(resolved=True).order_by('-id')
tickets = list(chain(tickets1, tickets2))
return render(request, 'minecraft_manager/ticket.html', {'current_app': 'ticket', 'tickets': tickets})
class TicketInfo(View):
@method_decorator(csrf_protect)
def get(self, request, ticket_id):
ticket = TicketModel.objects.get(id=ticket_id)
active_staff = User.objects.filter(is_active=True)
inactive_staff = User.objects.filter(is_active=False)
ticket_notes = TicketNoteModel.objects.filter(ticket=ticket)
ticket_note_form = TicketNoteForm(instance=request.user)
has_ticket_note = False
for ticket_note in ticket_notes:
if ticket_note.author == request.user:
ticket_note_form = TicketNoteForm(instance=ticket_note)
has_ticket_note = True
if not has_ticket_note:
ticket_note_form.fields['ticket'].initial = ticket_id
form = {'active_staff': active_staff, 'inactive_staff': inactive_staff, 'priority': TicketModel.PRIORITY,
'resolved': ticket.resolved, 'ticket_note_form': ticket_note_form.as_p(), 'ticket_notes': ticket_notes, 'has_ticket_note': has_ticket_note,
'show_ticket_note': False}
return render(request, 'minecraft_manager/ticket_info.html', {'current_app': 'ticket', 'ticket': ticket, 'form': form})
def post(self, request, ticket_id):
post = request.POST
ticket = TicketModel.objects.get(id=ticket_id)
link = full_reverse('ticket_info', ticket_id)
if 'priority' in post:
if post['priority'] != ticket.priority:
API.discord_mcm(
"[Ticket #**{0}**]({4})'s priority was changed from **{1}** to **{2}** by **{3}**".format(ticket.id,
ticket.priority_display,
TicketModel.priority_code_to_display(
post['priority']),
request.user.username,
link)
)
ticket.priority = post['priority']
if 'staff' in post and 'resolved' not in post:
if not ticket.staff or request.user.is_staff:
staff = User.objects.get(id=post['staff'])
if post['staff'] != str(getattr(ticket.staff, 'id', '-1')):
if post['staff'] == str(request.user.id):
API.discord_mcm(
"[Ticket #**{0}**]({2}) was claimed by **{1}**".format(ticket.id, request.user.username, link))
else:
API.discord_mcm(
"[Ticket #**{0}**]({3}) was given to **{1}** by **{2}**".format(ticket.id, staff.username, request.user.username, link))
ticket.staff = staff
if 'resolved' in post:
API.discord_mcm("[Ticket #**{0}**]({2}) was resolved by **{1}**".format(ticket.id, request.user.username, link))
ticket.resolved = True
ticket.save()
show_ticket_note = False
if 'ticket_note' in post:
ticket_note_form = TicketNoteForm(post)
if ticket_note_form.is_valid():
n = ticket_note_form.save(commit=False)
if post['ticket_note'] == 'create':
n.author = request.user
n.save()
elif post['ticket_note'] == 'edit':
db = TicketNoteModel.objects.get(ticket=ticket, author=request.user)
db.message = n.message
db.last_update = timezone.now()
db.save()
# Refresh to get the ID for attachments
note = TicketNoteModel.objects.get(ticket=ticket, author=request.user)
for file in request.FILES.getlist('attachments', []):
attachment = AttachmentModel(ref_model=RefModels.TICKET_NOTE[0], ref_id=note.id, file=file)
attachment.save()
else:
show_ticket_note = True
else:
ticket_note_form = TicketNoteForm(instance=request.user)
ticket_notes = TicketNoteModel.objects.filter(ticket=ticket)
has_ticket_note = False
for ticket_note in ticket_notes:
if ticket_note.author == request.user:
ticket_note_form = TicketNoteForm(instance=ticket_note)
has_ticket_note = True
if not has_ticket_note:
ticket_note_form.fields['ticket'].initial = ticket_id
active_staff = User.objects.filter(is_active=True)
inactive_staff = User.objects.filter(is_active=False)
form = {'active_staff': active_staff, 'inactive_staff': inactive_staff, 'priority': TicketModel.PRIORITY,
'resolved': ticket.resolved, 'ticket_note_form': ticket_note_form.as_p(), 'ticket_notes': ticket_notes, 'has_ticket_note': has_ticket_note,
'show_ticket_note': show_ticket_note}
return render(request, 'minecraft_manager/ticket_info.html',
{'current_app': 'ticket', 'ticket': ticket, 'form': form})
class Note(View):
def get(self, request):
notes = NoteModel.objects.order_by('-id')
return render(request, 'minecraft_manager/note.html', {'current_app': 'note', 'notes': notes})
class NoteInfo(View):
@method_decorator(csrf_protect)
def get(self, request, note_id):
note = NoteModel.objects.get(id=note_id)
form = {'importance': NoteModel.IMPORTANCE}
return render(request, 'minecraft_manager/note_info.html', {
'current_app': 'note',
'form': form,
'note': note
})
def post(self, request, note_id):
post = request.POST
note = NoteModel.objects.get(id=note_id)
if 'importance' in post:
API.discord_mcm("[Note #**{0}**]({4})'s importance was changed from **{1}** to **{2}** by **{3}**".format(
note.id,
note.importance_display,
NoteModel.importance_code_to_display(post['importance']),
request.user.username,
full_reverse('note_info', note_id))
)
note.importance = post['importance']
note.save()
form = {'importance': NoteModel.IMPORTANCE}
return render(request, 'minecraft_manager/note_info.html', context={
'current_app': 'note',
'form': form,
'note': note
})
class NoteAdd(View):
@method_decorator(csrf_protect)
def get(self, request):
get = request.GET
form = NoteForm()
if 'player' in get:
form.initial = {'player': get['player']}
return render(request, 'minecraft_manager/note_add.html', context={'current_app': 'note', 'form': form.as_p()})
def post(self, request):
post = request.POST
form = NoteForm(post)
if form.is_valid():
note = form.save()
note.staff = request.user
note.save()
API.discord_mcm(embed=build_note(note, full_reverse('note_info', note.id)))
for file in request.FILES.getlist('attachments', []):
attachment = AttachmentModel(ref_model=RefModels.NOTE[0], ref_id=note.id, file=file)
attachment.save()
return redirect("{0}{1}".format(full_reverse('note'), note.id))
else:
return render(request, 'minecraft_manager/note_add.html', context={'current_app': 'note', 'form': form})
class Attachment(View):
def get(self, request, attachment_id):
attachment = AttachmentModel.objects.get(id=attachment_id)
resp = HttpResponse(attachment.file)
resp['Content-Disposition'] = f"attachment; filename={attachment.file_name}"
return resp
def delete(self, request, attachment_id):
attachment = AttachmentModel.objects.get(id=attachment_id)
attachment.delete()
return HttpResponse(status=204)
class AddAttachment(View):
def post(self, request, ref_model, ref_id):
for file in request.FILES.getlist('attachments', []):
attachment = AttachmentModel(ref_model=ref_model, ref_id=ref_id, file=file)
attachment.save()
return redirect(request.POST.get('next', reverse('overview')))
class IP(View):
def get(self, request, ip_id):
ip = IPModel.api.get(id=ip_id)
ips = IPModel.api.filter(ip=ip.ip)
return render(request, 'minecraft_manager/ip.html', {'ip': ip, 'ips': ips})
def post(self, request, ip_id):
pass
class Report(View):
def get(self, request):
get = request.GET
results = []
timestamp = None
report = get.get('report')
world = get.get('world')
if report and world:
# Get some results
report_dir = os.path.join(settings.MINECRAFT_BASE_DIR, 'plugins', 'MinecraftManager', 'report.json')
if os.path.exists(report_dir):
with open(report_dir) as rpt:
raw = json.load(rpt)
time = raw.get('time')
timestamp = datetime.datetime.utcfromtimestamp(float(time))
timestamp = pytz.timezone('UTC').localize(timestamp)
timestamp = timestamp.astimezone(pytz.timezone(request.user.usersettings.default_timezone))
for w in raw:
if w.endswith('_nether') and world == 'nether':
world_raw = raw[w]
elif w.endswith('_the_end') and world == 'end':
world_raw = raw[w]
elif w != 'time' and not (w.endswith('_nether') or w.endswith('_the_end')) and world == 'overworld': # Need to think of a way to clean this up...
world_raw = raw[w]
break
results_raw = world_raw.get(report)
for result in results_raw:
if report == 'players':
results.append({'name': result.get('name'), 'x': result.get('x'), 'y': result.get('y'),
'z': result.get('z')})
else:
type_formatted = ' '.join([part.title() for part in result.split('_')])
if report == 'entities':
for location in results_raw[result]:
results.append({'name': type_formatted, 'x': location.get('x'), 'y': location.get('y'),
'z': location.get('z')})
else:
results.append({'name': type_formatted, 'count': results_raw.get(result)})
else:
results = 'NONE'
elif report or world:
results = 'BOTH'
if len(results) == 0:
results = 'EMPTY'
return render(request, 'minecraft_manager/report.html', {'current_app': 'report', 'report': report, 'world': world, 'timestamp': timestamp, 'results': results})
def post(self, request):
pass
class Chat(View):
@staticmethod
def replace_ascii(message):
return message.replace(" ", "\\040").replace("\"", "\\042").replace("#", "\\043").replace("$", "\\044")\
.replace("%", "\\045").replace("&", "\\046").replace("(", "\\050").replace(")", "\\051").replace("*", "\\052")\
.replace("+", "\\053").replace("-", "\\055")
def get(self, request):
staff = hasattr(settings, 'STAFF_LOG')
return render(request, 'minecraft_manager/chat.html', {'current_app': 'chat', 'staff': staff})
def post(self, request):
post = request.POST
if 'chat' in post and 'message' in post:
API.plugin(post['chat'], "{0} {1}".format(request.user.player.username, post['message']))
data = {'success': True, 'message': 'Message sent successfully.'}
else:
data = {'success': False, 'message': 'No chat type or message set.'}
return JsonResponse(data)