439 lines
14 KiB
Python
439 lines
14 KiB
Python
|
from django.db import models
|
||
|
from django.contrib.auth.models import User
|
||
|
from django.db.models import Q
|
||
|
import logging, yaml, pytz, json, os
|
||
|
from django.conf import settings
|
||
|
from datetime import datetime
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
class MinecraftManagerUser(User):
|
||
|
|
||
|
class Meta:
|
||
|
proxy = True
|
||
|
permissions = (
|
||
|
('coreprotect_partial', 'Can use CoreProtect GUI except Command/Chat searches'),
|
||
|
('coreprotect_full', 'Can use full CoreProtect GUI'),
|
||
|
('coreprotect_activity', 'Can use CoreProtect Activity Monitor'),
|
||
|
('bots', 'Can use the bot control page'),
|
||
|
('chat', 'Can use chat page'),
|
||
|
)
|
||
|
|
||
|
|
||
|
class UserSettings(models.Model):
|
||
|
RESULT_OPTIONS = (
|
||
|
(10, '10'),
|
||
|
(25, '25'),
|
||
|
(50, '50'),
|
||
|
(100, '100'),
|
||
|
(-1, 'All')
|
||
|
)
|
||
|
THEME_OPTIONS = (
|
||
|
('DE', 'Default'),
|
||
|
('DA', 'Dark'),
|
||
|
('SO', 'Solar'),
|
||
|
('SL', 'Slate')
|
||
|
)
|
||
|
tzs = []
|
||
|
for tz in pytz.common_timezones:
|
||
|
tzs.append((tz, tz))
|
||
|
TIMEZONES = tuple(tzs)
|
||
|
auth_user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
|
||
|
default_results = models.SmallIntegerField("Default Results", default=10, choices=RESULT_OPTIONS)
|
||
|
default_theme = models.CharField("Theme", max_length=2, default='DE', choices=THEME_OPTIONS)
|
||
|
default_timezone = models.CharField("Timezone", max_length=20, default='UTC', choices=TIMEZONES)
|
||
|
search_player_ip = models.BooleanField("Include IP in Player search", default=False)
|
||
|
show_timestamp_chat = models.BooleanField("Show Timestamp By Chat", default=False)
|
||
|
last_ip = models.CharField(max_length=30, default="127.0.0.1", editable=False)
|
||
|
|
||
|
class Meta:
|
||
|
verbose_name = "User Settings"
|
||
|
verbose_name_plural = "User Settings"
|
||
|
|
||
|
def __str__(self):
|
||
|
return "User Settings : %s" % self.auth_user.username
|
||
|
|
||
|
def __repr__(self):
|
||
|
return self.auth_user.username
|
||
|
|
||
|
|
||
|
class UnansweredManager(models.Manager):
|
||
|
def get_queryset(self):
|
||
|
return super(UnansweredManager, self).get_queryset().filter(accepted=None)
|
||
|
|
||
|
|
||
|
class Application(models.Model):
|
||
|
username = models.CharField("Minecraft Username", max_length=20, unique=True)
|
||
|
age = models.PositiveSmallIntegerField()
|
||
|
player_type = models.TextField("What type of player are you?", max_length=300)
|
||
|
ever_banned = models.BooleanField("Have you ever been banned?", default=False)
|
||
|
ever_banned_explanation = models.TextField("If you were previously banned, will you share why?", max_length=300, blank=True, null=True)
|
||
|
reference = models.CharField("Were you referred to our server?", max_length=50, blank=True, null=True)
|
||
|
read_rules = models.CharField("Have you read the rules?", max_length=10)
|
||
|
accepted = models.NullBooleanField()
|
||
|
date = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
||
|
objects = models.Manager()
|
||
|
unanswered = UnansweredManager()
|
||
|
|
||
|
@property
|
||
|
def status(self):
|
||
|
if self.accepted is not None:
|
||
|
if self.accepted is True:
|
||
|
return "Accepted"
|
||
|
elif self.accepted is False:
|
||
|
return "Denied"
|
||
|
else:
|
||
|
return "Unknown"
|
||
|
else:
|
||
|
return "Unanswered"
|
||
|
|
||
|
@property
|
||
|
def date_display(self):
|
||
|
return str(self.date).split(".")[0]
|
||
|
|
||
|
@property
|
||
|
def json(self):
|
||
|
return {'id': self.id, 'username': self.username, 'age': self.age, 'player_type': self.player_type,
|
||
|
'ever_banned': self.ever_banned, 'ever_banned_explanation': self.ever_banned_explanation,
|
||
|
'reference': self.reference, 'read_rules': self.read_rules, 'status': self.status,
|
||
|
'date': self.date_display}
|
||
|
|
||
|
@property
|
||
|
def skript(self):
|
||
|
return "{0}<:>{1}<:>{2}<:>{3}<:>{4}<:>{5}<:>{6}<:>{7}<:>{8}<:>{9}<:>{10}".format(
|
||
|
"success", self.id, self.username, self.age, self.player_type, self.ever_banned,
|
||
|
self.ever_banned_explanation, self.reference, self.read_rules, self.status, self.date_display
|
||
|
)
|
||
|
|
||
|
def __str__(self):
|
||
|
return "Application: %s" % self.username
|
||
|
|
||
|
def __repr__(self):
|
||
|
return self.username
|
||
|
|
||
|
|
||
|
class Player(models.Model):
|
||
|
auth_user = models.OneToOneField(User, on_delete=models.DO_NOTHING, null=True, blank=True)
|
||
|
uuid = models.CharField(max_length=36, unique=True)
|
||
|
username = models.CharField(max_length=20)
|
||
|
application = models.ForeignKey(Application, on_delete=models.CASCADE, null=True, blank=True)
|
||
|
first_seen = models.DateField(null=True, blank=True)
|
||
|
last_seen = models.DateField(null=True, blank=True)
|
||
|
|
||
|
|
||
|
@property
|
||
|
def is_banned(self):
|
||
|
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)
|
||
|
if bans:
|
||
|
for ban in bans:
|
||
|
if self.uuid == ban['uuid']:
|
||
|
return True
|
||
|
return False
|
||
|
else:
|
||
|
return False
|
||
|
|
||
|
@property
|
||
|
def donor_status(self):
|
||
|
|
||
|
def format_time(timestamp):
|
||
|
return datetime.utcfromtimestamp(timestamp).strftime('%m/%d/%Y')
|
||
|
|
||
|
try:
|
||
|
from django_luckperms.models import LuckPermsPlayerPermissions as lppp
|
||
|
donator = lppp.objects.filter(permission='group.donator', uuid=self.uuid)
|
||
|
if donator.exists():
|
||
|
expiry = donator.first().expiry
|
||
|
if expiry > 0:
|
||
|
return "Until {}".format(format_time(expiry))
|
||
|
else:
|
||
|
return "Permanent"
|
||
|
else:
|
||
|
return "None"
|
||
|
except:
|
||
|
pass
|
||
|
try:
|
||
|
pex_file = os.path.join(getattr(settings, 'MINECRAFT_BASE_DIR', ''), 'plugins/PermissionsEx/permissions.yml')
|
||
|
with open(pex_file) as f:
|
||
|
yml = yaml.load(f)
|
||
|
for user in yml['users']:
|
||
|
if user == self.uuid:
|
||
|
if 'donator' in yml['users'][user]['group']:
|
||
|
u = yml['users'][user]
|
||
|
if 'group-donator-until' in u['options']:
|
||
|
unix_time = float(u['options']['group-donator-until'])
|
||
|
return 'Until {0}'.format(format_time(unix_time))
|
||
|
else:
|
||
|
return 'Permanent'
|
||
|
else:
|
||
|
return 'None'
|
||
|
except:
|
||
|
pass
|
||
|
return "N/A"
|
||
|
|
||
|
@property
|
||
|
def ips(self):
|
||
|
ips = []
|
||
|
query = IP.objects.filter(player=self)
|
||
|
for q in query:
|
||
|
ips.append(q.ip)
|
||
|
return " ".join(ips)
|
||
|
|
||
|
def __str__(self):
|
||
|
return self.username + " (" + self.uuid + ")"
|
||
|
|
||
|
|
||
|
class UnclaimedManager(models.Manager):
|
||
|
def get_queryset(self):
|
||
|
return super(UnclaimedManager, self).get_queryset().filter(staff=None, resolved=False)
|
||
|
|
||
|
|
||
|
class ClaimedManager(models.Manager):
|
||
|
def get_queryset(self):
|
||
|
return super(ClaimedManager, self).get_queryset().filter(staff__isnull=False, resolved=False)
|
||
|
|
||
|
|
||
|
class Ticket(models.Model):
|
||
|
PRIORITY = (
|
||
|
('L', 'Low'),
|
||
|
('M', 'Medium'),
|
||
|
('H', 'High')
|
||
|
)
|
||
|
WORLDS = (
|
||
|
('O', 'Overworld'),
|
||
|
('N', 'Nether'),
|
||
|
('E', 'The End')
|
||
|
)
|
||
|
player = models.ForeignKey(Player, related_name="ticket_player", on_delete=models.CASCADE, blank=True, null=True)
|
||
|
message = models.CharField(max_length=500)
|
||
|
priority = models.CharField(max_length=1, choices=PRIORITY, blank=True, default='L')
|
||
|
staff = models.ForeignKey(User, related_name="ticket_staff", on_delete=models.CASCADE, null=True, blank=True)
|
||
|
resolved = models.BooleanField(default=False)
|
||
|
world = models.CharField(max_length=1, choices=WORLDS, blank=True, null=True)
|
||
|
x = models.CharField(max_length=20, blank=True, null=True)
|
||
|
y = models.CharField(max_length=20, blank=True, null=True)
|
||
|
z = models.CharField(max_length=20, blank=True, null=True)
|
||
|
date = models.DateTimeField(auto_now_add=True, null=True, blank=True)
|
||
|
objects = models.Manager()
|
||
|
unclaimed = UnclaimedManager()
|
||
|
claimed = ClaimedManager()
|
||
|
|
||
|
@property
|
||
|
def location(self):
|
||
|
return "{0}, {1}, {2} in {3}".format(self.x, self.y, self.z, self.world_label)
|
||
|
|
||
|
@property
|
||
|
def world_label(self):
|
||
|
for W in self.WORLDS:
|
||
|
if W[0] == self.world:
|
||
|
return W[1]
|
||
|
return ""
|
||
|
|
||
|
@property
|
||
|
def resolved_label(self):
|
||
|
if self.resolved:
|
||
|
return "Resolved"
|
||
|
else:
|
||
|
return "Unresolved"
|
||
|
|
||
|
@property
|
||
|
def snippet(self):
|
||
|
if len(self.message) > 50:
|
||
|
return self.message[:50] + "..."
|
||
|
else:
|
||
|
return self.message
|
||
|
|
||
|
@property
|
||
|
def issuer(self):
|
||
|
if self.player:
|
||
|
pl = Player.objects.get(id=self.player_id)
|
||
|
return pl.username
|
||
|
else:
|
||
|
return "Unknown"
|
||
|
|
||
|
@property
|
||
|
def claimed_by(self):
|
||
|
if self.staff:
|
||
|
pl = User.objects.get(id=self.staff_id)
|
||
|
return pl.username
|
||
|
else:
|
||
|
return "Unclaimed"
|
||
|
|
||
|
@property
|
||
|
def is_claimed(self):
|
||
|
if self.staff:
|
||
|
return True
|
||
|
else:
|
||
|
return False
|
||
|
|
||
|
@property
|
||
|
def priority_display(self):
|
||
|
for P in self.PRIORITY:
|
||
|
if P[0] == self.priority:
|
||
|
return P[1]
|
||
|
return "Unknown"
|
||
|
|
||
|
@staticmethod
|
||
|
def priority_code_to_display(piority_code):
|
||
|
for P in Ticket.PRIORITY:
|
||
|
if P[0] == piority_code:
|
||
|
return P[1]
|
||
|
return "Unknown"
|
||
|
|
||
|
@property
|
||
|
def date_display(self):
|
||
|
return str(self.date).split(".")[0]
|
||
|
|
||
|
def __str__(self):
|
||
|
username = "Unknown"
|
||
|
try:
|
||
|
pl = Player.objects.get(id=self.player_id)
|
||
|
username = pl.username
|
||
|
except:
|
||
|
pass
|
||
|
return "Ticket from %s" % username
|
||
|
|
||
|
|
||
|
class Warning(models.Model):
|
||
|
SEVERITY = (
|
||
|
('L', 'Low'),
|
||
|
('M', 'Medium'),
|
||
|
('H', 'High')
|
||
|
)
|
||
|
player = models.ForeignKey(Player, related_name="warning_player", on_delete=models.CASCADE)
|
||
|
message = models.CharField(max_length=200)
|
||
|
severity = models.CharField(max_length=1, choices=SEVERITY)
|
||
|
staff = models.ForeignKey(User, related_name="warning_staff", on_delete=models.CASCADE, null=True, blank=True, limit_choices_to=Q(is_active=True))
|
||
|
date = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
||
|
|
||
|
@property
|
||
|
def snippet(self):
|
||
|
if len(self.message) > 50:
|
||
|
return self.message[:50] + "..."
|
||
|
else:
|
||
|
return self.message
|
||
|
|
||
|
@property
|
||
|
def severity_display(self):
|
||
|
for S in self.SEVERITY:
|
||
|
if S[0] == self.severity:
|
||
|
return S[1]
|
||
|
return "Unknown"
|
||
|
|
||
|
@staticmethod
|
||
|
def severity_code_to_display(severity_code):
|
||
|
for S in Warning.SEVERITY:
|
||
|
if S[0] == severity_code:
|
||
|
return S[1]
|
||
|
return "Unknown"
|
||
|
|
||
|
@staticmethod
|
||
|
def resolve(severity):
|
||
|
for S in Warning.SEVERITY:
|
||
|
if severity.lower() in (S[0].lower(), S[1].lower()):
|
||
|
return S[0]
|
||
|
return 'L'
|
||
|
|
||
|
@property
|
||
|
def issuer(self):
|
||
|
if self.staff:
|
||
|
pl = User.objects.get(id=self.staff_id)
|
||
|
return pl.username
|
||
|
else:
|
||
|
return "System"
|
||
|
|
||
|
@property
|
||
|
def issuee(self):
|
||
|
if self.player:
|
||
|
pl = Player.objects.get(id=self.player_id)
|
||
|
return pl.username
|
||
|
else:
|
||
|
return "Unknown"
|
||
|
|
||
|
@property
|
||
|
def date_display(self):
|
||
|
return str(self.date).split(".")[0]
|
||
|
|
||
|
def __str__(self):
|
||
|
username = "Unknown"
|
||
|
try:
|
||
|
pl = Player.objects.get(id=self.player_id)
|
||
|
username = pl.username
|
||
|
except:
|
||
|
pass
|
||
|
return "Warning for %s" % username
|
||
|
|
||
|
|
||
|
class IP(models.Model):
|
||
|
player = models.ForeignKey(Player, on_delete=models.CASCADE)
|
||
|
ip = models.CharField(max_length=30)
|
||
|
|
||
|
class Meta:
|
||
|
verbose_name = "IP"
|
||
|
verbose_name_plural = "IPs"
|
||
|
|
||
|
@property
|
||
|
def associated(self):
|
||
|
ips = IP.objects.filter(ip=self.ip)
|
||
|
players = []
|
||
|
for ip in ips:
|
||
|
if self.player != ip.player:
|
||
|
players.append(ip.player)
|
||
|
if players:
|
||
|
return players
|
||
|
else:
|
||
|
return None
|
||
|
|
||
|
def __str__(self):
|
||
|
player = Player.objects.get(id=self.player_id)
|
||
|
return player.username + " - " + self.ip
|
||
|
|
||
|
|
||
|
class Alert(models.Model):
|
||
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||
|
message = models.TextField(max_length=1000)
|
||
|
seen = models.BooleanField(default=False)
|
||
|
date = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
||
|
|
||
|
@property
|
||
|
def snippet(self):
|
||
|
if len(self.message) > 50:
|
||
|
return self.message[:50] + "..."
|
||
|
else:
|
||
|
return self.message
|
||
|
|
||
|
def __str__(self):
|
||
|
return "Alert for %s" % self.user.username
|
||
|
|
||
|
|
||
|
class Note(models.Model):
|
||
|
NOTABLE = (
|
||
|
('PL', 'Player'),
|
||
|
('TI', 'Ticket'),
|
||
|
('WA', 'Warning')
|
||
|
)
|
||
|
author = models.ForeignKey(User, on_delete=models.CASCADE)
|
||
|
ref_table = models.CharField(max_length=2, choices=NOTABLE)
|
||
|
ref_id = models.CharField(max_length=4)
|
||
|
message = models.TextField(max_length=1000)
|
||
|
last_update = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
||
|
date = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
||
|
|
||
|
@property
|
||
|
def ref_model(self):
|
||
|
if self.ref_table == 'PL':
|
||
|
return Player
|
||
|
elif self.ref_table == 'TI':
|
||
|
return Ticket
|
||
|
elif self.ref_table == 'WA':
|
||
|
return Warning
|
||
|
|
||
|
def __str__(self):
|
||
|
ref = self.ref_model.objects.get(id=self.ref_id)
|
||
|
return "Note: {0}".format(ref)
|
||
|
|
||
|
|
||
|
|