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