Initial MVP: local visual novel library with Ren'Py → PGVN converter
- 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>
This commit is contained in:
commit
364b312064
72 files changed
+9707
No files matched your search
@@ -0,0 +1,43 @@
|
||||
import logging
|
||||
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import get_settings
|
||||
from app.models import Role, User
|
||||
from app.permissions import SYSTEM_ROLES
|
||||
from app.security import hash_password
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def bootstrap(db: AsyncSession) -> None:
|
||||
"""Create system roles and the initial admin on a fresh database."""
|
||||
roles = {r.name: r for r in (await db.scalars(select(Role))).all()}
|
||||
for name, perms in SYSTEM_ROLES.items():
|
||||
role = roles.get(name)
|
||||
if role is None:
|
||||
db.add(Role(name=name, permissions=perms, is_system=True))
|
||||
elif name == "admin":
|
||||
# admin always has every permission, including newly added ones
|
||||
role.permissions = perms
|
||||
await db.flush()
|
||||
|
||||
if await db.scalar(select(func.count()).select_from(User)):
|
||||
await db.commit()
|
||||
return
|
||||
|
||||
settings = get_settings()
|
||||
admin_role = await db.scalar(select(Role).where(Role.name == "admin"))
|
||||
db.add(
|
||||
User(
|
||||
username=settings.admin_username,
|
||||
password_hash=hash_password(settings.admin_password),
|
||||
role_id=admin_role.id,
|
||||
must_change_password=True,
|
||||
must_change_username=True,
|
||||
)
|
||||
)
|
||||
await db.commit()
|
||||
log.warning("Created initial admin '%s'; credentials must be changed on first login",
|
||||
settings.admin_username)
|
||||
Reference in new issue
Block a user