Files
spsays-bff/internal/model/admin.go
T
2026-08-07 22:46:08 +05:30

130 lines
5.4 KiB
Go

package model
import "time"
// Admin DTOs — read-only projections served only to admins via /api/v1/admin/*.
// They deliberately differ from the public-facing models: they may expose
// fields (email, role, reporter identity) that the normal API hides.
// AdminUser is a row in the admin users table.
type AdminUser struct {
ID string `json:"id"`
Email *string `json:"email"`
Handle string `json:"handle"`
Name string `json:"name"`
AvatarURL *string `json:"avatar_url"`
Role string `json:"role"`
Plan string `json:"plan"`
EmailVerifiedAt *time.Time `json:"email_verified_at"`
BannedAt *time.Time `json:"banned_at"`
PostCount int `json:"post_count"`
CreatedAt time.Time `json:"created_at"`
// Connected auth methods. HasPassword means email+password login is set up;
// Providers lists linked OAuth providers (e.g. "google", "facebook").
HasPassword bool `json:"has_password"`
Providers []string `json:"providers"`
// Effective save limits in force for this user (plan default merged with any
// admin override); -1 means unlimited. The admin UI pre-fills the "Edit
// limits" modal with these.
BookmarkLimit int `json:"bookmark_limit"`
PublicCollectionLimit int `json:"public_collection_limit"`
PrivateCollectionLimit int `json:"private_collection_limit"`
// Direct-disciple link. DiscipleID is the raw Mongo ObjectID stored on the
// users row; DiscipleName is hydrated from Mongo by the admin service so the
// panel can show who the account is linked to (nil when unlinked, or when
// the id no longer resolves to a disciple document).
DiscipleID *string `json:"disciple_id"`
DiscipleName *string `json:"disciple_name"`
}
// AdminDisciple is one option in the admin panel's disciple picker — enough to
// disambiguate similarly-named disciples, plus the handle of the account that
// already claims it (nil when free to link).
type AdminDisciple struct {
ID string `json:"id"`
InitiatedName string `json:"initiated_name"`
Suffix string `json:"suffix"`
InitiationDate *time.Time `json:"initiation_date"`
InitiationPlace *string `json:"initiation_place"`
// LinkedHandle is the @handle of the user already linked to this disciple,
// so the picker can grey the row out instead of failing on submit.
LinkedHandle *string `json:"linked_handle"`
}
// AdminPost is a row in the admin posts table.
type AdminPost struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Caption string `json:"caption"`
SourceTitle string `json:"source_title"`
SourceURL string `json:"source_url"`
IsHidden bool `json:"is_hidden"`
DeletedAt *time.Time `json:"deleted_at"`
CreatedAt time.Time `json:"created_at"`
AuthorName string `json:"author_name"`
AuthorHandle string `json:"author_handle"`
LikesCount int `json:"likes_count"`
CommentsCount int `json:"comments_count"`
}
// AdminCollection is a row in the admin collections table.
type AdminCollection struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Title string `json:"title"`
Description *string `json:"description"`
IsPublic bool `json:"is_public"`
ItemCount int `json:"item_count"`
CreatedAt time.Time `json:"created_at"`
OwnerName string `json:"owner_name"`
OwnerHandle string `json:"owner_handle"`
}
// AdminFeedback is a row in the admin feedback table (includes the reply).
type AdminFeedback struct {
ID string `json:"id"`
Category string `json:"category"`
Message string `json:"message"`
ContactEmail *string `json:"contact_email"`
CreatedAt time.Time `json:"created_at"`
AcknowledgedAt *time.Time `json:"acknowledged_at"`
ResolvedAt *time.Time `json:"resolved_at"`
RepliedAt *time.Time `json:"replied_at"`
ReplyMessage *string `json:"reply_message"`
AuthorHandle *string `json:"author_handle"`
AuthorName *string `json:"author_name"`
AuthorEmail *string `json:"author_email"`
}
// AdminReport is a unified projection over the three report tables
// (post_reports, comment_reports, user_reports). Type says which one.
type AdminReport struct {
ID string `json:"id"`
Type string `json:"type"` // "post" | "comment" | "user"
Category string `json:"category"`
Reason string `json:"reason"`
CreatedAt time.Time `json:"created_at"`
ResolvedAt *time.Time `json:"resolved_at"`
ReporterHandle *string `json:"reporter_handle"`
ReporterName *string `json:"reporter_name"`
// ResolutionNote is the admin's note left when resolving (nil while open).
ResolutionNote *string `json:"resolution_note"`
// TargetRemoved is true when the reported content is currently removed —
// a soft-deleted post/comment, or a banned account — so the UI can offer
// "Undo" instead of "Delete"/"Ban".
TargetRemoved bool `json:"target_removed"`
// Target of the report. TargetID is the post/comment/user id; TargetText
// is the post caption, comment body, or reported user's handle so the
// admin sees what was flagged without a second fetch. TargetAuthorHandle
// is the handle of the content's author (nil for user reports).
TargetID string `json:"target_id"`
TargetText *string `json:"target_text"`
TargetAuthorHandle *string `json:"target_author_handle"`
}