#create your views here. # https://api.mojang.com/users/profiles/minecraft/ from __future__ import absolute_import import json, datetime, pytz, os, sys from django.utils import timezone from itertools import chain from django.http import JsonResponse 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 django.forms.widgets import HiddenInput 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 from minecraft_manager.forms import TicketNoteForm, NoteForm from minecraft_manager.overview import overview_data import minecraft_manager.api.api as API import subprocess 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): #http://www.24carrotcraft.com/assets/cp/index.php?username=etzelia return render(request, 'minecraft_manager/coreprotect.html', {'current_app': 'coreprotect'}) class Activity(View): def get(self, request): #http://www.24carrotcraft.com/assets/cp/activity.php?username=etzelia 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): get = request.GET 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) API.discord_mcm("Application #**{0}** was **{1}** by **{2}**".format(application.id, "Accepted" if application.accepted else "Denied", request.user.player.username)) 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'] results = PlayerModel.objects.filter(username__icontains=search) if len(results) == 1: return redirect('{}{}/'.format(reverse('player'), results[0].id)) else: for result in results: if search.lower() == result.username.lower(): return redirect('{}{}/'.format(reverse('player'), result.id)) players = results 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 get(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 post(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}) class Ticket(View): def get(self, request): get = request.GET 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) if 'priority' in post: if post['priority'] != ticket.priority: API.discord_mcm( "Ticket #**{0}**'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)) 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}** was claimed by **{1}**".format(ticket.id, request.user.username)) else: API.discord_mcm( "Ticket #**{0}** was given to **{1}** by **{2}**".format(ticket.id, staff.username, request.user.username)) ticket.staff = staff if 'resolved' in post: API.discord_mcm("Ticket #**{0}** was resolved by **{1}**".format(ticket.id, request.user.username)) 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() 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}**'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.player.username)) note.importance = post['importance'] note.save() form = {'importance': NoteModel.IMPORTANCE} return render(request, 'minecraft_manager/note_info.html', {'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', {'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( "**{0}** made a **{1}** importance note for **{2}**\nPreview: {3}".format(note.staff.player.username, note.importance_display, note.player.username, note.snippet)) return redirect("{0}{1}".format(reverse('note'), note.id)) else: return render(request, 'minecraft_manager/note_add.html', {'current_app': 'note', 'form': form}) 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) class Bots(View): def assets(self): path = os.path.abspath(os.path.dirname(__file__)) bot_dir = os.path.join(path, 'assets/bots') return bot_dir def get_bots(self): bot_dir = getattr(settings, 'BOT_DIR', None) bots = [] if bot_dir: for file in os.listdir(bot_dir): if file.endswith('.bot.py'): ve = file.replace('.bot.py', '') py = os.path.join(bot_dir, ve, 'bin/python') if os.path.isfile(py): bots.append({'name': file.replace('.bot.py', ''), 'asset': False, 'executable': py}) else: bots.append({'name': file.replace('.bot.py', ''), 'asset': False, 'executable': sys.executable}) # Also get packaged MCM bots for file in os.listdir(self.assets()): if file.endswith('.bot.py'): bots.append({'name': file.replace('.bot.py', ''), 'asset': True, 'executable': sys.executable}) return bots def get_form(self): bots = self.get_bots() plugin_port = getattr(settings, 'PLUGIN_PORT', None) screens = subprocess.getoutput("screen -ls") form = {'screens': screens, 'bots': bots} for bot in bots: form[bot['name']] = True if "{0}_{1}".format(plugin_port, bot['name']) in screens else False return form def get(self, request): return render(request, 'minecraft_manager/bots.html', {'current_app': 'bots', 'form': self.get_form()}) def post(self, request): post = request.POST plugin_port = getattr(settings, 'PLUGIN_PORT', None) for bot in self.get_bots(): if bot['name'] in post: if post[bot['name']] == "stop": subprocess.run('screen -X -S "{0}_{1}" quit'.format(plugin_port, bot['name']), shell=True) elif post[bot['name']] in ('start', 'restart'): subprocess.run('screen -X -S "{0}_{1}" quit'.format(plugin_port, bot['name']), shell=True) path = self.assets() if bot['asset'] else getattr(settings, 'BOT_DIR', "") if not path.endswith("/"): path += "/" print('screen -S {0}_{1} -d -m {2} {3}{1}.bot.py'.format(plugin_port, bot['name'], bot['executable'], path)) subprocess.run( 'screen -S {0}_{1} -d -m {2} {3}{1}.bot.py'.format(plugin_port, bot['name'], bot['executable'], path), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return render(request, 'minecraft_manager/bots.html', {'current_app': 'bots', 'form': self.get_form()})