|
# retoor <retoor@molodetz.nl>
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from pydantic import BaseModel, Field
|
|
|
|
from devplacepy.database import bump_cache_version, get_int_setting, get_setting
|
|
from devplacepy_services.base.auth import internal_user
|
|
from devplacepy_services.base.compound import (
|
|
AttachmentsIn,
|
|
AwardsBundleIn,
|
|
BookmarksIn,
|
|
CacheBumpIn,
|
|
CommentCountsIn,
|
|
CommentsIn,
|
|
FeedPageIn,
|
|
FollowBundleIn,
|
|
GameStateIn,
|
|
GistDetailIn,
|
|
InvokeIn,
|
|
LeaderboardBundleIn,
|
|
LeaderboardPageIn,
|
|
MessagesPageIn,
|
|
NotificationPrefsIn,
|
|
NotificationsPageIn,
|
|
OnlineUsersIn,
|
|
PollsIn,
|
|
PostDetailIn,
|
|
ProfileBundleIn,
|
|
ProjectDetailIn,
|
|
ReactionsIn,
|
|
RecentCommentsIn,
|
|
RelationsIn,
|
|
SeoMetaIn,
|
|
SiteSidebarIn,
|
|
UserMediaIn,
|
|
UsersByUidsIn,
|
|
VoteCountsIn,
|
|
)
|
|
from devplacepy_services.base.db_codec import is_write_sql
|
|
from devplacepy_services.base.schemas import InternalUser
|
|
from devplacepy_services.database import compounds_page, compounds_primitive
|
|
from devplacepy_services.database.broker_setup import get_broker
|
|
from devplacepy_services.database.invoke_registry import (
|
|
REGISTRY,
|
|
_encode_result,
|
|
is_write,
|
|
run_with_db,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class DbOpIn(BaseModel):
|
|
op: str
|
|
table: str | None = None
|
|
method: str | None = None
|
|
args: list[Any] = Field(default_factory=list)
|
|
kwargs: dict[str, Any] = Field(default_factory=dict)
|
|
write: bool = False
|
|
|
|
|
|
def _db_tables(db_conn):
|
|
return list(db_conn.tables)
|
|
|
|
|
|
def _db_query(db_conn, sql: str, **params):
|
|
return list(db_conn.query(sql, **params))
|
|
|
|
|
|
def _db_table_op(db_conn, table: str, method: str, args: list, kwargs: dict):
|
|
target = db_conn[table]
|
|
fn = getattr(target, method)
|
|
result = fn(*args, **kwargs)
|
|
if hasattr(result, "__iter__") and not isinstance(result, (str, bytes, dict)):
|
|
try:
|
|
return [_encode_result(row) for row in result]
|
|
except TypeError:
|
|
pass
|
|
return _encode_result(result)
|
|
|
|
|
|
@router.post("/internal/invoke")
|
|
async def internal_invoke(body: InvokeIn, _: InternalUser = Depends(internal_user)):
|
|
fn = REGISTRY.get(body.fn)
|
|
if fn is None:
|
|
return {"error": f"Unknown function: {body.fn}", "code": "unknown_function"}
|
|
write = body.write or is_write(body.fn)
|
|
broker = get_broker()
|
|
if write:
|
|
result = await broker.write(run_with_db, fn, body.args, body.kwargs)
|
|
else:
|
|
result = await broker.read(run_with_db, fn, body.args, body.kwargs)
|
|
return {"result": _encode_result(result)}
|
|
|
|
|
|
@router.post("/internal/db-op")
|
|
async def internal_db_op(body: DbOpIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
if body.op == "tables":
|
|
tables = await broker.read(_db_tables)
|
|
return tables
|
|
if body.op == "query":
|
|
sql = body.args[0] if body.args else ""
|
|
write = body.write or is_write_sql(sql)
|
|
if write:
|
|
rows = await broker.write(_db_query, sql, **body.kwargs)
|
|
else:
|
|
rows = await broker.read(_db_query, sql, **body.kwargs)
|
|
return [_encode_result(row) for row in rows]
|
|
if body.op == "table_op":
|
|
if not body.table or not body.method:
|
|
return {"error": "table and method required", "code": "invalid_request"}
|
|
write_methods = {"insert", "update", "delete", "create_column_by_example"}
|
|
write = body.write or body.method in write_methods
|
|
if write:
|
|
result = await broker.write(
|
|
_db_table_op, body.table, body.method, body.args, body.kwargs
|
|
)
|
|
else:
|
|
result = await broker.read(
|
|
_db_table_op, body.table, body.method, body.args, body.kwargs
|
|
)
|
|
return result
|
|
return {"error": f"Unknown op: {body.op}", "code": "unknown_op"}
|
|
|
|
|
|
@router.get("/settings/{key}")
|
|
async def settings_get(key: str, default: str = "", _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
value = await broker.read(run_with_db, get_setting, [key, default], {})
|
|
return {"key": key, "value": value}
|
|
|
|
|
|
@router.post("/cache/bump")
|
|
async def cache_bump(body: CacheBumpIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
await broker.write(run_with_db, bump_cache_version, [body.name], {})
|
|
return {"ok": True, "name": body.name}
|
|
|
|
|
|
@router.post("/compound/users-by-uids")
|
|
async def compound_users_by_uids(body: UsersByUidsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(run_with_db, compounds_primitive.users_by_uids, [body.uids], {})
|
|
|
|
|
|
@router.post("/compound/comment-counts")
|
|
async def compound_comment_counts(body: CommentCountsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_primitive.comment_counts, [body.post_uids], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/vote-counts")
|
|
async def compound_vote_counts(body: VoteCountsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_primitive.vote_counts, [body.target_uids], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/reactions")
|
|
async def compound_reactions(body: ReactionsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.reactions,
|
|
[body.target_type, body.target_uids, body.user],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/bookmarks")
|
|
async def compound_bookmarks(body: BookmarksIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.bookmarks,
|
|
[body.user_uid, body.target_type, body.target_uids],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/polls")
|
|
async def compound_polls(body: PollsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_primitive.polls, [body.post_uids, body.user], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/recent-comments")
|
|
async def compound_recent_comments(
|
|
body: RecentCommentsIn, _: InternalUser = Depends(internal_user)
|
|
):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.recent_comments,
|
|
[body.post_uids, body.limit, body.user],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/comments")
|
|
async def compound_comments(body: CommentsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.comments,
|
|
[body.target_type, body.target_uid, body.user],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/follow-bundle")
|
|
async def compound_follow_bundle(body: FollowBundleIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.follow_bundle,
|
|
[body.user_uid, body.target_uids],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/relations")
|
|
async def compound_relations(body: RelationsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_primitive.relations_bundle, [body.viewer_uid], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/online-users")
|
|
async def compound_online_users(body: OnlineUsersIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.online_users_bundle,
|
|
[body.cutoff_iso, body.limit],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/notification-prefs")
|
|
async def compound_notification_prefs(
|
|
body: NotificationPrefsIn, _: InternalUser = Depends(internal_user)
|
|
):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.notification_prefs_bundle,
|
|
[body.user_uid],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/leaderboard")
|
|
async def compound_leaderboard(
|
|
body: LeaderboardBundleIn, _: InternalUser = Depends(internal_user)
|
|
):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.leaderboard_bundle,
|
|
[body.limit, body.offset, body.viewer_uid],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/site-sidebar")
|
|
async def compound_site_sidebar(body: SiteSidebarIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_primitive.site_sidebar, [body.authors_limit], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/awards")
|
|
async def compound_awards(body: AwardsBundleIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.awards_bundle,
|
|
[body.receiver_uid, body.page, body.per_page, body.profile_user],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/attachments")
|
|
async def compound_attachments(body: AttachmentsIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.attachments_batch,
|
|
[body.resource_type, body.resource_uids],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/user-media")
|
|
async def compound_user_media(body: UserMediaIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.user_media_bundle,
|
|
[body.user_uid, body.page, body.per_page],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/seo-meta")
|
|
async def compound_seo_meta(body: SeoMetaIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_primitive.seo_meta_batch,
|
|
[body.target_type, body.uids],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/feed-page")
|
|
async def compound_feed_page(body: FeedPageIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_page.build_feed_page, [], body.model_dump()
|
|
)
|
|
|
|
|
|
@router.post("/compound/post-detail")
|
|
async def compound_post_detail(body: PostDetailIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_page.build_post_detail,
|
|
[body.post_uid, body.user],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/profile-bundle")
|
|
async def compound_profile_bundle(
|
|
body: ProfileBundleIn, _: InternalUser = Depends(internal_user)
|
|
):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_page.build_profile_bundle,
|
|
[body.profile_uid, body.viewer],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/messages-page")
|
|
async def compound_messages_page(body: MessagesPageIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_page.build_messages_page, [body.user_uid], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/notifications-page")
|
|
async def compound_notifications_page(
|
|
body: NotificationsPageIn, _: InternalUser = Depends(internal_user)
|
|
):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_page.build_notifications_page, [body.user_uid], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/leaderboard-page")
|
|
async def compound_leaderboard_page(
|
|
body: LeaderboardPageIn, _: InternalUser = Depends(internal_user)
|
|
):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_page.build_leaderboard_page, [body.viewer_uid], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/project-detail")
|
|
async def compound_project_detail(
|
|
body: ProjectDetailIn, _: InternalUser = Depends(internal_user)
|
|
):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_page.build_project_detail, [body.project_uid], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/gist-detail")
|
|
async def compound_gist_detail(body: GistDetailIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db,
|
|
compounds_page.build_gist_detail,
|
|
[body.gist_uid, body.user],
|
|
{},
|
|
)
|
|
|
|
|
|
@router.post("/compound/game-state")
|
|
async def compound_game_state(body: GameStateIn, _: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(
|
|
run_with_db, compounds_page.build_game_state, [body.user_uid], {}
|
|
)
|
|
|
|
|
|
@router.post("/compound/admin-dashboard")
|
|
async def compound_admin_dashboard(_: InternalUser = Depends(internal_user)):
|
|
broker = get_broker()
|
|
return await broker.read(run_with_db, compounds_page.build_admin_dashboard, [], {}) |