Change questions (#19)

This PR updates the questions per Discord.

Reviewed-on: #19
Co-authored-by: jolheiser <john.olheiser@gmail.com>
Co-committed-by: jolheiser <john.olheiser@gmail.com>
master
jolheiser 2022-02-15 23:01:37 +00:00
parent 66cf464f3d
commit aa7e4ea770
15 changed files with 345 additions and 67 deletions

View File

@ -3,7 +3,7 @@ from __future__ import absolute_import
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext as _
from minecraft_manager.models import Application, Note, Ticket, TicketNote, Player, IP, UserSettings, Alert, Attachment from minecraft_manager.models import Application, Note, Ticket, TicketNote, Player, IP, UserSettings, Alert, Attachment
from minecraft_manager.api.admin import register as api_register from minecraft_manager.api.admin import register as api_register

View File

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext as _
from minecraft_manager.api.models import Token from minecraft_manager.api.models import Token

View File

@ -314,7 +314,7 @@ class PluginAPI(View):
warning.save() warning.save()
json['message'] = "Warning issued." json['message'] = "Warning issued."
link = mcm_utils.full_reverse('note_info', warning.id) link = mcm_utils.full_reverse('note_info', warning.id)
msg = mcm_utils.build_warning(warning, link) msg = mcm_utils.build_note(warning, link)
mcm_api.discord_mcm(embed=msg) mcm_api.discord_mcm(embed=msg)
except Exception as ex: except Exception as ex:
json['status'] = False json['status'] = False

29
discord.py 100644
View File

@ -0,0 +1,29 @@
from enum import Enum
from datetime import datetime
from typing import Union
class TimestampStyle(Enum):
SHORT_TIME = "t"
"""16:20"""
LONG_TIME = "T"
"""16:20:30"""
SHORT_DATE = "d"
"""20/04/2021"""
LONG_DATE = "D"
"""20 April 2021"""
SHORT_DATETIME = "f"
"""20 April 2021 16:20"""
LONG_DATETIME = "F"
"""Tuesday, 20 April 2021 16:20"""
RELATIVE = "R"
"""2 months ago"""
def format_timestamp(unix: Union[int, datetime], style: TimestampStyle = TimestampStyle.SHORT_DATETIME) -> str:
t = 0
if isinstance(unix, int):
t = unix
elif isinstance(unix, datetime):
t = unix.timestamp()
return f"<t:{t}:{style}>"

12
external/urls.py vendored
View File

@ -1,10 +1,10 @@
from django.conf.urls import url from django.urls import path
from django.contrib.auth.decorators import login_required
import minecraft_manager.external.views as external import minecraft_manager.external.views as external
urlpatterns = [ urlpatterns = [
url(r'^apply/$', external.Apply.as_view(), name="external-apply"), path('apply/', external.Apply.as_view(), name="external-apply"),
url(r'^ticket/$', external.Ticket.as_view(), name="external-ticket"), path('ticket/', external.Ticket.as_view(), name="external-ticket"),
url(r'^stats/$', external.Stats.as_view(), name="external-stats"), path('stats/', external.Stats.as_view(), name="external-stats"),
url(r'^stats/player/$', external.StatsPlayer.as_view(), name="external-stats-player"), path('stats/player/', external.StatsPlayer.as_view(), name="external-stats-player"),
] ]

View File

@ -13,4 +13,4 @@ class TimezoneMiddleware(MiddlewareMixin):
try: try:
timezone.activate(pytz.timezone(request.user.usersettings.default_timezone)) timezone.activate(pytz.timezone(request.user.usersettings.default_timezone))
except: except:
timezone.deactivate() timezone.deactivate()

View File

@ -66,12 +66,12 @@ class UserSettings(models.Model):
class Application(models.Model): class Application(models.Model):
username = models.CharField("Minecraft Username", max_length=20, unique=True) username = models.CharField("Minecraft Username", max_length=20, unique=True)
age = models.PositiveSmallIntegerField() age = models.PositiveSmallIntegerField()
player_type = models.TextField("What type of player are you?", max_length=300) player_type = models.TextField("What's your favorite thing to do in Minecraft?", max_length=300)
ever_banned = models.BooleanField("Have you ever been banned?", default=False) 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) 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) reference = models.CharField("How did you find out about us? Please give a website or player name, if applicable.", max_length=50, blank=True, null=True)
read_rules = models.CharField("Have you read the rules?", max_length=10) read_rules = models.CharField("Have you read the rules?", max_length=10)
accepted = models.NullBooleanField() accepted = models.BooleanField(null=True)
date = models.DateTimeField(auto_now_add=True, blank=True, null=True) date = models.DateTimeField(auto_now_add=True, blank=True, null=True)
objects = models.Manager() objects = models.Manager()

View File

@ -3,22 +3,19 @@
min-height:100%; min-height:100%;
height:auto!important; height:auto!important;
position:fixed; position:fixed;
top:0px; top:0;
left:0px; left:0;
overflow:hidden; overflow:hidden;
border:0px; border:0;
z-index:-9; z-index:-9;
float:left; float:left;
} }
#form { #form {
background: rgba(255, 255, 255, .9); background: rgba(0, 0, 0, .75);
margin: auto;
display: block; display: block;
width: 35%; width: 75%;
padding-top: 1em; padding: 1em 5em;
padding-bottom: 1em;
padding-left: 5em;
border-radius: 1em; border-radius: 1em;
top: 50%; top: 50%;
left: 50%; left: 50%;
@ -65,6 +62,10 @@
color: black; color: black;
} }
.sub {
margin-left: 1em;
}
.rule { .rule {
margin-bottom: .5em; margin-bottom: .5em;
} }

View File

@ -0,0 +1,249 @@
/* Sakura.css v1.3.1
* ================
* Minimal css theme.
* Project: https://github.com/oxalorg/sakura/
*/
/* Default Sakura Theme */
:root {
--color-blossom: #1d7484;
--color-fade: #982c61;
--color-bg: #f9f9f9;
--color-bg-alt: #f1f1f1;
--color-text: #4a4a4a;
}
/* Sakura Dark Theme */
@media (prefers-color-scheme: dark) {
:root {
--color-blossom: #ffffff;
--color-fade: #c9c9c9;
--color-bg: #222222;
--color-bg-alt: #4a4a4a;
--color-text: #c9c9c9;
}
}
html {
font-size: 62.5%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
}
body {
font-size: 1.8rem;
line-height: 1.618;
max-width: 38em;
margin: auto;
color: var(--color-text);
background-color: var(--color-bg);
padding: 13px;
}
@media (max-width: 684px) {
body {
font-size: 1.53rem;
}
}
@media (max-width: 382px) {
body {
font-size: 1.35rem;
}
}
h1, h2, h3, h4, h5, h6 {
line-height: 1.1;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
font-weight: 700;
margin-top: 3rem;
margin-bottom: 1.5rem;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-word;
}
h1 {
font-size: 2.35em;
}
h2 {
font-size: 2.00em;
}
h3 {
font-size: 1.75em;
}
h4 {
font-size: 1.5em;
}
h5 {
font-size: 1.25em;
}
h6 {
font-size: 1em;
}
p {
margin-top: 0px;
margin-bottom: 2.5rem;
}
small, sub, sup {
font-size: 75%;
}
hr {
border-color: var(--color-blossom);
}
a {
text-decoration: none;
color: var(--color-blossom);
}
a:hover {
color: var(--color-fade);
border-bottom: 2px solid var(--color-text);
}
a:visited {
color: var(--color-blossom);
}
ul {
padding-left: 1.4em;
margin-top: 0px;
margin-bottom: 2.5rem;
}
li {
margin-bottom: 0.4em;
}
blockquote {
margin-left: 0px;
margin-right: 0px;
padding-left: 1em;
padding-top: 0.8em;
padding-bottom: 0.8em;
padding-right: 0.8em;
border-left: 5px solid var(--color-blossom);
margin-bottom: 2.5rem;
background-color: var(--color-bg-alt);
}
blockquote p {
margin-bottom: 0;
}
img, video {
height: auto;
max-width: 100%;
margin-top: 0px;
margin-bottom: 2.5rem;
}
/* Pre and Code */
pre {
background-color: var(--color-bg-alt);
display: block;
padding: 1em;
overflow-x: auto;
margin-top: 0px;
margin-bottom: 2.5rem;
}
code {
font-size: 0.9em;
padding: 0 0.5em;
background-color: var(--color-bg-alt);
white-space: pre-wrap;
}
pre > code {
padding: 0;
background-color: transparent;
white-space: pre;
}
/* Tables */
table {
text-align: justify;
width: 100%;
border-collapse: collapse;
}
td, th {
padding: 0.5em;
border-bottom: 1px solid var(--color-bg-alt);
}
/* Buttons, forms and input */
input, textarea {
border: 1px solid var(--color-text);
}
input:focus, textarea:focus {
border: 1px solid var(--color-blossom);
}
textarea {
width: 100%;
}
.button, button, input[type="submit"], input[type="reset"], input[type="button"] {
display: inline-block;
padding: 5px 10px;
text-align: center;
text-decoration: none;
white-space: nowrap;
background-color: var(--color-blossom);
color: var(--color-bg);
border-radius: 1px;
border: 1px solid var(--color-blossom);
cursor: pointer;
box-sizing: border-box;
}
.button[disabled], button[disabled], input[type="submit"][disabled], input[type="reset"][disabled], input[type="button"][disabled] {
cursor: default;
opacity: .5;
}
.button:focus:enabled, .button:hover:enabled, button:focus:enabled, button:hover:enabled, input[type="submit"]:focus:enabled, input[type="submit"]:hover:enabled, input[type="reset"]:focus:enabled, input[type="reset"]:hover:enabled, input[type="button"]:focus:enabled, input[type="button"]:hover:enabled {
background-color: var(--color-fade);
border-color: var(--color-fade);
color: var(--color-bg);
outline: 0;
}
textarea, select, input {
color: var(--color-text);
padding: 6px 10px;
/* The 6px vertically centers text on FF, ignored by Webkit */
margin-bottom: 10px;
background-color: var(--color-bg-alt);
border: 1px solid var(--color-bg-alt);
border-radius: 4px;
box-shadow: none;
box-sizing: border-box;
}
textarea:focus, select:focus, input:focus {
border: 1px solid var(--color-blossom);
outline: 0;
}
input[type="checkbox"]:focus {
outline: 1px dotted var(--color-blossom);
}
label, legend, fieldset {
display: block;
margin-bottom: .5rem;
font-weight: 600;
}

View File

@ -9,7 +9,7 @@
<!-- <p>Username: {{ application.username }}</p> --> <!-- <p>Username: {{ application.username }}</p> -->
<p>Age: {{ application.age }}</p> <p>Age: {{ application.age }}</p>
<p>Application Date: {{ application.date }}</p> <p>Application Date: {{ application.date }}</p>
<p>Type Of Player:</p> <p>Favorite Activity:</p>
<p class="well">{{ application.player_type }}</p> <p class="well">{{ application.player_type }}</p>
{% if application.accepted is not null %} {% if application.accepted is not null %}
<p>Status: {{ application.status }}</p> <p>Status: {{ application.status }}</p>
@ -26,7 +26,7 @@
<p>Explanation: {{ application.ever_banned_explanation }}</p> <p>Explanation: {{ application.ever_banned_explanation }}</p>
{% endif %} {% endif %}
{% if application.reference %} {% if application.reference %}
<p>Reference: {{ application.reference }}</p> <p>Referral: {{ application.reference }}</p>
{% endif %} {% endif %}
<p>Read The Rules: {{ application.read_rules }}</p> <p>Read The Rules: {{ application.read_rules }}</p>
</div> </div>

View File

@ -1,4 +1,5 @@
{% extends 'minecraft_manager/external/base.html' %} {% extends 'minecraft_manager/external/base.html' %}
{% load str_utils %}
{% block title %}Application Form{% endblock %} {% block title %}Application Form{% endblock %}
@ -7,7 +8,7 @@
{% block form_top %} {% block form_top %}
<h3>Rules</h3> <h3>Rules</h3>
{% for rule in rules %} {% for rule in rules %}
<div class="rule">{{ rule }}</div> <div class="{% if rule|has_prefix:'*' %}sub {% endif %}rule">{{ rule }}</div>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

View File

@ -10,6 +10,7 @@
<script src='https://www.google.com/recaptcha/api.js'></script> <script src='https://www.google.com/recaptcha/api.js'></script>
{% endif %} {% endif %}
<link rel="stylesheet" href="{% static 'minecraft_manager/css/external.css' %}"> <link rel="stylesheet" href="{% static 'minecraft_manager/css/external.css' %}">
<link rel="stylesheet" href="{% static 'minecraft_manager/css/sakura.css' %}">
<link rel="stylesheet" href="//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css"> <link rel="stylesheet" href="//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
</head> </head>
<body> <body>

View File

@ -0,0 +1,10 @@
from django import template
register = template.Library()
def has_prefix(value: str, arg: str) -> bool:
return value.startswith(arg)
register.filter('has_prefix', has_prefix)

42
urls.py
View File

@ -1,47 +1,47 @@
from django.conf.urls import url from django.urls import path
from django.views.generic import RedirectView from django.views.generic import RedirectView
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
import minecraft_manager.views as mcm import minecraft_manager.views as mcm
urlpatterns = [ urlpatterns = [
url(r'^$', RedirectView.as_view(pattern_name='overview')), path('', RedirectView.as_view(pattern_name='overview')),
# Dashboard # Dashboard
url(r'^overview/$', login_required(mcm.Overview.as_view()), name="overview"), path('overview/', login_required(mcm.Overview.as_view()), name="overview"),
url(r'^ban/$', login_required(mcm.Ban.as_view()), name="ban"), path('ban/', login_required(mcm.Ban.as_view()), name="ban"),
# Alerts # Alerts
url(r'^alert/$', login_required(mcm.Alert.as_view()), name="alert"), path('alert/', login_required(mcm.Alert.as_view()), name="alert"),
url(r'^alert/(?P<alert_id>[0-9]{1,5})/$', login_required(mcm.AlertInfo.as_view()), name="alert_info"), path('alert/<int:alert_id>/', login_required(mcm.AlertInfo.as_view()), name="alert_info"),
# Applications # Applications
url(r'^application/$', login_required(mcm.Application.as_view()), name="application"), path('application/', login_required(mcm.Application.as_view()), name="application"),
url(r'^reference/$', login_required(mcm.Reference.as_view()), name="reference"), path('reference/', login_required(mcm.Reference.as_view()), name="reference"),
url(r'^application/(?P<application_id>[0-9]{1,5})/$', login_required(mcm.ApplicationInfo.as_view()), name="application_info"), path('application/<int:application_id>/', login_required(mcm.ApplicationInfo.as_view()), name="application_info"),
# Players # Players
url(r'^player/$', login_required(mcm.Player.as_view()), name="player"), path('player/', login_required(mcm.Player.as_view()), name="player"),
url(r'^player/(?P<player_id>[0-9]{1,5})/$', login_required(mcm.PlayerInfo.as_view()), name="player_info"), path('player/<int:player_id>/', login_required(mcm.PlayerInfo.as_view()), name="player_info"),
# Tickets # Tickets
url(r'^ticket/$', login_required(mcm.Ticket.as_view()), name="ticket"), path('ticket/', login_required(mcm.Ticket.as_view()), name="ticket"),
url(r'^ticket/(?P<ticket_id>[0-9]{1,5})/$', login_required(mcm.TicketInfo.as_view()), name="ticket_info"), path('ticket/<int:ticket_id>/', login_required(mcm.TicketInfo.as_view()), name="ticket_info"),
# Notes # Notes
url(r'^note/$', login_required(mcm.Note.as_view()), name="note"), path('note/', login_required(mcm.Note.as_view()), name="note"),
url(r'^note/(?P<note_id>[0-9]{1,5})/$', login_required(mcm.NoteInfo.as_view()), name='note_info'), path('note/<int:note_id>/', login_required(mcm.NoteInfo.as_view()), name='note_info'),
url(r'^note/add$', login_required(mcm.NoteAdd.as_view()), name="note_add"), path('note/add', login_required(mcm.NoteAdd.as_view()), name="note_add"),
# Attachments # Attachments
url(r'^attachment/(?P<attachment_id>[0-9]{1,5})/$', login_required(mcm.Attachment.as_view()), name="attachment"), path('attachment/<int:attachment_id>/', login_required(mcm.Attachment.as_view()), name="attachment"),
url(r'attachment/(?P<ref_model>[A-Za-z])/(?P<ref_id>[0-9]{1,5})/$', login_required(mcm.AddAttachment.as_view()), name='attachment_add'), path('attachment/<str:ref_model>/<int:ref_id>/', login_required(mcm.AddAttachment.as_view()), name='attachment_add'),
# IP # IP
url(r'^ip/(?P<ip_id>[0-9]{1,5})/$', login_required(mcm.IP.as_view()), name="ip"), path('ip/<int:ip_id>/', login_required(mcm.IP.as_view()), name="ip"),
# Report # Report
url(r'^report/$', login_required(mcm.Report.as_view()), name="report"), path('report/', login_required(mcm.Report.as_view()), name="report"),
# Chat # Chat
url(r'^chat/$', permission_required('minecraft_manager.chat')(mcm.Chat.as_view()), name="chat"), path('chat/', permission_required('minecraft_manager.chat')(mcm.Chat.as_view()), name="chat"),
] ]

View File

@ -30,20 +30,20 @@ def build_application(application):
embed = discord.Embed(colour=discord.Colour(0x417505)) embed = discord.Embed(colour=discord.Colour(0x417505))
embed.title = "Application" embed.title = "Application"
embed.set_thumbnail( embed.set_thumbnail(
url="https://minotar.net/helm/{0}/100.png".format(application.username)) url=f"https://minotar.net/helm/{application.username}/100.png")
embed.add_field(name="Application ID", value=application.id) embed.add_field(name="Application ID", value=application.id)
embed.add_field(name="Username", value=application.username.replace("_", "\\_")) embed.add_field(name="Username", value=application.username.replace("_", "\\_"))
embed.add_field(name="Age", value=application.age) embed.add_field(name="Age", value=application.age)
embed.add_field(name="Type of Player", value=application.player_type) embed.add_field(name="Favorite Activity", value=application.player_type)
embed.add_field(name="Ever been banned", value=application.ever_banned) embed.add_field(name="Ever been banned", value=application.ever_banned)
if application.ever_banned and application.ever_banned_explanation: if application.ever_banned and application.ever_banned_explanation:
embed.add_field(name="Reason for being banned", value=application.ever_banned_explanation) embed.add_field(name="Reason for being banned", value=application.ever_banned_explanation)
if application.reference: if application.reference:
embed.add_field(name="Reference", value=application.reference) embed.add_field(name="Referral", value=application.reference)
embed.add_field(name="Read the Rules", value=application.read_rules) embed.add_field(name="Read the Rules", value=application.read_rules)
embed.timestamp = application.date embed.timestamp = application.date
embed.add_field(name="Status", value=application.status) embed.add_field(name="Status", value=application.status)
embed.add_field(name="Link", value=full_reverse('application_info', application.id)) embed.add_field(name="Link", value=full_reverse('application_info', application.id), inline=False)
return embed return embed
@ -57,19 +57,7 @@ def build_ticket(ticket, link):
if ticket.x and ticket.y and ticket.z and ticket.world: if ticket.x and ticket.y and ticket.z and ticket.world:
embed.add_field(name="Location", value=ticket.location) embed.add_field(name="Location", value=ticket.location)
embed.add_field(name="Message", value=ticket.message) embed.add_field(name="Message", value=ticket.message)
embed.add_field(name="Link", value=link) embed.add_field(name="Link", value=link, inline=False)
return embed
def build_warning(warning, link):
embed = discord.Embed(colour=discord.Colour(0x417505))
embed.title = "Warning"
embed.set_thumbnail(url=full_static("favicon.png"))
embed.timestamp = warning.date
embed.add_field(name="Player", value=warning.player.username.replace("_", "\\_"))
embed.add_field(name="Importance", value=warning.importance_display)
embed.add_field(name="Message", value=warning.message)
embed.add_field(name="Link", value=link)
return embed return embed
@ -78,16 +66,15 @@ def build_note(note, link):
embed.title = "Note" embed.title = "Note"
embed.set_thumbnail(url=full_static("favicon.png")) embed.set_thumbnail(url=full_static("favicon.png"))
embed.timestamp = note.date embed.timestamp = note.date
embed.add_field(name="Date", value=note.date_display)
embed.add_field(name="Player", value=note.player.username.replace("_", "\\_")) embed.add_field(name="Player", value=note.player.username.replace("_", "\\_"))
embed.add_field(name="Importance", value=note.importance_display) embed.add_field(name="Importance", value=note.importance_display)
embed.add_field(name="Message", value=note.message) embed.add_field(name="Message", value=note.message)
embed.add_field(name="Link", value=link) embed.add_field(name="Link", value=link, inline=False)
return embed return embed
def validate_username(username): def validate_username(username):
response = requests.get("https://api.mojang.com/users/profiles/minecraft/{}".format(username)) response = requests.get(f"https://api.mojang.com/users/profiles/minecraft/{username}")
if response.status_code == 200: if response.status_code == 200:
return True return True
return False return False
@ -137,4 +124,4 @@ class Captcha:
def add_error(self, error): def add_error(self, error):
if error not in self.errors: if error not in self.errors:
self.errors.append(error) self.errors.append(error)