Skip to content

Commit 3509ace

Browse files
committed
feat: wip definition of models for new server management
1 parent fdd9c8f commit 3509ace

File tree

12 files changed

+266
-0
lines changed

12 files changed

+266
-0
lines changed

src/server/__init__.py

Whitespace-only changes.

src/server/admin.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from django.contrib import admin
2+
3+
from .models import (
4+
AccountModerationInfo,
5+
CodeScanInformation,
6+
ServerAdmonition,
7+
ServerInformation,
8+
)
9+
10+
11+
class ServerAdmonitionInline(admin.TabularInline):
12+
model = ServerAdmonition
13+
extra = 1
14+
raw_id_fields = ["server"]
15+
fields = ["server", "created_at", "reason", "severity"]
16+
readonly_fields = ["created_at"]
17+
18+
19+
@admin.register(CodeScanInformation)
20+
class CodeScanInformationAdmin(admin.ModelAdmin):
21+
list_display = ["version"]
22+
23+
24+
@admin.register(ServerInformation)
25+
class ServerInformationAdmin(admin.ModelAdmin):
26+
list_display = ["name", "owner", "is_18_plus", "is_delisted"]
27+
search_fields = ["name", "owner__username"]
28+
list_filter = ["is_18_plus", "is_delisted"]
29+
raw_id_fields = ["owner", "code_scan_version"]
30+
31+
32+
@admin.register(AccountModerationInfo)
33+
class AccountModerationInfoAdmin(admin.ModelAdmin):
34+
list_display = ["account", "can_create_servers", "can_list_servers"]
35+
search_fields = ["account__username"]
36+
list_filter = ["can_create_servers", "can_list_servers"]
37+
raw_id_fields = ["account"]

src/server/api/__init__.py

Whitespace-only changes.

src/server/api/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app_name = "server"

src/server/api/views.py

Whitespace-only changes.

src/server/apps.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class ServerConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "server"

src/server/management/__init__.py

Whitespace-only changes.

src/server/management/commands/__init__.py

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from django.core.management.base import BaseCommand
2+
3+
from accounts.models import Account
4+
from server.models import AccountModerationInfo
5+
6+
7+
class Command(BaseCommand):
8+
help = "creates AccountModerationInfo for existing accounts"
9+
10+
def handle(self, *args, **options):
11+
for account in Account.objects.all():
12+
AccountModerationInfo.objects.get_or_create(account=account)
13+
self.stdout.write(self.style.SUCCESS("Successfully created AccountModerationInfo for all accounts"))

src/server/migrations/0001_initial.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Generated by Django 3.2.24 on 2024-06-19 10:17
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
initial = True
11+
12+
dependencies = [
13+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='AccountModerationInfo',
19+
fields=[
20+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('can_create_servers', models.BooleanField(default=True)),
22+
('can_list_servers', models.BooleanField(default=True)),
23+
('account', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='moderation_info', to=settings.AUTH_USER_MODEL)),
24+
],
25+
),
26+
migrations.CreateModel(
27+
name='CodeScanInformation',
28+
fields=[
29+
('version', models.TextField(primary_key=True, serialize=False)),
30+
],
31+
),
32+
migrations.CreateModel(
33+
name='ServerInformation',
34+
fields=[
35+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
36+
('name', models.TextField(help_text='Name this server uses to present itself in the servers list', max_length=50, verbose_name='Name')),
37+
('description', models.TextField(help_text='A brief description of what this server is about', max_length=200, verbose_name='Description')),
38+
('icon', models.URLField(blank=True, help_text='URL of the image this server uses to present itself in the servers list', verbose_name='Icon')),
39+
('rules', models.TextField(blank=True, help_text='The rules that players must follow on this server', verbose_name='Rules')),
40+
('motd', models.TextField(help_text='Message displayed to players when they join the server', verbose_name='Message of the Day (MOTD)')),
41+
('is_18_plus', models.BooleanField(default=False, help_text='Indicates if this server is intended for players aged 18 and above', verbose_name='18+')),
42+
('is_delisted', models.BooleanField(help_text='Indicates if this server is delisted from the servers list', verbose_name='Is Delisted')),
43+
('listing_key', models.TextField(blank=True, help_text='A unique key used for listing this server. Do not lose this key!', null=True, unique=True, verbose_name='Listing Key')),
44+
('code_scan_version', models.ForeignKey(help_text='What version should this build of the game be tested against in CodeScan', on_delete=django.db.models.deletion.PROTECT, to='server.codescaninformation', verbose_name='CodeScan Version')),
45+
('owner', models.ForeignKey(help_text='Who created and/or is responsible for this server', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Owner')),
46+
],
47+
),
48+
migrations.CreateModel(
49+
name='ServerAdmonition',
50+
fields=[
51+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
52+
('created_at', models.DateTimeField(auto_now_add=True, help_text='When was this admonition created', verbose_name='Created at')),
53+
('reason', models.TextField(help_text='Why was this server warned?', verbose_name='Reason')),
54+
('severity', models.CharField(choices=[('low', 'Low'), ('medium', 'Medium'), ('high', 'High')], default='low', help_text='The severity level of the admonition', max_length=6)),
55+
('owner_moderation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='admonitions', to='server.accountmoderationinfo')),
56+
('server', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='admonitions', to='server.serverinformation')),
57+
],
58+
),
59+
]

src/server/migrations/__init__.py

Whitespace-only changes.

src/server/models.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import secrets
2+
import string
3+
4+
from django.db import models
5+
from django.db.models.signals import pre_save
6+
from django.dispatch import receiver
7+
8+
from accounts.models import Account
9+
10+
11+
class CodeScanInformation(models.Model):
12+
version = models.TextField(primary_key=True)
13+
14+
def __str__(self):
15+
return self.version
16+
17+
18+
def generate_listing_key():
19+
alphabet = string.ascii_letters + string.digits + "-_"
20+
return "".join(secrets.choice(alphabet) for _ in range(30))
21+
22+
23+
class ServerInformation(models.Model):
24+
owner = models.ForeignKey(
25+
verbose_name="Owner",
26+
to=Account,
27+
on_delete=models.CASCADE,
28+
help_text="Who created and/or is responsible for this server",
29+
)
30+
name = models.TextField(
31+
verbose_name="Name",
32+
max_length=50,
33+
help_text="Name this server uses to present itself in the servers list",
34+
)
35+
description = models.TextField(
36+
verbose_name="Description",
37+
max_length=200,
38+
help_text="A brief description of what this server is about",
39+
)
40+
icon = models.URLField(
41+
verbose_name="Icon",
42+
blank=True,
43+
help_text="URL of the image this server uses to present itself in the servers list",
44+
)
45+
rules = models.TextField(
46+
verbose_name="Rules",
47+
blank=True,
48+
help_text="The rules that players must follow on this server",
49+
)
50+
motd = models.TextField(
51+
verbose_name="Message of the Day (MOTD)",
52+
help_text="Message displayed to players when they join the server",
53+
)
54+
is_18_plus = models.BooleanField(
55+
verbose_name="18+",
56+
default=False,
57+
help_text="Indicates if this server is intended for players aged 18 and above",
58+
)
59+
code_scan_version = models.ForeignKey(
60+
verbose_name="CodeScan Version",
61+
to=CodeScanInformation,
62+
on_delete=models.PROTECT,
63+
help_text="What version should this build of the game be tested against in CodeScan",
64+
)
65+
is_delisted = models.BooleanField(
66+
verbose_name="Is Delisted",
67+
help_text="Indicates if this server is delisted from the servers list",
68+
)
69+
listing_key = models.TextField(
70+
unique=True,
71+
verbose_name="Listing Key",
72+
null=True,
73+
blank=True,
74+
help_text="A unique key used for listing this server. Do not lose this key!",
75+
)
76+
77+
def __str__(self):
78+
return f"Server: {self.name} by: {self.owner.unique_identifier}"
79+
80+
81+
@receiver(pre_save, sender=ServerInformation)
82+
def set_listing_key(sender, instance: ServerInformation, **kwargs):
83+
if not instance.listing_key:
84+
unique_key_found = False
85+
while not unique_key_found:
86+
new_key = generate_listing_key()
87+
if not ServerInformation.objects.filter(listing_key=new_key).exists():
88+
instance.listing_key = new_key
89+
unique_key_found = True
90+
91+
92+
# class ServerStatus(models.Model):
93+
# server = models.ForeignKey(
94+
# ServerInformation, related_name="status", on_delete=models.CASCADE
95+
# )
96+
# is_passworded = models.BooleanField()
97+
# fork_name = models.TextField()
98+
# build_version = models.TextField()
99+
# current_map = models.TextField()
100+
# game_mode = models.TextField()
101+
# ingame_time = models.TextField()
102+
# round_time = models.TextField()
103+
# player_count = models.PositiveSmallIntegerField()
104+
# player_count_max = models.PositiveSmallIntegerField()
105+
# ip = models.TextField()
106+
# port = models.PositiveSmallIntegerField()
107+
# windows_download = models.URLField()
108+
# osx_download = models.URLField()
109+
# linux_download = models.URLField()
110+
# fps = models.PositiveSmallIntegerField()
111+
112+
113+
class AccountModerationInfo(models.Model):
114+
account = models.OneToOneField(to=Account, related_name="moderation_info", on_delete=models.CASCADE)
115+
can_create_servers = models.BooleanField(default=True)
116+
can_list_servers = models.BooleanField(default=True)
117+
118+
def __str__(self):
119+
return f"Moderation for {self.account.unique_identifier}"
120+
121+
122+
class ServerAdmonition(models.Model):
123+
SEVERITY_LEVELS = [
124+
("low", "Low"),
125+
("medium", "Medium"),
126+
("high", "High"),
127+
]
128+
129+
owner_moderation = models.ForeignKey(AccountModerationInfo, related_name="admonitions", on_delete=models.CASCADE)
130+
server = models.ForeignKey(
131+
ServerInformation,
132+
related_name="admonitions",
133+
on_delete=models.SET_NULL,
134+
null=True,
135+
)
136+
created_at = models.DateTimeField(
137+
verbose_name="Created at",
138+
auto_now_add=True,
139+
help_text="When was this admonition created",
140+
)
141+
reason = models.TextField(verbose_name="Reason", help_text="Why was this server warned?")
142+
severity = models.CharField(
143+
max_length=6,
144+
choices=SEVERITY_LEVELS,
145+
default="low",
146+
help_text="The severity level of the admonition",
147+
)
148+
149+
def __str__(self):
150+
return f"[{self.get_severity_display()}]: {self.reason}"

0 commit comments

Comments
 (0)