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) last_used = models.DateField(null=True, blank=True) 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)