diff --git a/__init__.py b/__init__.py
index e69de29..4527f3e 100644
--- a/__init__.py
+++ b/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'minecraft_manager.apps.MinecraftManagerAppConfig'
diff --git a/admin.py b/admin.py
index 6cc4532..5de50b1 100644
--- a/admin.py
+++ b/admin.py
@@ -4,7 +4,7 @@ from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
-from minecraft_manager.models import Application, Note, Ticket, TicketNote, Player, IP, UserSettings, Alert
+from minecraft_manager.models import Application, Note, Ticket, TicketNote, Player, IP, UserSettings, Alert, Attachment
from minecraft_manager.api.admin import register as api_register
@@ -90,6 +90,14 @@ class IPAdmin(admin.ModelAdmin):
search_fields = ["player__username", "ip"]
+class AttachmentAdmin(admin.ModelAdmin):
+ list_display = ["file_name", "model_name"]
+
+ def model_name(self, attachment):
+ return attachment.ref_name
+ model_name.short_description = "Model"
+
+
try:
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
@@ -101,6 +109,7 @@ try:
admin.site.register(Player, PlayerAdmin)
admin.site.register(IP, IPAdmin)
admin.site.register(Alert)
+ admin.site.register(Attachment, AttachmentAdmin)
api_register()
except admin.sites.AlreadyRegistered:
pass
diff --git a/apps.py b/apps.py
new file mode 100644
index 0000000..a5fc31c
--- /dev/null
+++ b/apps.py
@@ -0,0 +1,12 @@
+from django.apps import AppConfig
+from django.db.models.signals import pre_delete
+from minecraft_manager.signals.pre_delete import attachment_delete
+
+
+class MinecraftManagerAppConfig(AppConfig):
+ name = 'minecraft_manager'
+ verbose_name = "Minecraft Manager"
+
+ def ready(self):
+ pre_delete.connect(attachment_delete)
+
diff --git a/bot/commands.py b/bot/commands.py
index 9d6f4c1..dd7c2ec 100644
--- a/bot/commands.py
+++ b/bot/commands.py
@@ -153,6 +153,29 @@ class Commands(commands.Cog):
if not api.plugin(api.PLUGIN_DENY, application.username):
await self.bot.discord_message(ctx.message.channel, "Could not deny in-game, is the server running?")
+ @commands.command()
+ async def clear(self, ctx, app_id: int):
+ await self._clear(ctx, app_id)
+
+ @app.command("clear")
+ async def app_clear(self, ctx, app_id: int):
+ await self._clear(ctx, app_id)
+
+ async def _clear(self, ctx, app_id: int):
+ application = get_application(app_id)
+ if not application:
+ await self.bot.discord_message(ctx.message.channel, "An Application with that ID doesn't exist.")
+ return
+
+ if not application.accepted:
+ application.accepted = None
+ application.save()
+ if Player.objects.filter(username__iexact=application.username).exists():
+ player = Player.objects.get(username__iexact=application.username)
+ player.application_id = application.id
+ player.save()
+ await self.bot.discord_message(ctx.message.channel, "App ID **{0}** was successfully cleared.".format(app_id))
+
@commands.command()
async def search(self, ctx, search: str):
await self._search(ctx, search)
diff --git a/forms.py b/forms.py
index d0a37b3..d16ab7c 100644
--- a/forms.py
+++ b/forms.py
@@ -30,7 +30,7 @@ class TicketForm(ModelForm):
fields = ['player', 'message', 'priority', 'world', 'x', 'y', 'z']
widgets = {
'player': TextInput,
- 'message': Textarea,
+ 'message': Textarea(attrs={'style': 'display: block;'}),
}
@@ -39,7 +39,7 @@ class NoteForm(ModelForm):
model = Note
fields = ['player', 'message', 'importance']
widgets = {
- 'message': Textarea
+ 'message': Textarea(attrs={'style': 'display: block;'})
}
diff --git a/migrations/0015_auto_20210206_2140.py b/migrations/0015_auto_20210206_2140.py
new file mode 100644
index 0000000..fcb0e44
--- /dev/null
+++ b/migrations/0015_auto_20210206_2140.py
@@ -0,0 +1,29 @@
+# Generated by Django 2.2.3 on 2021-02-06 21:40
+
+from django.db import migrations, models
+import minecraft_manager.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('minecraft_manager', '0014_auto_20190930_1103'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Attachment',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('ref_model', models.CharField(choices=[('T', 'Ticket Note'), ('N', 'Note')], max_length=1)),
+ ('ref_id', models.IntegerField()),
+ ('file', models.FileField(upload_to=minecraft_manager.models._attachment_upload_to)),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ],
+ ),
+ migrations.AlterField(
+ model_name='application',
+ name='reference',
+ field=models.CharField(blank=True, max_length=50, null=True, verbose_name='How did you find out about our server?'),
+ ),
+ ]
diff --git a/models.py b/models.py
index db11175..ad6ea38 100644
--- a/models.py
+++ b/models.py
@@ -1,13 +1,13 @@
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:
@@ -252,6 +252,10 @@ class Ticket(models.Model):
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)
@@ -263,6 +267,10 @@ class TicketNote(models.Model):
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"
@@ -324,10 +332,49 @@ class Note(models.Model):
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)
diff --git a/signals/__init__.py b/signals/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/signals/pre_delete.py b/signals/pre_delete.py
new file mode 100644
index 0000000..cb46ea4
--- /dev/null
+++ b/signals/pre_delete.py
@@ -0,0 +1,2 @@
+def attachment_delete(sender, instance, **kwargs):
+ instance.file.delete(False)
diff --git a/static/minecraft_manager/css/bootswatch-darkly.css b/static/minecraft_manager/css/bootswatch-darkly.css
index 9a5e710..b886c76 100644
--- a/static/minecraft_manager/css/bootswatch-darkly.css
+++ b/static/minecraft_manager/css/bootswatch-darkly.css
@@ -1,4 +1,9 @@
@import url("https://fonts.googleapis.com/css?family=Lato:400,700,400italic");
+/* Custom CSS */
+.nav-sidebar {
+ border-right: 1px solid #464545;
+}
+
/*!
* bootswatch v3.3.7
* Homepage: http://bootswatch.com
diff --git a/static/minecraft_manager/css/bootswatch-flatly.css b/static/minecraft_manager/css/bootswatch-flatly.css
index ba7e9e9..3e0f8f7 100644
--- a/static/minecraft_manager/css/bootswatch-flatly.css
+++ b/static/minecraft_manager/css/bootswatch-flatly.css
@@ -1,4 +1,9 @@
@import url("https://fonts.googleapis.com/css?family=Lato:400,700,400italic");
+/* Custom CSS */
+.nav-sidebar {
+ border-right: 1px solid #ecf0f1;
+}
+
/*!
* bootswatch v3.3.7
* Homepage: http://bootswatch.com
diff --git a/static/minecraft_manager/css/bootswatch-slate.css b/static/minecraft_manager/css/bootswatch-slate.css
index eb90344..599a694 100644
--- a/static/minecraft_manager/css/bootswatch-slate.css
+++ b/static/minecraft_manager/css/bootswatch-slate.css
@@ -1,3 +1,9 @@
+@import url("https://fonts.googleapis.com/css?family=Roboto:400,700");
+/* Custom CSS */
+.nav-sidebar {
+ border-right: 1px solid #1c1e22;
+}
+
/*!
* bootswatch v3.3.7
* Homepage: http://bootswatch.com
diff --git a/static/minecraft_manager/css/bootswatch-solar.css b/static/minecraft_manager/css/bootswatch-solar.css
index 3beb663..b9b0b72 100644
--- a/static/minecraft_manager/css/bootswatch-solar.css
+++ b/static/minecraft_manager/css/bootswatch-solar.css
@@ -1,4 +1,9 @@
@import url("https://fonts.googleapis.com/css?family=Roboto:400,700");
+/* Custom CSS */
+.nav-sidebar {
+ border-right: 1px solid #282828;
+}
+
/*!
* bootswatch v3.3.7
* Homepage: http://bootswatch.com
diff --git a/templates/minecraft_manager/alert.html b/templates/minecraft_manager/alert.html
index 736900a..d84c66a 100644
--- a/templates/minecraft_manager/alert.html
+++ b/templates/minecraft_manager/alert.html
@@ -4,7 +4,7 @@
{% block title %}Alerts{% endblock %}
{% block section %}
-
+
Message |
@@ -14,9 +14,15 @@
{% for alert in alerts %}
-
+
{{ alert.snippet }} |
- {{ alert.seen }} |
+
+ {% if alert.seen %}
+
+ {% else %}
+
+ {% endif %}
+ |
{{ alert.date }} |
{% endfor %}
diff --git a/templates/minecraft_manager/application.html b/templates/minecraft_manager/application.html
index e9368d5..3509399 100644
--- a/templates/minecraft_manager/application.html
+++ b/templates/minecraft_manager/application.html
@@ -3,7 +3,7 @@
{% block title %}Applications{% endblock %}
{% block section %}
-
+
App ID |
@@ -16,12 +16,19 @@
{% for app in applications %}
-
+
{{ app.id }} |
{{ app.username }} |
{{ app.age }} |
{{ app.ever_banned }} |
- {{ app.status }} |
+
+ {{ app.status }}
+ {% if app.accepted is True %}
+
+ {% elif app.accepted is False %}
+
+ {% endif %}
+ |
{{ app.date }} |
{% endfor %}
diff --git a/templates/minecraft_manager/ban.html b/templates/minecraft_manager/ban.html
index d239861..8f41631 100644
--- a/templates/minecraft_manager/ban.html
+++ b/templates/minecraft_manager/ban.html
@@ -2,7 +2,7 @@
{% block title %}Bans{% endblock %}
{% block section %}
-
+
Player |
diff --git a/templates/minecraft_manager/bots.html b/templates/minecraft_manager/bots.html
deleted file mode 100644
index d0ffd81..0000000
--- a/templates/minecraft_manager/bots.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends "minecraft_manager/dashboard.html" %}
-{% load csrf_html %}
-{% block title %}Bots{% endblock %}
-{% block section %}
-
- {% for bot in bots %}
-
{{ bot.name }}: {{ bot.display }}
-
-
- {% endfor %}
-
-{% endblock section %}
\ No newline at end of file
diff --git a/templates/minecraft_manager/dashboard.html b/templates/minecraft_manager/dashboard.html
index d63e4d9..b048493 100644
--- a/templates/minecraft_manager/dashboard.html
+++ b/templates/minecraft_manager/dashboard.html
@@ -28,6 +28,9 @@
{{ user.username }}