minecraft_manager/views.py

498 lines
23 KiB
Python

#create your views here.
# https://api.mojang.com/users/profiles/minecraft/<username>
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 minecraft_manager.models import Application as AppModel, Player as PlayerModel, Ticket as TicketModel, Warning as WarningModel, IP as IPModel, Alert as AlertModel, Note as NoteModel, UserSettings as UserSettingsModel
from minecraft_manager.forms import WarningForm, NoteForm
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()
unanswered_apps = AppModel.unanswered.count()
accepted_apps = AppModel.objects.filter(accepted=True).count()
denied_apps = AppModel.objects.filter(accepted=False).count()
unclaimed_tickets = TicketModel.unclaimed.count()
claimed_tickets = TicketModel.claimed.count()
resolved_tickets = TicketModel.objects.filter(resolved=True).count()
counts = {'applications': AppModel.objects.count(), 'players': PlayerModel.objects.count(),
"ips": IPModel.objects.count(), "tickets": TicketModel.objects.count(),
"warnings": WarningModel.objects.count()}
form = {'apps': {'unanswered': unanswered_apps, 'accepted': accepted_apps, 'denied': denied_apps},
'tickets': {'unclaimed': unclaimed_tickets, 'claimed': claimed_tickets, 'resolved': resolved_tickets},
'counts': counts}
return render(request, 'minecraft_manager/overview.html', {'current_app': 'overview', 'form': form})
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):
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.objects.filter(player=player)
tickets = TicketModel.objects.filter(player=player)
warnings = WarningModel.objects.filter(player=player)
form = {'ips': ips, 'tickets': tickets, 'warnings': warnings}
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)
return render(request, 'minecraft_manager/player_info.html', {'current_app': 'player', 'player': player})
class Ticket(View):
def get(self, request):
get = request.GET
if 'claimed' in get:
if get['claimed'].lower() == 'true':
tickets = TicketModel.claimed.all()
elif get['claimed'].lower() == 'false':
tickets = TicketModel.unclaimed.all()
else:
tickets = TicketModel.objects.filter(resolved=True)
else:
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)
notes = NoteModel.objects.filter(ref_id=ticket_id, ref_table='TI')
note_form = NoteForm(instance=request.user)
has_note = False
for note in notes:
if note.author == request.user:
note_form = NoteForm(instance=note)
has_note = True
if not has_note:
note_form.fields['ref_table'].initial = 'TI'
note_form.fields['ref_id'].initial = ticket_id
form = {'active_staff': active_staff, 'inactive_staff': inactive_staff, 'priority': TicketModel.PRIORITY,
'resolved': ticket.resolved, 'note_form': note_form.as_p(), 'notes': notes, 'has_note': has_note,
'show_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 post['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))
else:
staff = None
API.discord_mcm(
"Ticket #**{0}** was unclaimed by **{1}**".format(ticket.id, 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_note = False
if 'note' in post:
note_form = NoteForm(post)
if note_form.is_valid():
n = note_form.save(commit=False)
if post['note'] == 'create':
n.author = request.user
n.save()
elif post['note'] == 'edit':
db = NoteModel.objects.get(ref_id=ticket_id, ref_table='TI', author=request.user)
db.message = n.message
db.last_update = timezone.now()
db.save()
else:
show_note = True
else:
note_form = NoteForm(instance=request.user)
notes = NoteModel.objects.filter(ref_id=ticket_id, ref_table='TI')
has_note = False
for note in notes:
if note.author == request.user:
note_form = NoteForm(instance=note)
has_note = True
if not has_note:
note_form.fields['ref_table'].initial = 'TI'
note_form.fields['ref_id'].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, 'note_form': note_form.as_p(), 'notes': notes, 'has_note': has_note,
'show_note': show_note}
return render(request, 'minecraft_manager/ticket_info.html',
{'current_app': 'ticket', 'ticket': ticket, 'form': form})
class Warning(View):
def get(self, request):
warnings = WarningModel.objects.order_by('-id')
return render(request, 'minecraft_manager/warning.html', {'current_app': 'warning', 'warnings': warnings})
class WarningInfo(View):
@method_decorator(csrf_protect)
def get(self, request, warning_id):
warning = WarningModel.objects.get(id=warning_id)
form = {'severity': WarningModel.SEVERITY}
return render(request, 'minecraft_manager/warning_info.html', {'current_app': 'warning', 'form': form, 'warning': warning})
def post(self, request, warning_id):
post = request.POST
warning = WarningModel.objects.get(id=warning_id)
if 'severity' in post:
API.discord_mcm("Warning #**{0}**'s severity was changed from {1} to {2} by {3}".format(warning.id,
warning.severity_display,
WarningModel.severity_code_to_display(
post[
'severity']),
request.user.player.username))
warning.severity = post['severity']
warning.save()
form = {'severity': WarningModel.SEVERITY}
return render(request, 'minecraft_manager/warning_info.html',
{'current_app': 'warning', 'form': form, 'warning': warning})
class WarningAdd(View):
@method_decorator(csrf_protect)
def get(self, request):
form = WarningForm().as_p()
return render(request, 'minecraft_manager/warning_add.html',
{'current_app': 'warning', 'form': form})
def post(self, request):
post = request.POST
form = WarningForm(post)
if form.is_valid():
warning = form.save()
warning.staff = request.user
warning.save()
API.discord_mcm(
"**{0}** issued a **{1}** severity warning to **{2}**\nPreview: {3}".format(warning.staff.player.username,
warning.severity_display,
warning.player.username,
warning.snippet))
return redirect("{0}{1}".format(reverse('warning'), warning.id))
else:
return render(request, 'minecraft_manager/warning_add.html',
{'current_app': 'warning', 'form': form})
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()})