Skip to content

Commit

Permalink
More migration stuff, more endpoints
Browse files Browse the repository at this point in the history
- Add a system user for `last_modified_by` in migrations. This user is hidden by default in `CncUser.objects.all()` queries.
- Clean up migrations a bit
- Make the user management class available in migrations
- Make map category slugs auto-generate
- Pop fields that non-admins shouldn't see over the API
- Start standardizing what our `response.data` is going to look like. I want to avoid the UI needing a `is list or is dict` check for api returns
- Fix the pagination class to use limits and offsets
- Make pagination return standard api format
- Fix and test map category endpoint
- Add standard map categories in a migration. Copied from https://github.com/CnCNet/cncnet-yr-client-package/blob/develop/package/INI/MPMaps.ini
  • Loading branch information
alexlambson committed Feb 14, 2024
1 parent 07d3a47 commit 2207cab
Show file tree
Hide file tree
Showing 18 changed files with 347 additions and 95 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
# CnCNet Map Browser API

---

The backend for the CnCNet map browser.

UI is here https://github.com/CnCNet/cncnet-map-ui


# Kirovy

---

The mascot for the backend API is Kirovy, by [Direct & Dominate](https://www.youtube.com/@DirectandDominate)

![Kirovy enjoying his job](docs/images/kirovy_direct_and_dominate.png)

# Development

---

## Frontend devs

Just set up your environment file and run the full docker compose
Just set up your environment file and run the full docker compose.

[Example env file](example.env)

## Backend devs

Expand Down
Binary file added docs/images/kirovy_direct_and_dominate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/kirovy_square.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions kirovy/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ def is_messiah(cls, user_group: str) -> bool:
return user_group == cls.KANE


class MigrationUser:
ID = -1
USERNAME = "MobileConstructionVehicle_Migrator"
GROUP = CncnetUserGroup.USER


class GameSlugs(enum.StrEnum):
"""The slugs for each game / total conversion mod.
Expand Down
63 changes: 63 additions & 0 deletions kirovy/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,67 @@ class Migration(migrations.Migration):
fields=("cnc_map_id", "version"), name="unique_map_version"
),
),
migrations.AlterModelManagers(
name="cncuser",
managers=[
("objects", kirovy.models.cnc_user.CncUserManager()),
],
),
migrations.AddField(
model_name="cncfileextension",
name="last_modified_by",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="modified_%(class)s_set",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddField(
model_name="cncgame",
name="last_modified_by",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="modified_%(class)s_set",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddField(
model_name="cncmap",
name="is_banned",
field=models.BooleanField(
default=False,
help_text="If true, this map will be hidden everywhere. Likely due to breaking a rule.",
),
),
migrations.AddField(
model_name="cncmap",
name="legacy_upload_date",
field=models.DateTimeField(
default=None,
help_text="The original upload date for entries imported from the legacy map database.",
null=True,
),
),
migrations.AddField(
model_name="cncmapfile",
name="last_modified_by",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="modified_%(class)s_set",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AddField(
model_name="mapcategory",
name="last_modified_by",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="modified_%(class)s_set",
to=settings.AUTH_USER_MODEL,
),
),
]
22 changes: 21 additions & 1 deletion kirovy/migrations/0002_add_games.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.db.migrations.state import StateApps

from kirovy import constants
from kirovy.models import CncGame as _Game, CncFileExtension as _Ext
from kirovy.models import CncGame as _Game, CncFileExtension as _Ext, CncUser as _User


def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
Expand All @@ -16,41 +16,50 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
# migrations are after this one.
CncGame: typing.Type[_Game] = apps.get_model("kirovy", "CncGame")
CncFileExtension: typing.Type[_Ext] = apps.get_model("kirovy", "CncFileExtension")
CncUser: typing.Type[_User] = apps.get_model("kirovy", "CncUser")

migration_user = CncUser.objects.get_or_create_migration_user()

mix = CncFileExtension(
extension="mix",
extension_type=_Ext.ExtensionTypes.ASSETS.value,
about="Mix files are uncompressed group files that store game assets.",
last_modified_by_id=migration_user.id,
)
mix.save()
map_ext = CncFileExtension(
extension="map",
extension_type=_Ext.ExtensionTypes.MAP.value,
about="Map files are ini files that store map data.",
last_modified_by_id=migration_user.id,
)
map_ext.save()
yrm = CncFileExtension(
extension="yrm",
extension_type=_Ext.ExtensionTypes.MAP.value,
about="Yuri's Revenge custom multiplayer map.",
last_modified_by_id=migration_user.id,
)
yrm.save()
mpr = CncFileExtension(
extension="mpr",
extension_type=_Ext.ExtensionTypes.MAP.value,
about="RA2 custom multiplayer map.",
last_modified_by_id=migration_user.id,
)
mpr.save()
mmx = CncFileExtension(
extension="mmx",
extension_type=_Ext.ExtensionTypes.MAP.value,
about="Mix file containing a .MAP file and a .PKT file.",
last_modified_by_id=migration_user.id,
)
mmx.save()
yro = CncFileExtension(
extension="yro",
extension_type=_Ext.ExtensionTypes.MAP.value,
about="Mix file containing a .MAP file and a .PKT file.",
last_modified_by_id=migration_user.id,
)
yro.save()

Expand All @@ -67,6 +76,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=None,
is_mod=False,
last_modified_by_id=migration_user.id,
)
tib_dawn.save()
tib_dawn.allowed_extensions.add(mix, map_ext)
Expand All @@ -78,6 +88,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=None,
is_mod=False,
last_modified_by_id=migration_user.id,
)
red_alert.save()
red_alert.allowed_extensions.add(mix, map_ext)
Expand All @@ -89,6 +100,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=None,
is_mod=False,
last_modified_by_id=migration_user.id,
)
dune_2k.save()
dune_2k.allowed_extensions.add(mix, map_ext)
Expand All @@ -100,6 +112,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=None,
is_mod=False,
last_modified_by_id=migration_user.id,
)
tib_sun.save()
tib_sun.allowed_extensions.add(mix, map_ext)
Expand All @@ -111,6 +124,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=None,
is_mod=False,
last_modified_by_id=migration_user.id,
)
red_alert_2.save()
red_alert_2.allowed_extensions.add(mix, map_ext, mpr, mmx)
Expand All @@ -123,6 +137,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
parent_game=red_alert_2,
is_mod=False,
compatible_with_parent_maps=True,
last_modified_by_id=migration_user.id,
)
yuri.save()
yuri.allowed_extensions.add(*yr_extensions)
Expand All @@ -134,6 +149,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=tib_sun,
is_mod=True,
last_modified_by_id=migration_user.id,
)
dta.save()
dta.allowed_extensions.add(mix, map_ext)
Expand All @@ -145,6 +161,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=yuri,
is_mod=True,
last_modified_by_id=migration_user.id,
)
mental_omega.save()
mental_omega.allowed_extensions.add(*yr_extensions)
Expand All @@ -156,6 +173,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=yuri,
is_mod=True,
last_modified_by_id=migration_user.id,
)
red_resurrection.save()
red_resurrection.allowed_extensions.add(*yr_extensions)
Expand All @@ -167,6 +185,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=yuri,
is_mod=True,
last_modified_by_id=migration_user.id,
)
cnc_reloaded.save()
cnc_reloaded.allowed_extensions.add(*yr_extensions)
Expand All @@ -178,6 +197,7 @@ def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
allow_public_uploads=False,
parent_game=yuri,
is_mod=True,
last_modified_by_id=migration_user.id,
)
rise_of_the_east.save()
rise_of_the_east.allowed_extensions.add(*yr_extensions)
Expand Down

This file was deleted.

66 changes: 66 additions & 0 deletions kirovy/migrations/0003_map_categories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Generated by Django 4.2.5 on 2024-02-14 04:50

from django.db import migrations
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps
from django.utils.text import slugify

from kirovy import typing as t
from kirovy.models import MapCategory as _MapCategory, CncUser as _User


def _forward(apps: StateApps, schema_editor: DatabaseSchemaEditor):

# This is necessary in case later migrations make schema changes to this model.
# Importing them normally will use the latest schema state and will crash if those
# migrations are after this one.
MapCategory: t.Type[_MapCategory] = apps.get_model("kirovy", "MapCategory")
CncUser: t.Type[_User] = apps.get_model("kirovy", "CncUser")

migration_user = CncUser.objects.get_or_create_migration_user()

yuri_category_names = {
"Battle",
"YR Ladder",
"RA2 Ladder",
"RA2 Pro 2v2",
"Free For All",
"Cooperative",
"Naval War",
"Unholy Alliance",
"Megawealth",
"Meat Grinder",
"Team Alliance",
"Land Rush",
"Mod Maps",
"Standard",
"SFJ",
"Blitz",
"Survival",
}

for category_name in yuri_category_names:
# Note: Custom overriden .save() doesn't work in migrations, so
# we have to manually make the slug.
category = MapCategory(
name=category_name,
slug=slugify(category_name),
last_modified_by=migration_user,
)
category.save()


def _backward(apps: StateApps, schema_editor: DatabaseSchemaEditor):
pass


class Migration(migrations.Migration):

dependencies = [
("kirovy", "0002_add_games"),
]

# Elidable=false means that squashmigrations will not delete this.
operations = [
migrations.RunPython(_forward, reverse_code=_backward, elidable=False),
]
Loading

0 comments on commit 2207cab

Please sign in to comment.