minecraft_manager/api/views.py

453 lines
22 KiB
Python

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("<", "&lt;").replace(">", "&gt;")
if request.user.usersettings.show_timestamp_chat:
html_global += "<div>[{0}] {1}</div>".format(g['date'], g['text'])
else:
html_global += "<div data-toggle='tooltip' title='{0}' data-placement='left'>{1}</div>".format(g['date'], g['text'])
for s in chats['staff']:
s['text'] = s['text'].replace("<", "&lt;").replace(">", "&gt;")
if request.user.usersettings.show_timestamp_chat:
html_staff += "<div>[{0}] {1}</div>".format(s['date'], s['text'])
else:
html_staff += "<div data-toggle='tooltip' title='{0}' data-placement='left'>{1}</div>".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 += "<div class='label label-primary'>{0}</div>".format(p)
html += "<br/>"
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