from __future__ import absolute_import import datetime import logging from django.apps import apps from django.contrib.auth import update_session_auth_hash from django.contrib.auth.forms import PasswordChangeForm from django.contrib.auth.models import User from django.forms import modelform_factory from django.http import JsonResponse, HttpResponse from django.utils import timezone from django.views.generic import View import minecraft_manager.api.api as mcm_api import minecraft_manager.external.stats as mcm_stats import minecraft_manager.forms as mcm_forms import minecraft_manager.utils as mcm_utils from minecraft_manager.api.models import Token from minecraft_manager.models import Player, UserSettings, Application, IP, Ticket, Note logger = logging.getLogger(__name__) def request_allowed(request, permission): is_authenticated = False if hasattr(request, 'user'): if hasattr(request.user, 'is_authenticated'): is_authenticated = request.user.is_authenticated get = request.GET post = request.POST request_password = None if 'api' in get: request_password = get['api'] elif 'api' in post: request_password = post['api'] token_permission = False if Token.objects.filter(active=True, key=request_password).exists(): token = Token.objects.get(active=True, key=request_password) token_permission = getattr(token, permission, False) return is_authenticated or token_permission def clean(model, data): cleaned = {} for d in data: attr = d if '__' in d: attr = d.split('__')[0] if hasattr(model, attr) and attr != "api": cleaned[d] = data[d] return cleaned class WebAPI(View): def get(self, request, keyword): get = request.GET data = {'success': False, 'message': 'API failed'} if request_allowed(request, 'web_get_permission'): keyword = keyword.lower() if keyword == 'log': html_global = "" html_staff = "" chats = mcm_api.get_chats(request.user.usersettings.default_timezone) if chats: for g in chats['global']: g['text'] = g['text'].replace("<", "<").replace(">", ">") if request.user.usersettings.show_timestamp_chat: html_global += "
[{0}] {1}
".format(g['date'], g['text']) else: html_global += "
{1}
".format(g['date'], g['text']) for s in chats['staff']: s['text'] = s['text'].replace("<", "<").replace(">", ">") if request.user.usersettings.show_timestamp_chat: html_staff += "
[{0}] {1}
".format(s['date'], s['text']) else: html_staff += "
{1}
".format(s['date'], s['text']) html = {'global': html_global, 'staff': html_staff} data = {'chats': chats, 'html': html} elif keyword == 'online': query = mcm_api.get_query() html = "" for p in query['players']: html += "
{0}
".format(p) html += "
" data = {'query': query, 'html': html} elif keyword == "coreprotect": if 'username' in get and 'ip' in get: user = User.objects.get(username=get['username']) if user.is_active and user.usersettings.last_ip == get['ip']: data = {'success': True, 'message': self.access_level(user)} else: data = {'success': False, 'message': 'Parameters not set'} else: data = {'message': 'Not Authorized', 'success': False} return JsonResponse(data) def post(self, request, keyword): post = request.POST data = {} if request_allowed(request, 'web_post_permission'): keyword = keyword.lower() if keyword == 'settings' and request.user.usersettings: for s in [a for a in dir(UserSettings) if not a.startswith('__') and not callable(getattr(UserSettings,a))]: if s in post: setattr(request.user.usersettings, s, post[s]) request.user.usersettings.save() data = {'success': True, 'message': 'User Settings saved'} elif keyword == 'password': form = PasswordChangeForm(request.user, post) if form.is_valid(): user = form.save() update_session_auth_hash(request, user) return HttpResponse("success") else: return HttpResponse(form.as_p()) elif keyword == 'alert': form = mcm_forms.AlertForm(request.POST) if form.is_valid(): if mcm_api.create_alert(form.cleaned_data['message']): data = {'success': True} else: data = {'success': False, 'message': 'Could not create Alerts'} else: data = {'success': False, 'message': 'Invalid Message'} elif keyword == "discord": if 'message' in post: ping = post['ping'] if 'ping' in post else False mcm_api.discord_notification(post['message'], ping=ping) data = {'success': True, 'message': "Success", 'extra': {'message': post['message'], 'ping': ping}} else: data = {'success': False, 'message': 'No message supplied'} else: data = {'success': True, 'message': 'Model set to "{0}"'.format(keyword)} else: data = {'message': 'Not Authorized', 'success': False} return JsonResponse(data) def access_level(self, user): access = {'cpp': False, 'cpf': False, 'cpa': False} if user.has_perm('minecraft_manager.coreprotect_partial'): access['cpp'] = True if user.has_perm('minecraft_manager.coreprotect_full'): access['cpf'] = True if user.has_perm('minecraft_manager.coreprotect_activity'): access['cpa'] = True return access class PluginAPI(View): def get(self, request, keyword): json = {'status': True, 'message': '', 'extra': ''} if request_allowed(request, 'plugin_get_permission'): get = request.GET keyword = keyword.lower() return JsonResponse(json) def post(self, request, keyword): json = {'status': True, 'message': '', 'extra': ''} if request_allowed(request, 'plugin_post_permission'): post = request.POST keyword = keyword.lower() if "application" == keyword: if Application.objects.filter(username=post['username']).exists(): application = Application.objects.get(username=post['username']) if application.accepted is not None: json['status'] = False json['message'] = "An application for {0} has already been acted on. Please contact Staff.".format( post['username']) return JsonResponse(json) else: application.accepted = None application.age = post['age'] application.player_type = post['player_type'] application.ever_banned = False if post['ever_banned'] == "no" else True application.ever_banned_explanation = post['ever_banned_explanation'] application.reference = post['reference'] application.read_rules = post['read_rules'] else: application = Application(username=post['username'], age=post['age'], player_type=post['player_type'], ever_banned=False if post['ever_banned'] == "no" else True, ever_banned_explanation= post['ever_banned_explanation'], reference=post['reference'], read_rules=post['read_rules']) application.save() if Player.objects.filter(username__iexact=post['username']).exists(): player = Player.objects.get(username__iexact=post['username']) player.application_id = application.id player.save() json['message'] = "{0}'s application was submitted.".format(application.username) json['extra'] = application.id msg = mcm_utils.build_application(application) mcm_api.discord_mcm(message='New Application!', embed=msg) elif "application_action" == keyword: if Application.objects.filter(id=post['application_id']).exists(): application = Application.objects.get(id=post['application_id']) if application.accepted is not None: json['status'] = False json['message'] = "Application was already {0}.".format( "accepted" if post['action'] == "True" else "denied") else: application.accepted = True if post['action'] == "True" else False application.save() json['message'] = "Application was successfully {0}.".format( "accepted" if post['action'] == "True" else "denied") link = mcm_utils.full_reverse('application_info', application.id) mcm_api.discord_mcm("{0}'s application ([#{1}]({4})) was {2} by {3}".format(application.username, application.id, "accepted" if post['action'] == "True" else "denied", post['username'], link)) mcm_api.plugin("accept" if post['action'] == "True" else "deny", application.username) else: json['status'] = False json['message'] = "No application found." return JsonResponse(json) elif "application_clear" == keyword: if Application.objects.filter(id=post['application_id']).exists(): application = Application.objects.get(id=post['application_id']) if application.accepted is True: json['status'] = False json['message'] = "An accepted application can't be cleared." else: application.accepted = None application.save() json['message'] = "Application was successfully cleared." else: json['status'] = False json['message'] = "No application found." return JsonResponse(json) elif "login" == keyword: player = Player.objects.filter(uuid=post['uuid']).exists() new_player = False if not player: player = Player(uuid=post['uuid'], username=post['username']) new_player = True player.first_seen = timezone.now().strftime("%Y-%m-%d") test_app = Application.objects.filter(username__iexact=post['username']).exists() if test_app: test_app = Application.objects.get(username__iexact=post['username']) player.application = test_app player.save() else: player = Player.objects.get(uuid=post['uuid']) if player.username != post['username']: user = User.objects.filter(username__iexact=player.username).exists() if user: user = User.objects.get(username__iexact=player.username) user.username = post['username'].lower() user.save() mcm_api.create_alert("Name Change: {0} to {1}.".format(player.username, post['username'])) player.username = post['username'] if not player.application: test_app = Application.objects.filter(username__iexact=post['username']).exists() if test_app: test_app = Application.objects.get(username__iexact=player.username) player.application = test_app player.save() test_ip = IP.objects.filter(ip=post['ip'], player=player).exists() last_used = datetime.date.today() if not test_ip: ip = IP(ip=post['ip'], player=player) else: ip = IP.objects.get(ip=post['ip'], player=player) ip.last_used = last_used ip.save() player = Player.objects.get(uuid=post['uuid']) player.last_seen = timezone.now().strftime("%Y-%m-%d") player.save() if new_player and ip.associated: associated = [] for assoc in ip.associated: if assoc.uuid is not player.uuid and assoc.is_banned: associated.append(assoc) if associated: mcm_api.plugin("staff", "Server {0}'s IP matches the banned player(s) {1}".format(player.username, ", ".join([assoc.username for assoc in associated]))) mcm_api.discord_notification("{0}'s IP matches the banned player(s) {1}".format(player.username, ", ".join([assoc.username for assoc in associated])), ping=True) json['status'] = True json['message'] = "Updated {0}".format(post['username']) elif "register" == keyword: player = Player.objects.get(uuid=post['uuid']) password = mcm_api.generate_password() if player.auth_user: player.auth_user.password = password player.auth_user.is_active = True player.auth_user.save() json['message'] = password else: user = User.objects.create_user(username=player.username.lower(), password=password) user.save() player.auth_user = user player.save() json['message'] = password elif "ticket" == keyword: player = Player.objects.get(uuid=post['uuid']) try: ticket = Ticket(player=player, message=post['message'], x=post['x'], y=post['y'], z=post['z'], world=post['world']) ticket.save() json['message'] = "Ticket submitted." link = mcm_utils.full_reverse('ticket_info', ticket.id) msg = mcm_utils.build_ticket(ticket, link) json['extra'] = {'id': ticket.id, 'link': link} mcm_api.discord_mcm(embed=msg, ping=True) except: json['status'] = False json['message'] = "Error while submitting ticket." elif "warning" == keyword: player = Player.objects.get(uuid=post['player']) staff = Player.objects.get(uuid=post['staff']) try: warning = Note(player=player, message=post['message'], importance=post['severity'], staff=staff.auth_user) warning.save() json['message'] = "Warning issued." link = mcm_utils.full_reverse('note_info', warning.id) msg = mcm_utils.build_note(warning, link) mcm_api.discord_mcm(embed=msg) except Exception as ex: json['status'] = False json['message'] = "Error while issuing warning." return JsonResponse(json) class FormAPI(View): def get(self, request, request_model): html = "" if request_allowed(request, 'form_get_permission'): get = request.GET model = None for m in apps.get_app_config('minecraft_manager').get_models(): if m._meta.model_name.upper() == request_model.upper(): model = m break if model: form = None for modelform in mcm_forms.__all__(): if modelform.Meta.model == model: form = modelform() break if not form: form = modelform_factory(model, exclude=('id',))() if 'as' in get: html = getattr(form, 'as_{0}'.format(get['as']))() else: html = form.as_p() return HttpResponse(html) def post(self, request, request_model): html = "" if request_allowed(request, 'form_post_permission'): post = request.POST model = None for m in apps.get_app_config('minecraft_manager').get_models(): if m._meta.model_name.upper() == request_model.upper(): model = m break if model: form = None for modelform in mcm_forms.__all__(): if modelform.Meta.model == model: form = modelform(post) break if not form: form = modelform_factory(model, exclude=('id',))(post) if form.is_valid(): form.save() html = "Saved" else: if 'as' in post: html = getattr(form, 'as_{0}'.format(post['as']))() else: html = form.as_p() return HttpResponse(html) class ModelAPI(View): def get(self, request, request_model): json = [] if request_allowed(request, 'model_get_permission'): get = request.GET model = None for m in apps.get_app_config('minecraft_manager').get_models(): if m._meta.model_name.upper() == request_model.upper(): model = m break if model: keywords = clean(model, get) objects = model.api.filter(**keywords).values() if getattr(model, 'api', False) else model.objects.filter(**keywords).values() json = [] for value in objects: try: link = mcm_utils.full_reverse(f"{request_model}_info", value['id']) value['link'] = link except: pass json.append(value) return JsonResponse(json, safe=False) def post(self, request, request_model): json = {"success": False, "message": ""} if request_allowed(request, 'model_post_permission'): post = request.POST model = None for m in apps.get_app_config('minecraft_manager').get_models(): if m._meta.model_name.upper() == request_model.upper(): model = m break if model: keywords = clean(model, post) if "id" in keywords: try: obj = model.objects.get(id=keywords["id"]) for key in keywords.keys(): setattr(obj, key, keywords[key]) obj.save() json["success"] = True json["message"] = "Model updated" except Exception as ex: print(ex) json["message"] = "Could not update model" else: json["message"] = "Must provide an ID" return JsonResponse(json) class StatsAPI(View): def get(self, request): json = [] if request_allowed(request, 'stats_get_permission'): get = request.GET if 'stat' in get: if 'uuid' in get: json = mcm_stats.one_single(get['uuid'], get['stat']) elif 'username' in get and Player.objects.filter(username__iexact=get['username']).exists(): uuid = Player.objects.get(username__iexact=get['username']).uuid json = mcm_stats.one_single(uuid, get['stat']) else: json = mcm_stats.top_ten_stat(get['stat']) elif 'uuid' in get: json = mcm_stats.top_ten_player(get['uuid']) elif 'username' in get: uuid = Player.objects.get(username__iexact=get['username']).uuid json = mcm_stats.top_ten_player(uuid) return JsonResponse(json, safe=False) def post(self, request): pass