handlers

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 48 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIKeyHandler

type APIKeyHandler struct {
	// contains filtered or unexported fields
}

APIKeyHandler handles browser-realm API key lifecycle endpoints.

func NewAPIKeyHandler

func NewAPIKeyHandler(
	apiKeyService APIKeyService,
	logger *util.Logger,
) *APIKeyHandler

NewAPIKeyHandler constructs a new APIKeyHandler.

func (*APIKeyHandler) CreateAPIKey

func (h *APIKeyHandler) CreateAPIKey(w http.ResponseWriter, r *http.Request)

CreateAPIKey handles POST /api/admin/api-keys.

func (*APIKeyHandler) ListAPIKeys

func (h *APIKeyHandler) ListAPIKeys(w http.ResponseWriter, r *http.Request)

ListAPIKeys handles GET /api/admin/api-keys. Returns the caller's keys as masked list entries (prefix + metadata only). The secret, key_hash, and last_used_ip are NEVER included in the response.

func (*APIKeyHandler) RevokeAPIKey

func (h *APIKeyHandler) RevokeAPIKey(w http.ResponseWriter, r *http.Request)

RevokeAPIKey handles DELETE /api/admin/api-keys/:id. Soft-deletes the key (sets revoked_at). Idempotent: revoking an already-revoked key returns 200. Cross-user or nonexistent ids return 404 NOT_FOUND (identical response — no cross-user disclosure).

type APIKeyListItem

type APIKeyListItem struct {
	ID         int        `json:"id"`
	Name       string     `json:"name"`
	Prefix     string     `json:"prefix"`
	CreatedAt  time.Time  `json:"createdAt"`
	LastUsedAt *time.Time `json:"lastUsedAt"`
	ExpiresAt  *time.Time `json:"expiresAt"`
	RevokedAt  *time.Time `json:"revokedAt"`
}

APIKeyListItem is a safe (masked) list entry. It MUST NOT contain keyHash, the secret, or lastUsedIp (privacy-sensitive). Prefix is the masked display form "lesstruct_<keyID>••••" produced via apikey.DisplayPrefix.

type APIKeyService

type APIKeyService interface {
	// Existing (Story 1.1):
	Create(ctx context.Context, userID int, name string) (string, *apikey.APIKey, error)
	// New (Story 1.2):
	List(ctx context.Context, userID int) ([]*apikey.APIKey, error)
	Revoke(ctx context.Context, id, userID int) (*apikey.APIKey, error)
}

APIKeyService is the narrow interface the handler depends on (avoids hard-coupling to *apikey.Service; mirrors the dashboard ServiceInterface pattern).

type AliasRedirectHandler added in v0.8.0

type AliasRedirectHandler struct {
	// contains filtered or unexported fields
}

func NewAliasRedirectHandler added in v0.8.0

func NewAliasRedirectHandler(
	aliasService *aliasdomain.Service,
	contentSvc contentGetter,
	next http.Handler,
) *AliasRedirectHandler

func (*AliasRedirectHandler) ServeHTTP added in v0.8.0

func (h *AliasRedirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type ApproveUserResponse

type ApproveUserResponse struct {
	Message string      `json:"message"`
	User    *UserDetail `json:"user"`
}

ApproveUserResponse represents the response for approve user

type AuthHandler

type AuthHandler struct {
	// contains filtered or unexported fields
}

AuthHandler handles authentication HTTP requests

func NewAuthHandler

func NewAuthHandler(
	authService *authdomain.AuthService,
	jwtManager *auth.JWTManager,
	logger *util.Logger,
	firstLoginService *authdomain.FirstLoginService,
	registrationService *authdomain.RegistrationService,
	verificationService *authdomain.VerificationService,
	loginService *authdomain.LoginService,
	passwordResetService *authdomain.PasswordResetService,
	userRepo repository.UserRepo,
	failedLoginRepo repository.FailedLoginAttemptRepo,
	notificationRepo repository.NotificationRepo,
	emailService email.EmailService,
	blockedEmailRepo repository.BlockedEmailRepo,
) *AuthHandler

NewAuthHandler creates a new auth handler

func (*AuthHandler) ForgotPassword

func (h *AuthHandler) ForgotPassword(w http.ResponseWriter, r *http.Request)

ForgotPassword handles POST /api/auth/forgot-password

func (*AuthHandler) Login

func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request)

Login handles POST /api/auth/login

func (*AuthHandler) RegisterUser

func (h *AuthHandler) RegisterUser(w http.ResponseWriter, r *http.Request)

RegisterUser handles POST /api/auth/register

func (*AuthHandler) ResendVerificationEmail

func (h *AuthHandler) ResendVerificationEmail(w http.ResponseWriter, r *http.Request)

ResendVerificationEmail handles POST /api/auth/resend-verification

func (*AuthHandler) ResetPassword

func (h *AuthHandler) ResetPassword(w http.ResponseWriter, r *http.Request)

ResetPassword handles POST /api/auth/reset-password

func (*AuthHandler) VerifyEmail

func (h *AuthHandler) VerifyEmail(w http.ResponseWriter, r *http.Request)

VerifyEmail handles GET /api/auth/verify-email

type CommentHandler

type CommentHandler struct {
	// contains filtered or unexported fields
}

func NewCommentHandler

func NewCommentHandler(contentService contentdomain.ServiceInterface) *CommentHandler

func (*CommentHandler) CreateComment

func (h *CommentHandler) CreateComment(w http.ResponseWriter, r *http.Request)

func (*CommentHandler) DeleteComment

func (h *CommentHandler) DeleteComment(w http.ResponseWriter, r *http.Request)

func (*CommentHandler) DeleteOwnComment

func (h *CommentHandler) DeleteOwnComment(w http.ResponseWriter, r *http.Request)

func (*CommentHandler) GetComments

func (h *CommentHandler) GetComments(w http.ResponseWriter, r *http.Request)

func (*CommentHandler) GetCommentsForModeration

func (h *CommentHandler) GetCommentsForModeration(w http.ResponseWriter, r *http.Request)

func (*CommentHandler) GetMyComments

func (h *CommentHandler) GetMyComments(w http.ResponseWriter, r *http.Request)

func (*CommentHandler) GetPendingComments added in v0.3.0

func (h *CommentHandler) GetPendingComments(w http.ResponseWriter, r *http.Request)

func (*CommentHandler) UpdateCommentStatus

func (h *CommentHandler) UpdateCommentStatus(w http.ResponseWriter, r *http.Request)

type CommentResponse

type CommentResponse struct {
	ID        int       `json:"id"`
	Comment   string    `json:"comment"`
	Author    string    `json:"author,omitempty"`
	Username  string    `json:"username,omitempty"`
	Role      string    `json:"role,omitempty"`
	Status    string    `json:"status,omitempty"`
	CreatedAt time.Time `json:"createdAt"`
}

type CompleteSetupRequest

type CompleteSetupRequest struct {
	Password     string `json:"password"`
	Email        string `json:"email"`
	DatabaseType string `json:"databaseType"`
}

CompleteSetupRequest represents the request body for completing first-login setup

type CompleteSetupResponse

type CompleteSetupResponse struct {
	Message  string `json:"message"`
	Redirect string `json:"redirect"`
}

CompleteSetupResponse represents the response for completing first-login setup

type ContentHandler

type ContentHandler struct {
	// contains filtered or unexported fields
}

func NewContentHandler

func NewContentHandler(
	contentService ContentServiceInterface,
	logger *util.Logger,
	baseURL string,
	profilePictureURLResolver func(string) string,
	featuredImageResolver func(string) string,
) *ContentHandler

func (*ContentHandler) CreateContent

func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) DeleteContent

func (h *ContentHandler) DeleteContent(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) GenerateSlug

func (h *ContentHandler) GenerateSlug(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) GetContent

func (h *ContentHandler) GetContent(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) GetPublishedAuthor added in v0.7.0

func (h *ContentHandler) GetPublishedAuthor(w http.ResponseWriter, r *http.Request)

GetPublishedAuthor returns a single published author's public profile. It follows the same response shape as the ListPublishedAuthors endpoint (PublicAuthorResponse) but for one author. Returns 404 when the author has no published content or does not exist.

func (*ContentHandler) GetPublishedContent

func (h *ContentHandler) GetPublishedContent(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) GetPublishedContentByAuthor

func (h *ContentHandler) GetPublishedContentByAuthor(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) GetSEO

func (h *ContentHandler) GetSEO(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) ListContents

func (h *ContentHandler) ListContents(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) ListPublishedArchive added in v0.6.0

func (h *ContentHandler) ListPublishedArchive(w http.ResponseWriter, r *http.Request)

ListPublishedArchive returns published-content counts grouped by year and month, newest first. Optional ?post_type filters to a single post type; optional ?language filters to a single language. Each entry includes a URL pointing to the matching listing page with ?year= and ?month= params.

func (*ContentHandler) ListPublishedAuthors added in v0.5.0

func (h *ContentHandler) ListPublishedAuthors(w http.ResponseWriter, r *http.Request)

ListPublishedAuthors returns the users who have published at least one content item, with only safe public fields (username, display name, avatar, profile URL, published-content count, and the distinct post types they publish under). No email, role, or custom fields are exposed. Ordered by published-content count (desc) then username (asc) — useful for "most active contributors" widgets and author directories.

func (*ContentHandler) ListPublishedContents

func (h *ContentHandler) ListPublishedContents(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) SearchPublished

func (h *ContentHandler) SearchPublished(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) SetSystemFields

func (h *ContentHandler) SetSystemFields(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) UpdateContent

func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request)

func (*ContentHandler) WithPublicFieldRegistry added in v0.7.0

func (h *ContentHandler) WithPublicFieldRegistry(registry PublicFieldLookup) *ContentHandler

WithPublicFieldRegistry attaches a [[public_field]] registry to the handler so /api/v1/public/* endpoints can enforce the public query allowlist. When not called (or called with nil), the handler rejects every cf_*/sort_by=cf:* parameter — fail-closed is the safe default. Returns the receiver for chaining at construction time.

type ContentServiceInterface

type ContentServiceInterface interface {
	Create(ctx context.Context, userID int, req contentdomain.CreateContentRequest) (*contentdomain.Content, error)
	GetByUser(ctx context.Context, userID int, limit int, offset int) ([]*contentdomain.Content, error)
	GetAll(ctx context.Context, limit int, offset int) ([]*contentdomain.Content, error)
	GetByID(ctx context.Context, id int) (*contentdomain.Content, error)
	GenerateSlugFromTitle(ctx context.Context, title string) (string, error)
	Update(ctx context.Context, id int, userID int, role string, req contentdomain.UpdateContentRequest) (*contentdomain.Content, error)
	DeleteContent(ctx context.Context, id int, userID int, role string) error
	GetPublished(ctx context.Context, limit int, offset int) ([]*contentdomain.Content, error)
	GetPublishedBySlug(ctx context.Context, slug string, language string) (*contentdomain.Content, error)
	GetTranslations(ctx context.Context, translationGroupID int, excludeID int) ([]*contentdomain.Content, error)
	GetPublishedByAuthorUsername(ctx context.Context, username string, language string, limit int, offset int) ([]*contentdomain.Content, error)
	AuthorExists(ctx context.Context, username string) (bool, error)
	ListByFilters(ctx context.Context, userID int, filters contentdomain.ContentFilters) ([]*contentdomain.Content, error)
	Count(ctx context.Context, userID int, filters contentdomain.ContentFilters) (int, error)
	SetSystemFields(ctx context.Context, contentID int, systemFields map[string]any) (*contentdomain.Content, error)
	SearchPublished(ctx context.Context, query string, limit int) ([]*contentdomain.Content, error)
	GetPublishedAuthors(ctx context.Context, filters contentdomain.PublishedAuthorFilters) ([]*contentdomain.PublishedAuthor, error)
	GetPublishedAuthor(ctx context.Context, username string) (*contentdomain.PublishedAuthor, error)
	GetPublishedArchive(ctx context.Context, postType string, language string) ([]*contentdomain.ArchiveMonth, error)
	GetPublishedByPostType(ctx context.Context, postType string, language string, year int, month int, limit int, offset int) ([]*contentdomain.Content, error)
}

type CreateAPIKeyRequest

type CreateAPIKeyRequest struct {
	Name  string `json:"name"`
	Scope string `json:"scope,omitempty"` // TODO(story-future): per-key scopes deferred — accepted but not persisted
}

CreateAPIKeyRequest is the payload for POST /api/admin/api-keys.

type CreateAPIKeyResponse

type CreateAPIKeyResponse struct {
	Key       string    `json:"key"`
	ID        int       `json:"id"`
	Name      string    `json:"name"`
	KeyPrefix string    `json:"keyPrefix"`
	CreatedAt time.Time `json:"createdAt"`
}

CreateAPIKeyResponse is returned on successful key creation. The full key string is included exactly once; the client must store it.

type CreateCommentRequest

type CreateCommentRequest struct {
	Comment string `json:"comment"`
}

type CreateContentData

type CreateContentData struct {
	Content *contentdomain.Content `json:"content"`
}

type CreateContentRequest

type CreateContentRequest struct {
	Title              string         `json:"title"`
	Slug               string         `json:"slug,omitempty"`
	Content            string         `json:"content"`
	Format             string         `json:"format,omitempty"`
	Tags               []string       `json:"tags"`
	Status             string         `json:"status"`
	PostType           string         `json:"postType"`
	MetaDescription    string         `json:"metaDescription,omitempty"`
	OGTitle            string         `json:"ogTitle,omitempty"`
	OGDescription      string         `json:"ogDescription,omitempty"`
	AllowComments      *bool          `json:"allowComments,omitempty"`
	CustomFields       map[string]any `json:"customFields,omitempty"`
	Language           string         `json:"language,omitempty"`
	TranslationGroupID *int           `json:"translationGroupId,omitempty"`
}

type CreateContentResponse

type CreateContentResponse struct {
	Data *CreateContentData `json:"data"`
	Meta *ResponseMeta      `json:"meta"`
}

type CreateUserRequest

type CreateUserRequest struct {
	Username     string         `json:"username"`
	Name         string         `json:"name"`
	Email        string         `json:"email"`
	Role         string         `json:"role"`
	CustomFields map[string]any `json:"customFields,omitempty"`
}

CreateUserRequest represents the request body for creating a user

type CreateUserResponse

type CreateUserResponse struct {
	Message  string      `json:"message"`
	User     *UserDetail `json:"user"`
	Password string      `json:"password"`
}

CreateUserResponse represents the response for creating a user

type DashboardHandler

type DashboardHandler struct {
	// contains filtered or unexported fields
}

func NewDashboardHandler

func NewDashboardHandler(dashboardService DashboardServiceInterface, logger *util.Logger) *DashboardHandler

func (*DashboardHandler) GetStats

func (h *DashboardHandler) GetStats(w http.ResponseWriter, r *http.Request)

type DashboardServiceInterface

type DashboardServiceInterface interface {
	GetStats(ctx context.Context, userID int) (*dashboarddomain.Stats, error)
}

type DataExportMeta

type DataExportMeta struct {
	Timestamp string `json:"timestamp"`
}

DataExportMeta represents metadata in data export response

type DeleteAccountRequest

type DeleteAccountRequest struct {
	Confirmation string `json:"confirmation"`
}

DeleteAccountRequest represents a request to delete an account

type DeletedContentItem

type DeletedContentItem struct {
	ID          int    `json:"id"`
	ContentType string `json:"contentType"`
	ContentID   int    `json:"contentId"`
	DeletedAt   string `json:"deletedAt"`
	DeletedBy   string `json:"deletedBy"`
	Reason      string `json:"reason,omitempty"`
}

DeletedContentItem represents a soft deleted content item

type EmailUpdateData

type EmailUpdateData struct {
	Message  string `json:"message"`
	NewEmail string `json:"newEmail"`
}

EmailUpdateData represents email update data in the response

type EmailUpdateRequest

type EmailUpdateRequest struct {
	NewEmail        string `json:"newEmail"`
	CurrentPassword string `json:"currentPassword"`
}

EmailUpdateRequest represents a request to update email

type EmailUpdateResponse

type EmailUpdateResponse struct {
	Data *EmailUpdateData     `json:"data"`
	Meta *ProfileResponseMeta `json:"meta"`
}

EmailUpdateResponse represents the response for email update

type ExportHandler added in v0.8.0

type ExportHandler struct {
	// contains filtered or unexported fields
}

func NewExportHandler added in v0.8.0

func NewExportHandler(exporter *export.Exporter, logger *util.Logger) *ExportHandler

func (*ExportHandler) Export added in v0.8.0

func (h *ExportHandler) Export(w http.ResponseWriter, r *http.Request)

type FirstLoginHandler

type FirstLoginHandler struct {
	// contains filtered or unexported fields
}

FirstLoginHandler handles first-login setup HTTP requests

func NewFirstLoginHandler

func NewFirstLoginHandler(
	firstLoginService *authdomain.FirstLoginService,
	userRepo repository.UserRepo,
	logger *util.Logger,
) *FirstLoginHandler

NewFirstLoginHandler creates a new first-login handler

func (*FirstLoginHandler) CompleteSetup

func (h *FirstLoginHandler) CompleteSetup(w http.ResponseWriter, r *http.Request)

CompleteSetup handles POST /api/auth/first-login

func (*FirstLoginHandler) GetStatus

func (h *FirstLoginHandler) GetStatus(w http.ResponseWriter, r *http.Request)

GetStatus handles GET /api/auth/first-login

type FirstLoginStatus

type FirstLoginStatus struct {
	FirstLoginComplete bool   `json:"firstLoginComplete"`
	Redirect           string `json:"redirect,omitempty"`
}

FirstLoginStatus represents the first-login status response

type ForgotPasswordRequest

type ForgotPasswordRequest struct {
	Email string `json:"email"`
}

ForgotPasswordRequest represents the forgot password request body

type GenerateSlugData

type GenerateSlugData struct {
	Slug string `json:"slug"`
}

type GenerateSlugRequest

type GenerateSlugRequest struct {
	Title string `json:"title"`
}

type GenerateSlugResponse

type GenerateSlugResponse struct {
	Data *GenerateSlugData `json:"data"`
	Meta *ResponseMeta     `json:"meta"`
}

type GetAllUsersResponse

type GetAllUsersResponse struct {
	Data []*UserInList `json:"data"`
	Meta *UsersMeta    `json:"meta"`
}

GetAllUsersResponse represents the response for get all users

type GetPendingUsersResponse

type GetPendingUsersResponse struct {
	Data []*PendingUser `json:"data"`
	Meta *ResponseMeta  `json:"meta"`
}

GetPendingUsersResponse represents the response for pending users

type GetSoftDeletedContentResponse

type GetSoftDeletedContentResponse struct {
	Data []*DeletedContentItem `json:"data"`
	Meta *ResponseMeta         `json:"meta"`
}

GetSoftDeletedContentResponse represents the response for get soft deleted content

type HugoHandler added in v0.8.0

type HugoHandler struct {
	// contains filtered or unexported fields
}

func NewHugoHandler added in v0.8.0

func NewHugoHandler(
	importer *hugo.Importer,
	logger *util.Logger,
	maxImportBytes int64,
	importTimeout time.Duration,
) *HugoHandler

func (*HugoHandler) Import added in v0.8.0

func (h *HugoHandler) Import(w http.ResponseWriter, r *http.Request)

Import accepts a tar.gz archive of a Hugo project and starts an asynchronous import job. Returns 202 Accepted with a job ID immediately. The caller can poll GET /api/admin/hugo/import/status/{jobId} for progress.

func (*HugoHandler) ImportStatus added in v0.8.0

func (h *HugoHandler) ImportStatus(w http.ResponseWriter, r *http.Request)

ImportStatus returns the current state of a Hugo import job. GET /api/admin/hugo/import/status/{jobId} — specific job GET /api/admin/hugo/import/status — most recent job

type LoginRequest

type LoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

LoginRequest represents the login request body

type LoginResponse

type LoginResponse struct {
	Token string      `json:"token"`
	User  UserInfoRef `json:"user"`
}

LoginResponse represents the successful login response

type MarkUserAsSpamResponse

type MarkUserAsSpamResponse struct {
	Message string `json:"message"`
	Email   string `json:"email"`
}

MarkUserAsSpamResponse represents the response for mark as spam

type MediaHandler

type MediaHandler struct {
	// contains filtered or unexported fields
}

func NewMediaHandler

func NewMediaHandler(
	mediaService MediaServiceInterface,
	imageGenService media.ImageGenerationService,
	logger *util.Logger,
) *MediaHandler

func (*MediaHandler) DeleteMedia

func (h *MediaHandler) DeleteMedia(w http.ResponseWriter, r *http.Request)

func (*MediaHandler) GenerateImage

func (h *MediaHandler) GenerateImage(w http.ResponseWriter, r *http.Request)

func (*MediaHandler) GetMedia

func (h *MediaHandler) GetMedia(w http.ResponseWriter, r *http.Request)

GetMedia handles GET /api/v1/media (browser admin realm). It returns ALL media (admins manage all site media) in newest-first (id DESC) order using opaque keyset (cursor) pagination — the SAME contract as the agent media list (bare data array + meta.pagination). It reuses the response package's cursor helpers and SuccessList/ Pagination/ListMeta types so both auth realms share one envelope.

func (*MediaHandler) GetMediaByID

func (h *MediaHandler) GetMediaByID(w http.ResponseWriter, r *http.Request)

func (*MediaHandler) Upload

func (h *MediaHandler) Upload(w http.ResponseWriter, r *http.Request)

type MediaLister added in v0.6.0

type MediaLister interface {
	ListByCursor(ctx context.Context, userID int, limit int, beforeID int) ([]*mediadomain.Media, error)
}

MediaLister provides access to media items for AI context injection.

type MediaServiceInterface

type MediaServiceInterface interface {
	Upload(ctx context.Context, req media.UploadRequest) (*media.Media, error)
	ForceUpload(ctx context.Context, req media.UploadRequest) (*media.Media, error)
	GenerateFromBytes(ctx context.Context, imageBytes []byte, userID int, altText string, originalFilename string) (*media.Media, error)
	GetByID(ctx context.Context, id int) (*media.Media, error)
	Delete(ctx context.Context, id int, userID int, userRole string) error
	SearchMediaByCursor(ctx context.Context, search string, dateFilter string, limit int, beforeID int) ([]*media.Media, error)
	Count(ctx context.Context, search string, dateFilter string) (int, error)
}

type NotificationHandler

type NotificationHandler struct {
	// contains filtered or unexported fields
}

NotificationHandler handles notification HTTP requests

func NewNotificationHandler

func NewNotificationHandler(
	logger *util.Logger,
	notificationRepo repository.NotificationRepo,
) *NotificationHandler

NewNotificationHandler creates a new notification handler

func (*NotificationHandler) GetNotifications

func (h *NotificationHandler) GetNotifications(w http.ResponseWriter, r *http.Request)

GetNotifications handles GET /api/notifications

type NotificationRef

type NotificationRef struct {
	ID        int                         `json:"id"`
	Type      repository.NotificationType `json:"type"`
	Message   string                      `json:"message"`
	CreatedAt time.Time                   `json:"createdAt"`
}

NotificationRef represents a notification in the response

type NotificationsResponse

type NotificationsResponse struct {
	Notifications []NotificationRef `json:"notifications"`
}

NotificationsResponse represents the notifications response

type PasswordUpdateData

type PasswordUpdateData struct {
	Message string `json:"message"`
}

PasswordUpdateData represents password update data in the response

type PasswordUpdateRequest

type PasswordUpdateRequest struct {
	CurrentPassword string `json:"currentPassword"`
	NewPassword     string `json:"newPassword"`
}

PasswordUpdateRequest represents a request to update password

type PasswordUpdateResponse

type PasswordUpdateResponse struct {
	Data *PasswordUpdateData  `json:"data"`
	Meta *ProfileResponseMeta `json:"meta"`
}

PasswordUpdateResponse represents the response for password update

type PendingCommentResponse added in v0.3.0

type PendingCommentResponse struct {
	ID           int       `json:"id"`
	ContentID    int       `json:"contentId"`
	ContentTitle string    `json:"contentTitle,omitempty"`
	ContentSlug  string    `json:"contentSlug,omitempty"`
	Comment      string    `json:"comment"`
	Author       string    `json:"author,omitempty"`
	Username     string    `json:"username,omitempty"`
	Status       string    `json:"status,omitempty"`
	CreatedAt    time.Time `json:"createdAt"`
}

PendingCommentResponse is the admin-facing representation of a comment awaiting moderation, enriched with the content item it belongs to.

type PendingUser

type PendingUser struct {
	ID             int       `json:"id"`
	Username       string    `json:"username"`
	Email          string    `json:"email"`
	ProfilePicture string    `json:"profilePicture,omitempty"`
	CreatedAt      time.Time `json:"createdAt"`
}

PendingUser represents a pending user in the response

type PostTypeHandler

type PostTypeHandler struct {
	// contains filtered or unexported fields
}

PostTypeHandler handles post type HTTP requests

func NewPostTypeHandler

func NewPostTypeHandler(postTypeService PostTypeServiceInterface, logger *util.Logger) *PostTypeHandler

NewPostTypeHandler creates a new post type handler

func (*PostTypeHandler) GetPostTypes

func (h *PostTypeHandler) GetPostTypes(w http.ResponseWriter, r *http.Request)

GetPostTypes returns all registered post types

func (*PostTypeHandler) GetPublicPostTypes

func (h *PostTypeHandler) GetPublicPostTypes(w http.ResponseWriter, r *http.Request)

GetPublicPostTypes returns all post types without requiring authentication

func (*PostTypeHandler) GetUserFieldsEndpoint

func (h *PostTypeHandler) GetUserFieldsEndpoint(w http.ResponseWriter, r *http.Request)

GetUserFieldsEndpoint returns user field schemas (custom and system)

type PostTypeServiceInterface

type PostTypeServiceInterface interface {
	GetAll() []posttype.PostType
	GetBySlug(slug string) (posttype.PostType, error)
	Register(pt posttype.PostType) error
	GetUserFields() []customfield.FieldSchema
	GetUserSystemFields() []customfield.FieldSchema
}

PostTypeServiceInterface defines the interface for post type service

type ProfileData

type ProfileData struct {
	Profile *ProfileInfo `json:"profile"`
}

ProfileData represents profile data in the response

type ProfileHandler

type ProfileHandler struct {
	// contains filtered or unexported fields
}

ProfileHandler handles profile management HTTP requests

func NewProfileHandler

func NewProfileHandler(
	profileService user.ProfileServiceInterface,
	accountDeletionService user.AccountDeletionServiceInterface,
	jwtManager *auth.JWTManager,
	logger *util.Logger,
	userFieldsProvider userFieldsProvider,
	profilePictureURLBuilder func(string) string,
) *ProfileHandler

NewProfileHandler creates a new profile handler

func (*ProfileHandler) ChangePassword

func (h *ProfileHandler) ChangePassword(w http.ResponseWriter, r *http.Request)

ChangePassword handles PUT /api/profile/password

func (*ProfileHandler) DeleteAccount

func (h *ProfileHandler) DeleteAccount(w http.ResponseWriter, r *http.Request)

DeleteAccount handles DELETE /api/profile/account

func (*ProfileHandler) ExportUserData

func (h *ProfileHandler) ExportUserData(w http.ResponseWriter, r *http.Request)

ExportUserData handles GET /api/profile/export

func (*ProfileHandler) GetProfile

func (h *ProfileHandler) GetProfile(w http.ResponseWriter, r *http.Request)

GetProfile handles GET /api/profile

func (*ProfileHandler) GetUserFields

func (h *ProfileHandler) GetUserFields(w http.ResponseWriter, r *http.Request)

GetUserFields handles GET /api/profile/user-fields

func (*ProfileHandler) UpdateCustomFields

func (h *ProfileHandler) UpdateCustomFields(w http.ResponseWriter, r *http.Request)

UpdateCustomFields handles PUT /api/profile/custom-fields

func (*ProfileHandler) UpdateEmail

func (h *ProfileHandler) UpdateEmail(w http.ResponseWriter, r *http.Request)

UpdateEmail handles PUT /api/profile/email

func (*ProfileHandler) UpdateName added in v0.2.0

func (h *ProfileHandler) UpdateName(w http.ResponseWriter, r *http.Request)

UpdateName handles PUT /api/profile/name

func (*ProfileHandler) VerifyEmailUpdate

func (h *ProfileHandler) VerifyEmailUpdate(w http.ResponseWriter, r *http.Request)

VerifyEmailUpdate handles GET /api/profile/verify-email This endpoint does NOT require authentication - the verification token is sufficient

type ProfileInfo

type ProfileInfo struct {
	ID             int            `json:"id"`
	Username       string         `json:"username"`
	Name           string         `json:"name,omitempty"`
	Email          string         `json:"email"`
	Role           string         `json:"role"`
	ProfilePicture string         `json:"profilePicture,omitempty"`
	CreatedAt      time.Time      `json:"createdAt"`
	UpdatedAt      time.Time      `json:"updatedAt,omitempty"`
	CustomFields   map[string]any `json:"customFields,omitempty"`
}

ProfileInfo represents user profile information

type ProfilePictureHandler

type ProfilePictureHandler struct {
	// contains filtered or unexported fields
}

ProfilePictureHandler handles profile picture HTTP requests

func NewProfilePictureHandler

func NewProfilePictureHandler(
	service *profilepicture.Service,
	userRepo repository.UserRepo,
	logger *util.Logger,
) *ProfilePictureHandler

NewProfilePictureHandler creates a new profile picture handler

func (*ProfilePictureHandler) AdminDeleteUserPicture

func (h *ProfilePictureHandler) AdminDeleteUserPicture(w http.ResponseWriter, r *http.Request)

AdminDeleteUserPicture handles DELETE /api/admin/users/{id}/picture

func (*ProfilePictureHandler) AdminUploadUserPicture

func (h *ProfilePictureHandler) AdminUploadUserPicture(w http.ResponseWriter, r *http.Request)

AdminUploadUserPicture handles PUT /api/admin/users/{id}/picture

func (*ProfilePictureHandler) DeleteProfilePicture

func (h *ProfilePictureHandler) DeleteProfilePicture(w http.ResponseWriter, r *http.Request)

DeleteProfilePicture handles DELETE /api/profile/picture

func (*ProfilePictureHandler) UploadProfilePicture

func (h *ProfilePictureHandler) UploadProfilePicture(w http.ResponseWriter, r *http.Request)

UploadProfilePicture handles PUT /api/profile/picture

type ProfileResponse

type ProfileResponse struct {
	Data *ProfileData         `json:"data"`
	Meta *ProfileResponseMeta `json:"meta"`
}

ProfileResponse represents the response for profile information

type ProfileResponseMeta

type ProfileResponseMeta struct {
	Timestamp string `json:"timestamp"`
}

ProfileResponseMeta represents metadata in profile response

type PublicArchiveMonthResponse added in v0.6.0

type PublicArchiveMonthResponse struct {
	Year  int    `json:"year"`
	Month int    `json:"month"`
	Count int    `json:"count"`
	URL   string `json:"url"`
}

PublicArchiveMonthResponse is the public-facing shape for one month in a content archive. URL points to the listing page filtered by year/month.

type PublicAuthorResponse added in v0.5.0

type PublicAuthorResponse struct {
	Username     string         `json:"username"`
	DisplayName  string         `json:"displayName"`
	AvatarURL    string         `json:"avatarURL"`
	ProfileURL   string         `json:"profileURL"`
	ContentCount int            `json:"contentCount"`
	PostTypes    []string       `json:"postTypes"`
	PublicFields map[string]any `json:"publicFields,omitempty"`
}

PublicAuthorResponse is the safe, public-facing shape for a published author. It deliberately omits email, role, and status — those stay behind authentication (per Lesstruct's no-enumeration model). PublicFields carries the raw values of custom/system fields that are allowlisted with the "expose" operation in the [[public_field]] config. When no fields are allowlisted, the key is omitted from the JSON response (omitempty).

type PublicFieldLookup added in v0.7.0

type PublicFieldLookup interface {
	IsQueryable(resource, postType, field, operation string) bool
	ExposedFields(resource, postType string) []string
}

PublicFieldLookup is the minimal subset of *config.PublicFieldRegistry that ContentHandler consults to enforce the [[public_field]] allowlist. Defining it locally keeps the handler package decoupled from the config package and makes the handler trivially testable with a stub.

type RegisterUserRequest

type RegisterUserRequest struct {
	Username string `json:"username"`
	Name     string `json:"name"`
	Email    string `json:"email"`
	Password string `json:"password"`
}

RegisterUserRequest represents the registration request body

type RegisterUserResponse

type RegisterUserResponse struct {
	Message string `json:"message"`
	UserID  int    `json:"userId"`
}

RegisterUserResponse represents the successful registration response

type RejectUserResponse

type RejectUserResponse struct {
	Message  string `json:"message"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

RejectUserResponse represents the response for reject user

type ResendVerificationRequest

type ResendVerificationRequest struct {
	Email string `json:"email"`
}

ResendVerificationRequest represents the resend verification request body

type ResendVerificationResponse

type ResendVerificationResponse struct {
	Message string `json:"message"`
}

ResendVerificationResponse represents the successful resend response

type ResetPasswordRequest

type ResetPasswordRequest struct {
	Token       string `json:"token"`
	NewPassword string `json:"newPassword"`
}

ResetPasswordRequest represents the reset password request body

type ResponseMeta

type ResponseMeta struct {
	Count     int    `json:"count"`
	Timestamp string `json:"timestamp"`
}

ResponseMeta represents metadata in API responses

type RestoreContentResponse

type RestoreContentResponse struct {
	Message string           `json:"message"`
	Content *RestoredContent `json:"content"`
}

RestoreContentResponse represents the response for restore content

type RestoredContent

type RestoredContent struct {
	ID   int    `json:"id"`
	Type string `json:"type"`
}

RestoredContent represents restored content details

type RevokeAPIKeyResponse

type RevokeAPIKeyResponse struct {
	ID        int        `json:"id"`
	RevokedAt *time.Time `json:"revokedAt"`
}

RevokeAPIKeyResponse is returned on successful (or idempotent) revoke.

type SEOHandler

type SEOHandler struct {
	// contains filtered or unexported fields
}

func NewSEOHandler

func NewSEOHandler(
	contentService ContentServiceInterface,
	baseURL string,
	logger *util.Logger,
) *SEOHandler

func (*SEOHandler) GetRobotsTxt

func (h *SEOHandler) GetRobotsTxt(w http.ResponseWriter, r *http.Request)

func (*SEOHandler) GetSitemapData

func (h *SEOHandler) GetSitemapData(w http.ResponseWriter, r *http.Request)

func (*SEOHandler) GetSitemapXML added in v0.2.0

func (h *SEOHandler) GetSitemapXML(w http.ResponseWriter, r *http.Request)

GetSitemapXML serves the sitemaps.org XML document crawlers expect at /sitemap.xml (the path robots.txt advertises). The JSON shape served at /api/v1/sitemap is for programmatic callers; crawlers need XML.

type SSGHandler added in v0.8.0

type SSGHandler struct {
	// contains filtered or unexported fields
}

func NewSSGHandler added in v0.8.0

func NewSSGHandler(generator *ssg.Generator, logger *util.Logger) *SSGHandler

func (*SSGHandler) Generate added in v0.8.0

func (h *SSGHandler) Generate(w http.ResponseWriter, r *http.Request)

type SearchResult

type SearchResult struct {
	Slug            string `json:"slug"`
	Title           string `json:"title"`
	MetaDescription string `json:"metaDescription"`
}

type SoftDeleteContentRequest

type SoftDeleteContentRequest struct {
	Confirmed bool   `json:"confirmed"`
	Reason    string `json:"reason"`
}

SoftDeleteContentRequest represents the request for soft delete

type SoftDeleteUserResponse

type SoftDeleteUserResponse struct {
	Message             string      `json:"message"`
	User                *UserDetail `json:"user"`
	DeletedContentCount int         `json:"deletedContentCount"`
}

SoftDeleteUserResponse represents the response for soft delete user

type SuspendUserResponse

type SuspendUserResponse struct {
	Message string      `json:"message"`
	User    *UserDetail `json:"user"`
}

SuspendUserResponse represents the response for suspend user

type TextGenHandler

type TextGenHandler struct {
	// contains filtered or unexported fields
}

TextGenHandler handles AI text generation requests.

func NewTextGenHandler

func NewTextGenHandler(
	textGenService TextGenerationService,
	mediaService MediaLister,
	logger *util.Logger,
) *TextGenHandler

NewTextGenHandler creates a new TextGenHandler.

func (*TextGenHandler) Enhance

func (h *TextGenHandler) Enhance(w http.ResponseWriter, r *http.Request)

Enhance handles the "Enhance with AI" / "Generate with AI" endpoint.

func (*TextGenHandler) Translate

func (h *TextGenHandler) Translate(w http.ResponseWriter, r *http.Request)

Translate handles the "Translate with AI" endpoint.

type TextGenerationService

type TextGenerationService interface {
	EnhanceText(ctx context.Context, content, format, mediaContext string) (string, error)
	TranslateText(ctx context.Context, content, sourceLang, targetLang, format string) (string, error)
}

TextGenerationService defines the interface for AI text generation.

type UnsuspendUserResponse

type UnsuspendUserResponse struct {
	Message string      `json:"message"`
	User    *UserDetail `json:"user"`
}

UnsuspendUserResponse represents the response for unsuspend user

type UpdateCommentStatusRequest

type UpdateCommentStatusRequest struct {
	Status string `json:"status"`
}

type UpdateUserProfileRequest

type UpdateUserProfileRequest struct {
	Name         string         `json:"name"`
	Email        string         `json:"email"`
	Role         string         `json:"role"`
	CustomFields map[string]any `json:"customFields,omitempty"`
}

UpdateUserProfileRequest represents the request body for updating a user profile

type UpdateUserProfileResponse

type UpdateUserProfileResponse struct {
	Message string      `json:"message"`
	User    *UserDetail `json:"user"`
}

UpdateUserProfileResponse represents the response for updating a user profile

type UserDetail

type UserDetail struct {
	ID             int            `json:"id"`
	Username       string         `json:"username"`
	Email          string         `json:"email"`
	Role           string         `json:"role,omitempty"`
	Status         string         `json:"status"`
	ProfilePicture string         `json:"profilePicture,omitempty"`
	CustomFields   map[string]any `json:"customFields,omitempty"`
	CreatedAt      time.Time      `json:"createdAt,omitempty"`
}

UserDetail represents user details in responses

type UserInList

type UserInList struct {
	ID             int            `json:"id"`
	Username       string         `json:"username"`
	Email          string         `json:"email"`
	Status         string         `json:"status"`
	Role           string         `json:"role"`
	ProfilePicture string         `json:"profilePicture,omitempty"`
	CustomFields   map[string]any `json:"customFields,omitempty"`
	CreatedAt      time.Time      `json:"createdAt"`
}

UserInList represents a user in the list response

type UserInfoRef

type UserInfoRef struct {
	ID       string `json:"id"`
	Username string `json:"username"`
	Role     string `json:"role"`
}

UserInfoRef represents user information returned in login response

type UserManagementHandler

type UserManagementHandler struct {
	// contains filtered or unexported fields
}

UserManagementHandler handles user management HTTP requests

func NewUserManagementHandler

func NewUserManagementHandler(
	userService *user.UserManagementService,
	adminCreateService *user.AdminCreateUserService,
	userRepo repository.UserRepo,
	softDeleteRepo repository.SoftDeleteRepo,
	jwtManager *auth.JWTManager,
	emailService email.EmailService,
	logger *util.Logger,
	profilePictureURLBuilder func(string) string,
) *UserManagementHandler

NewUserManagementHandler creates a new user management handler

func (*UserManagementHandler) ApproveUser

func (h *UserManagementHandler) ApproveUser(w http.ResponseWriter, r *http.Request)

ApproveUser handles POST /api/admin/users/:id/approve

func (*UserManagementHandler) CreateUser

func (h *UserManagementHandler) CreateUser(w http.ResponseWriter, r *http.Request)

CreateUser handles POST /api/admin/users

func (*UserManagementHandler) GetAllUsers

func (h *UserManagementHandler) GetAllUsers(w http.ResponseWriter, r *http.Request)

GetAllUsers handles GET /api/admin/users

func (*UserManagementHandler) GetPendingUsers

func (h *UserManagementHandler) GetPendingUsers(w http.ResponseWriter, r *http.Request)

GetPendingUsers handles GET /api/admin/pending-users

func (*UserManagementHandler) GetSoftDeletedContent

func (h *UserManagementHandler) GetSoftDeletedContent(w http.ResponseWriter, r *http.Request)

GetSoftDeletedContent handles GET /api/admin/users/:id/deleted-content

func (*UserManagementHandler) MarkUserAsSpam

func (h *UserManagementHandler) MarkUserAsSpam(w http.ResponseWriter, r *http.Request)

MarkUserAsSpam handles POST /api/admin/users/:id/mark-spam

func (*UserManagementHandler) RejectUser

func (h *UserManagementHandler) RejectUser(w http.ResponseWriter, r *http.Request)

RejectUser handles POST /api/admin/users/:id/reject

func (*UserManagementHandler) RestoreContent

func (h *UserManagementHandler) RestoreContent(w http.ResponseWriter, r *http.Request)

RestoreContent handles POST /api/admin/content/:id/restore

func (*UserManagementHandler) SoftDeleteUser

func (h *UserManagementHandler) SoftDeleteUser(w http.ResponseWriter, r *http.Request)

SoftDeleteUser handles POST /api/admin/users/:id/soft-delete

func (*UserManagementHandler) SuspendUser

func (h *UserManagementHandler) SuspendUser(w http.ResponseWriter, r *http.Request)

SuspendUser handles POST /api/admin/users/:id/suspend

func (*UserManagementHandler) UnsuspendUser

func (h *UserManagementHandler) UnsuspendUser(w http.ResponseWriter, r *http.Request)

UnsuspendUser handles POST /api/admin/users/:id/unsuspend

func (*UserManagementHandler) UpdateUser

func (h *UserManagementHandler) UpdateUser(w http.ResponseWriter, r *http.Request)

UpdateUser handles PUT /api/admin/users/:id

type UsersMeta

type UsersMeta struct {
	Count     int    `json:"count"`
	Total     int    `json:"total"`
	Limit     int    `json:"limit"`
	Offset    int    `json:"offset"`
	Timestamp string `json:"timestamp"`
}

UsersMeta represents metadata for users list

type VerifyEmailResponse

type VerifyEmailResponse struct {
	Message  string `json:"message"`
	Redirect string `json:"redirect"`
}

VerifyEmailResponse represents the successful email verification response

type VerifyEmailUpdateData

type VerifyEmailUpdateData struct {
	Message string `json:"message"`
	Email   string `json:"email"`
}

VerifyEmailUpdateData represents email verification data in the response

type VerifyEmailUpdateResponse

type VerifyEmailUpdateResponse struct {
	Data *VerifyEmailUpdateData `json:"data"`
	Meta *ProfileResponseMeta   `json:"meta"`
}

VerifyEmailUpdateResponse represents the response for email verification

type WordPressHandler

type WordPressHandler struct {
	// contains filtered or unexported fields
}

WordPressHandler exposes the WordPress import endpoint to administrators.

func NewWordPressHandler

func NewWordPressHandler(
	importer *wordpress.Importer,
	logger *util.Logger,
	maxImportBytes int64,
	importTimeout time.Duration,
) *WordPressHandler

NewWordPressHandler creates a WordPressHandler. maxImportBytes is the total upload ceiling (from IMPORT_MAX_SIZE_MB) applied via MaxBytesReader.

func (*WordPressHandler) Import

func (h *WordPressHandler) Import(w http.ResponseWriter, r *http.Request)

Import accepts a WordPress WXR XML file upload and starts an asynchronous import job. Returns 202 Accepted with a job ID immediately. The caller can poll GET /api/admin/wordpress/import/status/{jobId} for progress.

func (*WordPressHandler) ImportStatus added in v0.7.0

func (h *WordPressHandler) ImportStatus(w http.ResponseWriter, r *http.Request)

ImportStatus returns the current state of an import job. GET /api/admin/wordpress/import/status/{jobId} — specific job GET /api/admin/wordpress/import/status — most recent job

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL