wip: planning-slot test
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import re
|
||||
import unicodedata
|
||||
|
||||
from ..models import Game, PlanningSlot
|
||||
|
||||
|
||||
def normalize_name(name: str) -> str:
|
||||
"""'Towerfall: Ascension' and 'TowerFall Ascension' are the same game:
|
||||
no accents, no case, letters and digits only."""
|
||||
name = unicodedata.normalize("NFKD", name)
|
||||
name = "".join(c for c in name if not unicodedata.combining(c))
|
||||
return re.sub(r"[^0-9a-z]", "", name.casefold())
|
||||
|
||||
|
||||
def _game_out(name: str, game: Game | None) -> dict:
|
||||
if game is None:
|
||||
return {"name": name}
|
||||
return {
|
||||
"name": game.name,
|
||||
"library_image": game.library_image_url,
|
||||
"store_url": game.store_url,
|
||||
"steam_app_id": game.steam_app_id,
|
||||
}
|
||||
|
||||
|
||||
def planning_with_games(slots) -> list[dict]:
|
||||
"""Slots as PlanningSlotOut dicts, with their games matched by name to ours."""
|
||||
games_by_name = {normalize_name(game.name): game for game in Game.objects.all()}
|
||||
|
||||
def match(name: str) -> Game | None:
|
||||
return games_by_name.get(normalize_name(name))
|
||||
|
||||
out = []
|
||||
for slot in slots:
|
||||
if slot.is_multi_anims:
|
||||
games = [_game_out(name, match(name)) for name in slot.game_names]
|
||||
else:
|
||||
# The title is the usual match, the legacy game names are a fallback
|
||||
# ("Golf it!" slot running the "Golf It!" game)
|
||||
game = next(
|
||||
filter(None, map(match, [slot.title, *slot.game_names])), None
|
||||
)
|
||||
games = [_game_out(slot.title, game)]
|
||||
|
||||
out.append(
|
||||
{
|
||||
"id": slot.id,
|
||||
"title": slot.title,
|
||||
"begin": slot.begin,
|
||||
"end": slot.end,
|
||||
"column": slot.column,
|
||||
"color": slot.color,
|
||||
"is_multi_anims": slot.is_multi_anims,
|
||||
"games": games,
|
||||
}
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def import_planning(event, entries: list[dict]) -> tuple[int, int, int]:
|
||||
"""Sync the event planning with the legacy planning entries (its "list").
|
||||
Returns (created, updated, deleted)."""
|
||||
created = updated = 0
|
||||
for entry in entries:
|
||||
_, was_created = PlanningSlot.objects.update_or_create(
|
||||
event=event,
|
||||
source_pk=entry["pk"],
|
||||
defaults={
|
||||
"title": entry["title"],
|
||||
"begin": entry["begin"],
|
||||
"end": entry["end"],
|
||||
"column": entry.get("colonneS") or 0,
|
||||
"color": entry.get("color_code") or "",
|
||||
"is_multi_anims": bool(entry.get("is_multi_anims")),
|
||||
"game_names": [a["name"] for a in entry.get("aandts") or []],
|
||||
},
|
||||
)
|
||||
if was_created:
|
||||
created += 1
|
||||
else:
|
||||
updated += 1
|
||||
|
||||
deleted, _ = (
|
||||
PlanningSlot.objects.filter(event=event)
|
||||
.exclude(source_pk__in=[entry["pk"] for entry in entries])
|
||||
.delete()
|
||||
)
|
||||
return created, updated, deleted
|
||||
Reference in New Issue
Block a user