feat: social graph features
This commit is contained in:
@@ -26,9 +26,36 @@ import (
|
||||
// PostHandler
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type PostHandler struct{ svc *service.PostService }
|
||||
type PostHandler struct {
|
||||
svc *service.PostService
|
||||
graph *service.SocialGraphService // post reporting
|
||||
}
|
||||
|
||||
func NewPostHandler(svc *service.PostService) *PostHandler { return &PostHandler{svc: svc} }
|
||||
func NewPostHandler(svc *service.PostService, graph *service.SocialGraphService) *PostHandler {
|
||||
return &PostHandler{svc: svc, graph: graph}
|
||||
}
|
||||
|
||||
type reportPostReq struct {
|
||||
Category string `json:"category"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// Report files a report against this post. Body: {category, reason?}.
|
||||
// Auth-required; the reporter is the signed-in viewer.
|
||||
func (h *PostHandler) Report(w http.ResponseWriter, r *http.Request) {
|
||||
uid := middleware.UserID(r.Context())
|
||||
id := chi.URLParam(r, "id")
|
||||
var req reportPostReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
response.Error(w, http.StatusBadRequest, "invalid JSON body")
|
||||
return
|
||||
}
|
||||
if err := h.graph.ReportPost(r.Context(), uid, id, req.Category, req.Reason); err != nil {
|
||||
mapSocialErr(w, err)
|
||||
return
|
||||
}
|
||||
response.NoContent(w)
|
||||
}
|
||||
|
||||
type createPostReq struct {
|
||||
Caption string `json:"caption"`
|
||||
@@ -414,10 +441,11 @@ type ProfileHandler struct {
|
||||
users *repository.UserRepo
|
||||
posts *repository.PostRepo
|
||||
collections *repository.CollectionRepo
|
||||
graph *service.SocialGraphService
|
||||
}
|
||||
|
||||
func NewProfileHandler(users *repository.UserRepo, posts *repository.PostRepo, collections *repository.CollectionRepo) *ProfileHandler {
|
||||
return &ProfileHandler{users: users, posts: posts, collections: collections}
|
||||
func NewProfileHandler(users *repository.UserRepo, posts *repository.PostRepo, collections *repository.CollectionRepo, graph *service.SocialGraphService) *ProfileHandler {
|
||||
return &ProfileHandler{users: users, posts: posts, collections: collections, graph: graph}
|
||||
}
|
||||
|
||||
func (h *ProfileHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -437,12 +465,27 @@ func (h *ProfileHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
response.Error(w, http.StatusInternalServerError, "could not load collections")
|
||||
return
|
||||
}
|
||||
// Follower/following counts + the viewer's relationship to this
|
||||
// profile. viewerID is "" for anonymous viewers (OptionalAuth) and
|
||||
// equal to u.ID when the owner hits their own /u/{handle} — both
|
||||
// cases yield a nil `relationship` so the frontend hides the
|
||||
// follow/block affordances.
|
||||
viewerID := middleware.UserID(r.Context())
|
||||
followers, following, rel, err := h.graph.ProfileExtras(r.Context(), viewerID, u)
|
||||
if err != nil {
|
||||
response.Error(w, http.StatusInternalServerError, "could not load relationship")
|
||||
return
|
||||
}
|
||||
response.JSON(w, http.StatusOK, map[string]any{
|
||||
"handle": u.Handle,
|
||||
"name": u.Name,
|
||||
"avatar_url": u.AvatarURL,
|
||||
"joined_at": u.CreatedAt,
|
||||
"country": u.Country,
|
||||
"post_count": count,
|
||||
"follower_count": followers,
|
||||
"following_count": following,
|
||||
"relationship": rel,
|
||||
"public_collections": cols,
|
||||
})
|
||||
}
|
||||
@@ -500,6 +543,8 @@ func mapSocialErr(w http.ResponseWriter, err error) {
|
||||
response.Error(w, http.StatusNotFound, "not found")
|
||||
case errors.Is(err, service.ErrForbidden):
|
||||
response.Error(w, http.StatusForbidden, "not allowed")
|
||||
case errors.Is(err, service.ErrBlocked):
|
||||
response.Error(w, http.StatusForbidden, "this action isn't available between you and this user")
|
||||
case errors.Is(err, service.ErrPlanLimit):
|
||||
response.Error(w, http.StatusPaymentRequired, err.Error())
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user