feat: social graph features
This commit is contained in:
@@ -86,3 +86,88 @@ type PublicProfile struct {
|
||||
PostCount int `json:"post_count"`
|
||||
BookmarkCount int `json:"-"` // never serialized — private
|
||||
}
|
||||
|
||||
// RelationshipState is the viewer's relationship to a target profile,
|
||||
// computed fresh per request from the follows + blocks tables. Every
|
||||
// field is "from the viewer looking at the target":
|
||||
//
|
||||
// - Following: viewer → target follow edge is accepted.
|
||||
// - FollowRequested: viewer → target follow edge is pending (awaiting
|
||||
// the target's approval). The "Requested" button state.
|
||||
// - FollowsYou: target → viewer follow edge is accepted (they
|
||||
// already follow the viewer). Drives the "Follow back" label and
|
||||
// the "Remove from followers" menu item.
|
||||
// - RequestsYou: target → viewer follow edge is pending (the target
|
||||
// asked to follow the viewer). Drives the Accept / Reject buttons.
|
||||
// - Blocked: viewer has blocked the target.
|
||||
// - BlockedBy: target has blocked the viewer.
|
||||
//
|
||||
// nil (not this struct's zero value) is returned for anonymous viewers
|
||||
// and for a user viewing their own profile — callers special-case those.
|
||||
type RelationshipState struct {
|
||||
Following bool `json:"following"`
|
||||
FollowRequested bool `json:"follow_requested"`
|
||||
FollowsYou bool `json:"follows_you"`
|
||||
RequestsYou bool `json:"requests_you"`
|
||||
Blocked bool `json:"blocked"`
|
||||
BlockedBy bool `json:"blocked_by"`
|
||||
}
|
||||
|
||||
// Follow is one row of the follows table — a directed, request-based
|
||||
// edge from Follower to Following. Status is "pending" until the target
|
||||
// accepts.
|
||||
type Follow struct {
|
||||
ID string `json:"id"`
|
||||
FollowerID string `json:"follower_id"`
|
||||
FollowingID string `json:"following_id"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
RespondedAt *time.Time `json:"responded_at,omitempty"`
|
||||
}
|
||||
|
||||
// UserBlock is one row of user_blocks — Blocker has blocked Blocked.
|
||||
type UserBlock struct {
|
||||
ID string `json:"id"`
|
||||
BlockerID string `json:"blocker_id"`
|
||||
BlockedID string `json:"blocked_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// UserReport is one row of user_reports — Reporter flagged Reported.
|
||||
type UserReport struct {
|
||||
ID string `json:"id"`
|
||||
ReporterID string `json:"reporter_id"`
|
||||
ReportedID string `json:"reported_id"`
|
||||
Category string `json:"category"`
|
||||
Reason string `json:"reason"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
|
||||
}
|
||||
|
||||
// PostReport is one row of post_reports — Reporter flagged a specific
|
||||
// post. Reason is optional ("" when none given).
|
||||
type PostReport struct {
|
||||
ID string `json:"id"`
|
||||
ReporterID string `json:"reporter_id"`
|
||||
PostID string `json:"post_id"`
|
||||
Category string `json:"category"`
|
||||
Reason string `json:"reason"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
|
||||
}
|
||||
|
||||
// Notification is one delivered/queued notification for a recipient
|
||||
// (UserID). ActorID is who triggered it; Kind is a short machine string.
|
||||
// Hydrated Actor* fields are filled by repo joins for list rendering.
|
||||
type Notification struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
ActorID *string `json:"actor_id,omitempty"`
|
||||
Kind string `json:"kind"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ReadAt *time.Time `json:"read_at,omitempty"`
|
||||
|
||||
ActorName *string `json:"actor_name,omitempty"`
|
||||
ActorHandle *string `json:"actor_handle,omitempty"`
|
||||
ActorAvatar *string `json:"actor_avatar_url,omitempty"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user