minecraft_manager/models.py

445 lines
13 KiB
Python

from django.db import models
from django.contrib.auth.models import User
from django.db.models import Q
from os.path import basename
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 = (
('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=50, 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 self.auth_user.username
def __repr__(self):
return self.auth_user.username
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("How did you find out about 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()
@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]
def __str__(self):
return self.username
def __repr__(self):
return self.username
class Player(models.Model):
auth_user = models.OneToOneField(User, on_delete=models.SET_NULL, 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.SET_NULL, 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 = []
if not getattr(self.auth_user, 'is_active', False):
query = IP.objects.filter(player=self)
for q in query:
ips.append(q.ip)
return " ".join(ips)
def __str__(self):
return "{} ({})".format(self.username, self.uuid)
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()
@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]
@property
def notes(self):
return TicketNote.objects.filter(ticket=self)
def __str__(self):
return "{}: {}".format(self.issuer, self.snippet)
class TicketNote(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
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 attachments(self):
return Attachment.objects.filter(ref_model=RefModels.TICKET_NOTE[0], ref_id=self.id)
class Meta:
verbose_name = "Ticket Note"
verbose_name_plural = "Ticket Notes"
def __str__(self):
return "Ticket: {0}".format(self.ticket.snippet)
class Note(models.Model):
IMPORTANCE = (
('L', 'Low'),
('M', 'Medium'),
('H', 'High')
)
player = models.ForeignKey(Player, related_name="note_player", on_delete=models.CASCADE)
message = models.CharField(max_length=200)
importance = models.CharField(max_length=1, choices=IMPORTANCE)
staff = models.ForeignKey(User, related_name="note_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 importance_display(self):
for S in self.IMPORTANCE:
if S[0] == self.importance:
return S[1]
return "Unknown"
@staticmethod
def importance_code_to_display(importance_code):
for S in Note.IMPORTANCE:
if S[0] == importance_code:
return S[1]
return "Unknown"
@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]
@property
def attachments(self):
return Attachment.objects.filter(ref_model=RefModels.NOTE[0], ref_id=self.id)
def __str__(self):
return "{}: {}".format(self.issuee, self.snippet)
class RefModels:
TICKET_NOTE = 'T', 'Ticket Note'
NOTE = 'N', 'Note'
choices = TICKET_NOTE, NOTE
@staticmethod
def label(ref: str):
for c in RefModels.choices:
if c[0] == ref:
return c[1]
return "None"
def _attachment_upload_to(instance, filename):
return f"attachments/{instance.ref_name.lower().replace(' ', '_')}s/{instance.ref_id}/{filename}"
class Attachment(models.Model):
ref_model = models.CharField(max_length=1, choices=RefModels.choices)
ref_id = models.IntegerField()
file = models.FileField(upload_to=_attachment_upload_to)
created = models.DateTimeField(auto_now_add=True)
@property
def ref_name(self):
return RefModels.label(self.ref_model)
@property
def file_name(self):
return basename(self.file.name)
def __str__(self):
return self.file.name
class IPManager(models.Manager):
def get_queryset(self):
users = User.objects.filter(is_active=True)
filtered = []
for user in users:
if getattr(user, 'player', False):
ips = IP.objects.filter(player=user.player)
for ip in ips:
filtered.append(ip.ip)
return super(IPManager, self).get_queryset().exclude(ip__in=filtered)
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)
objects = models.Manager()
api = IPManager()
class Meta:
verbose_name = "IP"
verbose_name_plural = "IPs"
@property
def last_used_formatted(self):
if self.last_used:
return self.last_used
else:
return "N/A"
@property
def associated(self):
ips = IP.api.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 "{}: {}".format(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 {}".format(self.user.username)