"""Community mutations — discussions, meetups, gigs, notifications.""" from fastapi import APIRouter, Header, HTTPException, Query from app.schemas import ( CreateDiscussionRequest, CreateGigRequest, CreateMeetupRequest, CreateReplyRequest, FeedbackRequest, GigApplyRequest, GigItem, NotificationItem, StatsOverview, ) from app.services.auth import get_user_by_token from app.services import community_store, social_store router = APIRouter(tags=["community"]) def _user(authorization: str | None) -> dict: if not authorization or not authorization.startswith("Bearer "): raise HTTPException(401, "未登录") user = get_user_by_token(authorization[7:]) if not user: raise HTTPException(401, "未登录") return user @router.post("/discussions") async def create_discussion(body: CreateDiscussionRequest, authorization: str | None = Header(None)): user = _user(authorization) d = community_store.create_discussion(user["id"], user["name"], body.model_dump()) return {"success": True, "discussion": d} @router.post("/discussions/{discussion_id}/replies") async def post_reply( discussion_id: str, body: CreateReplyRequest, authorization: str | None = Header(None), ): user = _user(authorization) reply = community_store.add_reply(discussion_id, user["id"], user["name"], body.content, body.author_emoji) if not reply: raise HTTPException(404, "讨论不存在") return {"success": True, "reply": reply} @router.post("/discussions/{discussion_id}/like") async def like_discussion(discussion_id: str, authorization: str | None = Header(None)): user = _user(authorization) return community_store.toggle_discussion_like(discussion_id, user["id"]) @router.post("/discussions/{discussion_id}/pin") async def pin_discussion(discussion_id: str, authorization: str | None = Header(None)): user = _user(authorization) d = community_store.toggle_pin(discussion_id, user["id"]) if not d: raise HTTPException(403, "仅作者可置顶") return {"success": True, "discussion": d} @router.post("/meetups") async def create_meetup(body: CreateMeetupRequest, authorization: str | None = Header(None)): user = _user(authorization) m = community_store.create_meetup(user["id"], user["name"], body.model_dump()) return {"success": True, "meetup": m} @router.get("/meetups/my-rsvp") async def my_rsvps(authorization: str | None = Header(None)): user = _user(authorization) return {"ids": list(community_store.user_rsvp_ids(user["id"]))} @router.get("/gigs", response_model=list[GigItem]) async def list_gigs(): return [GigItem(**g) for g in community_store.list_gigs()] @router.post("/gigs") async def create_gig(body: CreateGigRequest, authorization: str | None = Header(None)): user = _user(authorization) g = community_store.create_gig(user["id"], user["name"], body.model_dump()) return {"success": True, "gig": g} @router.post("/gigs/{gig_id}/apply") async def apply_gig(gig_id: str, body: GigApplyRequest, authorization: str | None = Header(None)): user = _user(authorization) res = community_store.apply_gig(gig_id, user["id"], user["name"], body.message) if not res.get("ok"): raise HTTPException(400, res.get("error", "申请失败")) return res @router.get("/notifications", response_model=list[NotificationItem]) async def list_notifications(authorization: str | None = Header(None)): user = _user(authorization) return [NotificationItem(**n) for n in community_store.list_notifications(user["id"])] @router.post("/notifications/read") async def mark_read(authorization: str | None = Header(None)): user = _user(authorization) community_store.mark_notifications_read(user["id"]) return {"success": True} @router.post("/notifications/{notif_id}/{action}") async def notification_action(notif_id: str, action: str, authorization: str | None = Header(None)): user = _user(authorization) if action not in ("read", "unread", "archive", "restore", "pin", "unpin"): raise HTTPException(400, "无效操作") n = community_store.update_notification(user["id"], notif_id, action) if not n: raise HTTPException(404, "通知不存在") return {"success": True, "notification": n} @router.post("/feedback") async def submit_feedback(body: FeedbackRequest, authorization: str | None = Header(None)): user = None name = body.name or "访客" if authorization and authorization.startswith("Bearer "): user = get_user_by_token(authorization[7:]) if user: name = user["name"] item = community_store.add_feedback(user["id"] if user else None, name, body.content, body.category) return {"success": True, "id": item["id"]} @router.get("/stats/overview", response_model=StatsOverview) async def stats_overview(): return StatsOverview(**community_store.stats_overview()) @router.get("/members/{user_id}") async def public_member(user_id: str): profile = social_store.get_public_profile(user_id) if not profile: raise HTTPException(404, "用户不存在") return profile