- FastAPI backend: admin bootstrap with forced credential change, admin-created users with one-time generated passwords, roles as permission sets - Games and versions with content-addressed blob storage; forks copy only the manifest, so mods share assets with the original - Worker: archive/RPA extraction, unrpyc for .rpyc, own .rpy parser, Python subset translated via ast, media converted to WebP/Opus/WebM - React panel (library search, game page, upload, users, roles) and a framework-free web player with saves, history, skip/auto, transitions - docker compose: postgres, backend, worker, nginx on a single HTTP port Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
129 lines
2.2 KiB
Python
129 lines
2.2 KiB
Python
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class ORM(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class LoginIn(BaseModel):
|
|
username: str
|
|
password: str
|
|
|
|
|
|
class ChangeCredentialsIn(BaseModel):
|
|
current_password: str
|
|
new_password: str
|
|
new_username: str | None = None
|
|
|
|
|
|
class RoleOut(ORM):
|
|
id: int
|
|
name: str
|
|
permissions: list[str]
|
|
is_system: bool
|
|
|
|
|
|
class RoleIn(BaseModel):
|
|
name: str = Field(min_length=1, max_length=64)
|
|
permissions: list[str]
|
|
|
|
|
|
class UserOut(ORM):
|
|
id: int
|
|
username: str
|
|
role: RoleOut
|
|
is_active: bool
|
|
must_change_password: bool
|
|
must_change_username: bool
|
|
created_at: datetime
|
|
|
|
|
|
class MeOut(UserOut):
|
|
permissions: list[str]
|
|
|
|
|
|
class UserCreateIn(BaseModel):
|
|
username: str
|
|
role_id: int
|
|
|
|
|
|
class UserUpdateIn(BaseModel):
|
|
role_id: int | None = None
|
|
is_active: bool | None = None
|
|
|
|
|
|
class UserWithPasswordOut(BaseModel):
|
|
user: UserOut
|
|
password: str
|
|
|
|
|
|
class OwnerOut(ORM):
|
|
id: int
|
|
username: str
|
|
|
|
|
|
class VersionOut(ORM):
|
|
id: int
|
|
game_id: int
|
|
parent_id: int | None
|
|
owner: OwnerOut | None
|
|
name: str
|
|
description: str
|
|
status: str
|
|
progress: str
|
|
size_bytes: int
|
|
created_at: datetime
|
|
|
|
|
|
class VersionDetailOut(VersionOut):
|
|
report: dict[str, Any] | None
|
|
|
|
|
|
class GameOut(ORM):
|
|
id: int
|
|
title: str
|
|
description: str
|
|
tags: list[str]
|
|
engine: str
|
|
cover_hash: str | None
|
|
created_at: datetime
|
|
|
|
|
|
class GameDetailOut(GameOut):
|
|
versions: list[VersionOut]
|
|
|
|
|
|
class GameIn(BaseModel):
|
|
title: str = Field(min_length=1, max_length=255)
|
|
description: str = ""
|
|
tags: list[str] = []
|
|
|
|
|
|
class GameUpdateIn(BaseModel):
|
|
title: str | None = Field(default=None, min_length=1, max_length=255)
|
|
description: str | None = None
|
|
tags: list[str] | None = None
|
|
|
|
|
|
class VersionIn(BaseModel):
|
|
name: str = Field(min_length=1, max_length=255)
|
|
description: str = ""
|
|
|
|
|
|
class SaveIn(BaseModel):
|
|
title: str = ""
|
|
data: dict[str, Any]
|
|
|
|
|
|
class SaveOut(ORM):
|
|
slot: str
|
|
title: str
|
|
updated_at: datetime
|
|
|
|
|
|
class SaveDetailOut(SaveOut):
|
|
data: dict[str, Any]
|