forked from Minecraft/minecraft_manager
476 lines
21 KiB
Python
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)
|