Add Google OAuth configuration and enhance API functionality

- Updated .env.example with WEB_GOOGLE_CLIENT_ID and WEB_GOOGLE_CLIENT_SECRET for Google OAuth.
- Modified README.md to reflect changes in docker-compose for unified web and API deployment.
- Enhanced auth.py to support NextAuth JWT session cookies.
- Improved main.py with lifespan management and additional API endpoints.
- Added mod_overview endpoint in mod.py for MOD panel statistics.
- Updated docker-compose.yml for local API and web service configurations.
This commit is contained in:
2026-03-30 13:55:12 +07:00
parent 5da7cc4530
commit ac5f5db447
6 changed files with 590 additions and 26 deletions
+62 -1
View File
@@ -150,7 +150,10 @@ async def dev_make_mod(
@router.get("/mod/the-loai")
async def mod_list_genres(db: AsyncSession = Depends(get_db_session)):
async def mod_list_genres(
db: AsyncSession = Depends(get_db_session),
user: dict = Depends(require_mod_user),
):
result = await db.execute(text('SELECT id, name, slug, description, icon FROM "Genre" ORDER BY name ASC'))
return [dict(r) for r in result.mappings()]
@@ -376,6 +379,64 @@ async def _resolve_series_id(
# ---------------------------------------------------------------------------
@router.get("/mod/overview")
async def mod_overview(
db: AsyncSession = Depends(get_db_session),
user: dict = Depends(require_mod_user),
):
if _is_admin(user):
novel_count = (await db.execute(text('SELECT COUNT(*)::int FROM "Novel"'))).scalar() or 0
total_views = (await db.execute(text('SELECT COALESCE(SUM(views), 0)::bigint FROM "Novel"'))).scalar() or 0
comment_count = (await db.execute(text('SELECT COUNT(*)::int FROM "Comment"'))).scalar() or 0
series_count = (await db.execute(text('SELECT COUNT(*)::int FROM "Series"'))).scalar() or 0
else:
novel_count = (
await db.execute(
text('SELECT COUNT(*)::int FROM "Novel" WHERE "uploaderId" = :uid OR "uploaderId" IS NULL'),
{"uid": user["id"]},
)
).scalar() or 0
total_views = (
await db.execute(
text('SELECT COALESCE(SUM(views), 0)::bigint FROM "Novel" WHERE "uploaderId" = :uid OR "uploaderId" IS NULL'),
{"uid": user["id"]},
)
).scalar() or 0
comment_count = (
await db.execute(
text(
'SELECT COUNT(c.id)::int '
'FROM "Comment" c '
'JOIN "Novel" n ON n.id = c."novelId" '
'WHERE n."uploaderId" = :uid OR n."uploaderId" IS NULL'
),
{"uid": user["id"]},
)
).scalar() or 0
series_count = (
await db.execute(
text(
'SELECT COUNT(s.id)::int '
'FROM "Series" s '
'WHERE EXISTS ('
' SELECT 1 FROM "Novel" n '
' WHERE n."seriesId" = s.id AND (n."uploaderId" = :uid OR n."uploaderId" IS NULL)'
') OR NOT EXISTS ('
' SELECT 1 FROM "Novel" n2 WHERE n2."seriesId" = s.id'
')'
),
{"uid": user["id"]},
)
).scalar() or 0
return {
"novelCount": int(novel_count),
"totalViews": int(total_views),
"commentCount": int(comment_count),
"seriesCount": int(series_count),
}
@router.get("/mod/truyen")
async def mod_list_novels(
db: AsyncSession = Depends(get_db_session),