89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
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
|