Skip to content

Commit 050e0ce

Browse files
committed
- fix docker for real
- make moderabile object - Fix circular imports with file extensions - Fix broken 0002 migration due to the object manager not using the correct schema state
1 parent 2102b74 commit 050e0ce

15 files changed

+327
-96
lines changed

docker-compose.debugger.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ services:
55
container_name: mapdb-postgres-debugger
66
image: postgres:18
77
volumes:
8-
- ${POSTGRES_DATA_DIR}/debugger-db/:/var/lib/postgresql/18/data
8+
- ${POSTGRES_DATA_DIR}/debugger-db/:/var/lib/postgresql/18/docker
99
environment:
1010
- POSTGRES_DB=${POSTGRES_DB}
1111
- POSTGRES_USER=${POSTGRES_USER}

docker-compose.prod.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ services:
33
container_name: mapdb-postgres
44
image: postgres:18
55
volumes:
6-
- ${POSTGRES_DATA_DIR}:/var/lib/postgresql/18/data
6+
- ${POSTGRES_DATA_DIR}:/var/lib/postgresql/18/docker
77
environment:
88
- POSTGRES_DB=${POSTGRES_DB}
99
- POSTGRES_USER=${POSTGRES_USER}

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ services:
33
container_name: mapdb-postgres-dev
44
image: postgres:18
55
volumes:
6-
- ${POSTGRES_DATA_DIR}:/var/lib/postgresql/18/data
6+
- ${POSTGRES_DATA_DIR}:/var/lib/postgresql/18/docker
77
environment:
88
- POSTGRES_DB=${POSTGRES_DB}
99
- POSTGRES_USER=${POSTGRES_USER}

kirovy/migrations/0002_add_games.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
1818
CncFileExtension: typing.Type[_Ext] = apps.get_model("kirovy", "CncFileExtension")
1919
CncUser: typing.Type[_User] = apps.get_model("kirovy", "CncUser")
2020

21-
migration_user = CncUser.objects.get_or_create_migration_user()
21+
# We have to create the migration user manually because the helper method on
22+
# ``objects`` will crash due to not using the correct schema.
23+
migration_user = CncUser(
24+
cncnet_id=constants.MigrationUser.CNCNET_ID,
25+
username=constants.MigrationUser.USERNAME,
26+
group=constants.MigrationUser.GROUP,
27+
)
28+
migration_user.save()
29+
migration_user.refresh_from_db()
2230

2331
mix = CncFileExtension(
2432
extension="mix",
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Generated by Django 4.2.23 on 2025-10-04 06:43
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+
dependencies = [
11+
("kirovy", "0017_cncmapimagefile_kirovy_cncm_is_extr_0259c5_idx_and_more"),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name="cncmap",
17+
name="ban_count",
18+
field=models.IntegerField(default=0, help_text="How many times this user has been banned."),
19+
),
20+
migrations.AddField(
21+
model_name="cncmap",
22+
name="ban_date",
23+
field=models.DateTimeField(default=None, help_text="If banned, when the object was banned.", null=True),
24+
),
25+
migrations.AddField(
26+
model_name="cncmap",
27+
name="ban_expires",
28+
field=models.DateField(default=None, help_text="If banned, when the ban expires, if temporary.", null=True),
29+
),
30+
migrations.AddField(
31+
model_name="cncmap",
32+
name="ban_reason",
33+
field=models.CharField(default=None, help_text="If banned, the reason the object was banned.", null=True),
34+
),
35+
migrations.AddField(
36+
model_name="cncmap",
37+
name="moderated_by",
38+
field=models.ForeignKey(
39+
help_text="The most recent moderator who most recently modified this object",
40+
null=True,
41+
on_delete=django.db.models.deletion.SET_NULL,
42+
related_name="moderated_%(class)ss_set",
43+
to=settings.AUTH_USER_MODEL,
44+
),
45+
),
46+
migrations.AddField(
47+
model_name="cncmap",
48+
name="moderator_notes",
49+
field=models.TextField(help_text="Notes on moderator actions.", null=True),
50+
),
51+
migrations.AddField(
52+
model_name="cncuser",
53+
name="moderated_by",
54+
field=models.ForeignKey(
55+
help_text="The most recent moderator who most recently modified this object",
56+
null=True,
57+
on_delete=django.db.models.deletion.SET_NULL,
58+
related_name="moderated_%(class)ss_set",
59+
to=settings.AUTH_USER_MODEL,
60+
),
61+
),
62+
migrations.AddField(
63+
model_name="cncuser",
64+
name="moderator_notes",
65+
field=models.TextField(help_text="Notes on moderator actions.", null=True),
66+
),
67+
migrations.AlterField(
68+
model_name="cncmap",
69+
name="is_banned",
70+
field=models.BooleanField(default=False, help_text="If true, object was banned for some reason."),
71+
),
72+
migrations.AlterField(
73+
model_name="cncuser",
74+
name="ban_date",
75+
field=models.DateTimeField(default=None, help_text="If banned, when the object was banned.", null=True),
76+
),
77+
migrations.AlterField(
78+
model_name="cncuser",
79+
name="ban_expires",
80+
field=models.DateField(default=None, help_text="If banned, when the ban expires, if temporary.", null=True),
81+
),
82+
migrations.AlterField(
83+
model_name="cncuser",
84+
name="ban_reason",
85+
field=models.CharField(default=None, help_text="If banned, the reason the object was banned.", null=True),
86+
),
87+
migrations.AlterField(
88+
model_name="cncuser",
89+
name="is_banned",
90+
field=models.BooleanField(default=False, help_text="If true, object was banned for some reason."),
91+
),
92+
]

kirovy/models/cnc_game.py

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import pathlib
21
from functools import cached_property
32

43
from django.conf import settings
5-
from django.core.files.uploadedfile import UploadedFile
64
from django.db import models
7-
from structlog.stdlib import BoundLogger
85

96
from kirovy import exceptions, typing as t
107

@@ -78,40 +75,6 @@ def extension_for_path(self) -> str:
7875
"""
7976
return f".{self.extension}"
8077

81-
@classmethod
82-
def get_extension_id_for_upload(
83-
cls,
84-
uploaded_file: UploadedFile,
85-
allowed_types: t.Set[str],
86-
*,
87-
logger: BoundLogger,
88-
error_detail_upload_type: str,
89-
extra_log_attrs: t.Dict[str, t.Any] | None = None,
90-
) -> str:
91-
# TODO: Get rid of relative import after model import is removed from ui_objects.py
92-
from kirovy.constants.api_codes import UploadApiCodes
93-
from kirovy.exceptions.view_exceptions import KirovyValidationError
94-
95-
uploaded_extension = pathlib.Path(uploaded_file.name).suffix.lstrip(".").lower()
96-
# iexact is case insensitive
97-
kirovy_extension = cls.objects.filter(
98-
extension__iexact=uploaded_extension,
99-
extension_type__in=allowed_types,
100-
).first()
101-
102-
if kirovy_extension:
103-
return str(kirovy_extension.id)
104-
105-
logger.warning(
106-
"User attempted uploading unknown filetype",
107-
uploaded_extension=uploaded_extension,
108-
**(extra_log_attrs or {}), # todo: the userattrs should be a context tag for structlog.
109-
)
110-
raise KirovyValidationError(
111-
detail=f"'{uploaded_extension}' is not a valid {error_detail_upload_type.strip()} file extension.",
112-
code=UploadApiCodes.FILE_EXTENSION_NOT_SUPPORTED,
113-
)
114-
11578

11679
class CncGame(CncNetBaseModel):
11780
"""Represents C&C games and large total-conversion mods like Mental Omega."""

kirovy/models/cnc_map.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from kirovy.models.cnc_base_model import CncNetBaseModel
1111
from kirovy import typing as t, exceptions
1212
from kirovy.models.cnc_game import GameScopedUserOwnedModel
13+
from kirovy.models.moderabile import Moderabile
1314

1415

1516
class MapCategory(CncNetBaseModel):
@@ -47,7 +48,7 @@ def save(
4748
super().save(force_insert, force_update, using, update_fields)
4849

4950

50-
class CncMap(GameScopedUserOwnedModel):
51+
class CncMap(GameScopedUserOwnedModel, Moderabile):
5152
"""The Logical representation of a map for a Command & Conquer game.
5253
5354
We have this as a separate model from the file model because later C&C's allow for various files
@@ -98,12 +99,6 @@ class CncMap(GameScopedUserOwnedModel):
9899

99100
is_reviewed = models.BooleanField(default=False, help_text="If true, this map was reviewed by a staff member.")
100101

101-
is_banned = models.BooleanField(
102-
default=False,
103-
help_text="If true, this map will be hidden everywhere. Likely due to breaking a rule.",
104-
)
105-
""":attr: Keep banned maps around so we can keep track of rule-breakers."""
106-
107102
incomplete_upload = models.BooleanField(
108103
default=False,
109104
help_text="If true, then the map file has been uploaded, but the map info has not been set yet.",
@@ -158,11 +153,9 @@ def get_map_directory_path(self, upload_type: str = settings.CNC_MAP_DIRECTORY)
158153
self.id.hex,
159154
)
160155

161-
def set_ban(self, is_banned: bool, banned_by: cnc_user.CncUser) -> None:
156+
def check_is_bannable(self) -> None:
162157
if self.is_legacy:
163158
raise exceptions.BanException("legacy-maps-cannot-be-banned")
164-
self.is_banned = is_banned
165-
self.save(update_fields=["is_banned"])
166159

167160

168161
class CncMapFileManager(models.Manager["CncMapFile"]):

kirovy/models/cnc_user.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.utils.translation import gettext as _
66
from kirovy import typing as t, constants
77
from kirovy.models.cnc_base_model import CncNetBaseModel
8+
from kirovy.models.moderabile import Moderabile
89

910
from kirovy.objects import CncnetUserInfo
1011

@@ -81,7 +82,7 @@ def all_including_legacy_uploader(self):
8182
return super().get_queryset().exclude(cncnet_id=constants.MigrationUser.CNCNET_ID)
8283

8384

84-
class CncUser(AbstractBaseUser):
85+
class CncUser(AbstractBaseUser, Moderabile):
8586
CncnetUserGroup = constants.CncnetUserGroup
8687
""":attr: The user group constants for convenience so you don't need ``import kirovy.constants`` everywhere."""
8788

@@ -108,16 +109,6 @@ class CncUser(AbstractBaseUser):
108109
blank=False,
109110
)
110111

111-
is_banned = models.BooleanField(default=False, help_text="If true, user was banned for some reason.")
112-
ban_reason = models.CharField(default=None, null=True, help_text="If banned, the reason the user was banned.")
113-
ban_date = models.DateTimeField(default=None, null=True, help_text="If banned, when the user was banned.")
114-
ban_expires = models.DateTimeField(
115-
default=None,
116-
null=True,
117-
help_text="If banned, when the ban expires, if temporary.",
118-
)
119-
ban_count = models.IntegerField(default=0, help_text="How many times this user has been banned.")
120-
121112
USERNAME_FIELD = "cncnet_id"
122113
""":attr:
123114
This attribute controls which field Django REST Framework uses as the username field. Values must be unique.
@@ -181,11 +172,6 @@ def create_or_update_from_cncnet(user_dto: CncnetUserInfo) -> "CncUser":
181172

182173
return kirovy_user
183174

184-
def set_ban(self, is_banned: bool, banned_by: "CncUser") -> None:
185-
# TODO: bannable objects should probably be an abstract class
186-
self.is_banned = is_banned
187-
self.save(update_fields=["is_banned"])
188-
189175

190176
class CncNetUserOwnedModel(CncNetBaseModel):
191177
"""A mixin model for any models that will be owned by a user."""

0 commit comments

Comments
 (0)