Documentation
¶
Index ¶
- type APIKeyHandler
- type APIKeyListItem
- type APIKeyService
- type ApproveUserResponse
- type AuthHandler
- func (h *AuthHandler) ForgotPassword(w http.ResponseWriter, r *http.Request)
- func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request)
- func (h *AuthHandler) RegisterUser(w http.ResponseWriter, r *http.Request)
- func (h *AuthHandler) ResendVerificationEmail(w http.ResponseWriter, r *http.Request)
- func (h *AuthHandler) ResetPassword(w http.ResponseWriter, r *http.Request)
- func (h *AuthHandler) VerifyEmail(w http.ResponseWriter, r *http.Request)
- type CommentHandler
- func (h *CommentHandler) CreateComment(w http.ResponseWriter, r *http.Request)
- func (h *CommentHandler) DeleteComment(w http.ResponseWriter, r *http.Request)
- func (h *CommentHandler) DeleteOwnComment(w http.ResponseWriter, r *http.Request)
- func (h *CommentHandler) GetComments(w http.ResponseWriter, r *http.Request)
- func (h *CommentHandler) GetCommentsForModeration(w http.ResponseWriter, r *http.Request)
- func (h *CommentHandler) GetMyComments(w http.ResponseWriter, r *http.Request)
- func (h *CommentHandler) GetPendingComments(w http.ResponseWriter, r *http.Request)
- func (h *CommentHandler) UpdateCommentStatus(w http.ResponseWriter, r *http.Request)
- type CommentResponse
- type CompleteSetupRequest
- type CompleteSetupResponse
- type ContentHandler
- func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) DeleteContent(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) GenerateSlug(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) GetContent(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) GetPublishedAuthor(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) GetPublishedContent(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) GetPublishedContentByAuthor(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) GetSEO(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) ListContents(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) ListPublishedArchive(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) ListPublishedAuthors(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) ListPublishedContents(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) SearchPublished(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) SetSystemFields(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request)
- func (h *ContentHandler) WithPublicFieldRegistry(registry PublicFieldLookup) *ContentHandler
- type ContentServiceInterface
- type CreateAPIKeyRequest
- type CreateAPIKeyResponse
- type CreateCommentRequest
- type CreateContentData
- type CreateContentRequest
- type CreateContentResponse
- type CreateUserRequest
- type CreateUserResponse
- type DashboardHandler
- type DashboardServiceInterface
- type DataExportMeta
- type DeleteAccountRequest
- type DeletedContentItem
- type EmailUpdateData
- type EmailUpdateRequest
- type EmailUpdateResponse
- type FirstLoginHandler
- type FirstLoginStatus
- type ForgotPasswordRequest
- type GenerateSlugData
- type GenerateSlugRequest
- type GenerateSlugResponse
- type GetAllUsersResponse
- type GetPendingUsersResponse
- type GetSoftDeletedContentResponse
- type LoginRequest
- type LoginResponse
- type MarkUserAsSpamResponse
- type MediaHandler
- func (h *MediaHandler) DeleteMedia(w http.ResponseWriter, r *http.Request)
- func (h *MediaHandler) GenerateImage(w http.ResponseWriter, r *http.Request)
- func (h *MediaHandler) GetMedia(w http.ResponseWriter, r *http.Request)
- func (h *MediaHandler) GetMediaByID(w http.ResponseWriter, r *http.Request)
- func (h *MediaHandler) Upload(w http.ResponseWriter, r *http.Request)
- type MediaLister
- type MediaServiceInterface
- type NotificationHandler
- type NotificationRef
- type NotificationsResponse
- type PasswordUpdateData
- type PasswordUpdateRequest
- type PasswordUpdateResponse
- type PendingCommentResponse
- type PendingUser
- type PostTypeHandler
- type PostTypeServiceInterface
- type ProfileData
- type ProfileHandler
- func (h *ProfileHandler) ChangePassword(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) DeleteAccount(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) ExportUserData(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) GetProfile(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) GetUserFields(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) UpdateCustomFields(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) UpdateEmail(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) UpdateName(w http.ResponseWriter, r *http.Request)
- func (h *ProfileHandler) VerifyEmailUpdate(w http.ResponseWriter, r *http.Request)
- type ProfileInfo
- type ProfilePictureHandler
- func (h *ProfilePictureHandler) AdminDeleteUserPicture(w http.ResponseWriter, r *http.Request)
- func (h *ProfilePictureHandler) AdminUploadUserPicture(w http.ResponseWriter, r *http.Request)
- func (h *ProfilePictureHandler) DeleteProfilePicture(w http.ResponseWriter, r *http.Request)
- func (h *ProfilePictureHandler) UploadProfilePicture(w http.ResponseWriter, r *http.Request)
- type ProfileResponse
- type ProfileResponseMeta
- type PublicArchiveMonthResponse
- type PublicAuthorResponse
- type PublicFieldLookup
- type RegisterUserRequest
- type RegisterUserResponse
- type RejectUserResponse
- type ResendVerificationRequest
- type ResendVerificationResponse
- type ResetPasswordRequest
- type ResponseMeta
- type RestoreContentResponse
- type RestoredContent
- type RevokeAPIKeyResponse
- type SEOHandler
- type SearchResult
- type SoftDeleteContentRequest
- type SoftDeleteUserResponse
- type SuspendUserResponse
- type TextGenHandler
- type TextGenerationService
- type UnsuspendUserResponse
- type UpdateCommentStatusRequest
- type UpdateUserProfileRequest
- type UpdateUserProfileResponse
- type UserDetail
- type UserInList
- type UserInfoRef
- type UserManagementHandler
- func (h *UserManagementHandler) ApproveUser(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) CreateUser(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) GetAllUsers(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) GetPendingUsers(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) GetSoftDeletedContent(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) MarkUserAsSpam(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) RejectUser(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) RestoreContent(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) SoftDeleteUser(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) SuspendUser(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) UnsuspendUser(w http.ResponseWriter, r *http.Request)
- func (h *UserManagementHandler) UpdateUser(w http.ResponseWriter, r *http.Request)
- type UsersMeta
- type VerifyEmailResponse
- type VerifyEmailUpdateData
- type VerifyEmailUpdateResponse
- type WordPressHandler
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 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 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)
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 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 ¶
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 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 LoginRequest ¶
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 ¶
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)
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)
GetAll(ctx context.Context, limit int, offset int) ([]*media.Media, error)
Delete(ctx context.Context, id int, userID int, userRole string) error
SearchMedia(ctx context.Context, search string, dateFilter string, limit int, offset int) ([]*media.Media, 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 ¶
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 ¶
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 ¶
RestoredContent represents restored content details
type RevokeAPIKeyResponse ¶
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 SearchResult ¶
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"`
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 ¶
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