from __future__ import absolute_import
import logging, random, string, discord
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth import update_session_auth_hash
from django.apps import apps
from django.conf import settings
from django.contrib.auth.models import User
from django.http import JsonResponse, HttpResponse
from django.urls import reverse
from django.utils import timezone
from django.views.generic import View
from django.forms import modelform_factory
import minecraft_manager.forms as MCMForms
from minecraft_manager.models import Player, UserSettings, Application, IP, Ticket, Warning
import minecraft_manager.api.api as mcm_api
import minecraft_manager.utils as mcm_utils
import minecraft_manager.external.stats as mcm_stats
logger = logging.getLogger(__name__)
def request_allowed(request):
is_authenticated = False
if hasattr(request, 'user'):
if hasattr(request.user, 'is_authenticated'):
is_authenticated = request.user.is_authenticated
password = getattr(settings, 'API_PASSWORD', None)
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']
correct_password = False
if password and request_password:
correct_password = request_password == password
return is_authenticated or correct_password
def clean(model, data):
cleaned = {}
for d in data:
attr = d
if '__' in d:
attr = d.split('__')[0]
if hasattr(model, attr):
cleaned[d] = data[d]
return cleaned
def generate_password():
return "".join([random.choice(string.ascii_letters + string.digits) for idx in range(0, 20)])
class WebAPI(View):
def get(self, request, keyword):
get = request.GET
data = {'success': False, 'message': 'API failed'}
if request_allowed(request):
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):
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 = MCMForms.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('auth.coreprotect_partial'):
access['cpp'] = True
if user.has_perm('auth.coreprotect_full'):
access['cpf'] = True
if user.has_perm('auth.coreprotect_activity'):
access['cpa'] = True
return access
class PluginAPI(View):
def get(self, request, keyword):
json = {'status': True, 'message': '', 'extra': ''}
if request_allowed(request):
get = request.GET
keyword = keyword.lower()
return JsonResponse(json)
def post(self, request, keyword):
json = {'status': True, 'message': '', 'extra': ''}
if request_allowed(request):
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!', embeds=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")
mcm_api.discord_mcm("{0}'s application (#{1}) was {2} by {3}".format(application.username,
application.id,
"accepted" if post['action'] == "True" else "denied",
post['username']))
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()
if not test_ip:
ip = IP(ip=post['ip'], player=player)
ip.save()
else:
ip = IP.objects.get(ip=post['ip'], player=player)
player = Player.objects.get(uuid=post['uuid'])
player.last_seen = timezone.now().strftime("%Y-%m-%d")
player.save()
if new_player and ip.associated:
for assoc in ip.associated:
if assoc.uuid is not player.uuid and assoc.is_banned:
mcm_api.plugin("staff", "Server {0}'s IP matches the banned player {1}".format(player.username, assoc.username))
mcm_api.discord_notification("{0}'s IP matches the banned player {1}".format(player.username, assoc.username), ping=True)
json['status'] = True
json['message'] = "Updated {0}".format(post['username'])
elif "register" == keyword:
player = Player.objects.get(uuid=post['uuid'])
if player.auth_user:
json['status'] = False
json['message'] = "You are already registered. To change your password, contact an Admin."
else:
password = generate_password()
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 = "{}".format(mcm_utils.url_path(settings.MCM_BASE_LINK, 'dashboard/ticket', ticket.id))
msg = mcm_utils.build_ticket(ticket, link)
json['extra'] = {'id': ticket.id, 'link': link}
mcm_api.discord_mcm(embeds=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 = Warning(player=player, message=post['message'], severity=post['severity'], staff=staff.auth_user)
warning.save()
json['message'] = "Warning issued."
link = "{}".format(mcm_utils.url_path(settings.MCM_BASE_LINK, 'dashboard/warning', warning.id))
msg = mcm_utils.build_warning(warning, link)
mcm_api.discord_mcm(embeds=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):
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 MCMForms.__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):
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 MCMForms.__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):
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.objects.filter(**keywords).values()
json = []
for value in objects:
try:
link = "{}".format(mcm_utils.url_path(settings.MCM_BASE_LINK, 'dashboard', request_model, value['id']))
value['link'] = link
except:
pass
json.append(value)
return JsonResponse(json, safe=False)
def post(self, request, request_model):
pass
class StatsAPI(View):
def get(self, request):
json = []
if request_allowed(request):
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