Documentation
¶
Overview ¶
Package user owns user persistence, password hashing, authorization guards, and the user HTTP surface.
Index ¶
- Variables
- func NormalizeOptionalEmail(email *string) (*string, error)
- func RegisterUsers(api huma.API, userService *UserService, invalidateUserTokenCache func(string), ...)
- type Argon2Params
- type CreateUserInput
- type DeleteUserInput
- type GetUserAvatarInput
- type GetUserAvatarOutput
- type GetUserInput
- type ListUsersInput
- type Module
- type UpdateUserInput
- type User
- type UserAvatar
- type UserHandler
- func (h *UserHandler) CreateUser(ctx context.Context, input *CreateUserInput) (*handlerutil.Out[user.User], error)
- func (h *UserHandler) DeleteUser(ctx context.Context, input *DeleteUserInput) (*handlerutil.Out[base.MessageResponse], error)
- func (h *UserHandler) GetUser(ctx context.Context, input *GetUserInput) (*handlerutil.Out[user.User], error)
- func (h *UserHandler) GetUserAvatar(ctx context.Context, input *GetUserAvatarInput) (*GetUserAvatarOutput, error)
- func (h *UserHandler) ListUsers(ctx context.Context, input *ListUsersInput) (*handlerutil.Page[user.User], error)
- func (h *UserHandler) UpdateUser(ctx context.Context, input *UpdateUserInput) (*handlerutil.Out[user.User], error)
- type UserService
- func (s *UserService) AttachOidcSubjectTransactional(ctx context.Context, userID, subject string, updateFn func(u *User)) (*User, error)
- func (s *UserService) CreateDefaultAdmin(ctx context.Context) error
- func (s *UserService) CreateUser(ctx context.Context, localUser *User) (*User, error)
- func (s *UserService) DeleteAvatar(ctx context.Context, userID string) error
- func (s *UserService) DeleteUser(ctx context.Context, id string, actorPerms *authz.PermissionSet) error
- func (s *UserService) GetAvatar(ctx context.Context, userID string) ([]byte, string, error)
- func (s *UserService) GetUser(ctx context.Context, userID string) (*User, error)
- func (s *UserService) GetUserByEmail(ctx context.Context, email string) (*User, error)
- func (s *UserService) GetUserByID(ctx context.Context, id string) (*User, error)
- func (s *UserService) GetUserByOidcSubjectId(ctx context.Context, subjectId string) (*User, error)
- func (s *UserService) GetUserByUsername(ctx context.Context, username string) (*User, error)
- func (s *UserService) HashPassword(ctx context.Context, password string) (string, error)
- func (s *UserService) ListUsersPaginated(ctx context.Context, params pagination.QueryParams) ([]user.User, pagination.Response, error)
- func (s *UserService) ResolveUserPermissions(ctx context.Context, userID string) (*authz.PermissionSet, error)
- func (s *UserService) SetPassword(ctx context.Context, localUser *User, password string) (*User, error)
- func (s *UserService) SetPasswordAndRevokeSessionsExcept(ctx context.Context, localUser *User, password, exceptSessionID string, ...) (*User, error)
- func (s *UserService) ToUserResponseDto(ctx context.Context, u User) (user.User, error)
- func (s *UserService) TouchLastLogin(ctx context.Context, userID string, at time.Time) error
- func (s *UserService) UpdateUser(ctx context.Context, localUser *User, actorPerms *authz.PermissionSet) (*User, error)
- func (s *UserService) UploadAvatar(ctx context.Context, userID string, data []byte, mimeType string) error
- func (s *UserService) ValidatePassword(ctx context.Context, encodedHash, password string) error
Constants ¶
This section is empty.
Variables ¶
var ( ErrCannotRemoveLastAdmin = errors.New("cannot remove the last admin user") ErrUsernameRequired = errors.New("username is required") ErrUsernameTaken = errors.New("username already in use") ErrEmailTaken = common.Classify(common.ErrConflict, errors.New("email already in use")) // ErrInsufficientPrivilege is returned when a caller attempts to modify a // target whose effective privilege is equal to or higher than the caller's // (e.g. a delegated users:update holder trying to edit a global admin). ErrInsufficientPrivilege = errors.New("insufficient privilege to modify this user") )
Functions ¶
func NormalizeOptionalEmail ¶
func RegisterUsers ¶
func RegisterUsers(api huma.API, userService *UserService, invalidateUserTokenCache func(string), settingsService *settings.SettingsService)
RegisterUsers registers all user management endpoints.
Types ¶
type Argon2Params ¶
type Argon2Params struct {
// contains filtered or unexported fields
}
func DefaultArgon2Params ¶
func DefaultArgon2Params() *Argon2Params
type CreateUserInput ¶
type CreateUserInput struct {
Body user.CreateUser
}
type DeleteUserInput ¶
type DeleteUserInput struct {
UserID string `path:"userId" doc:"User ID"`
}
type GetUserAvatarInput ¶
type GetUserAvatarInput struct {
UserID string `path:"userId" doc:"User ID"`
}
type GetUserAvatarOutput ¶
type GetUserInput ¶
type GetUserInput struct {
UserID string `path:"userId" doc:"User ID"`
}
type ListUsersInput ¶
type ListUsersInput struct {
Search string `query:"search" doc:"Search query"`
Sort string `query:"sort" doc:"Column to sort by"`
Order string `query:"order" default:"asc" doc:"Sort direction"`
Start int `query:"start" default:"0" doc:"Start index"`
Limit int `query:"limit" default:"20" doc:"Items per page"`
}
type Module ¶
type Module struct {
// contains filtered or unexported fields
}
func New ¶
func New(service *UserService, invalidateUserTokenCache func(string), settingsService *settings.SettingsService) *Module
func (*Module) RegisterRoutes ¶
func (*Module) Service ¶
func (m *Module) Service() *UserService
type UpdateUserInput ¶
type UpdateUserInput struct {
UserID string `path:"userId" doc:"User ID"`
Body user.UpdateUser
}
type User ¶ added in v2.15.0
type User struct {
database.BaseModel
Username string `json:"username" sortable:"true"`
PasswordHash string `json:"-" gorm:"column:password_hash"`
DisplayName *string `json:"displayName,omitempty" gorm:"column:display_name" sortable:"true" unorm:"nfc" trim:"true"`
Email *string `json:"email,omitempty" sortable:"true"`
OidcSubjectId *string `json:"oidcSubjectId,omitempty" gorm:"column:oidc_subject_id"`
LastLogin *time.Time `json:"lastLogin,omitempty" gorm:"column:last_login" sortable:"true"`
Locale *string `json:"locale,omitempty" gorm:"column:locale"`
TimeFormat user.TimeFormat `json:"timeFormat" gorm:"column:time_format;not null;default:auto"`
FontSize *int `json:"fontSize,omitempty" gorm:"column:font_size"`
Preferences user.Preferences `json:"preferences" gorm:"column:preferences;serializer:json"`
RequiresPasswordChange bool `json:"requiresPasswordChange" gorm:"column:requires_password_change"`
IsServiceAccount bool `json:"isServiceAccount" gorm:"column:is_service_account;not null;default:false"`
PasskeyMFAEnabled bool `json:"passkeyMfaEnabled" gorm:"column:passkey_mfa_enabled;not null;default:false"`
// Avatar metadata
HasAvatar bool `json:"hasAvatar" gorm:"column:has_avatar;not null;default:false"`
// OIDC provider tokens
OidcAccessToken *string `json:"-" gorm:"type:text"`
OidcRefreshToken *string `json:"-" gorm:"type:text"`
OidcAccessTokenExpiresAt *time.Time `json:"-"`
}
func CurrentUserFromContext ¶ added in v2.15.0
CurrentUserFromContext retrieves the authenticated persistence model.
type UserAvatar ¶ added in v2.8.1
type UserAvatar struct {
UserID string `json:"userId" gorm:"column:user_id;primaryKey"`
Data []byte `json:"-" gorm:"column:data;type:blob;not null"`
MimeType string `json:"mimeType" gorm:"column:mime_type;not null"`
}
UserAvatar represents the raw profile picture data for a user. Stored separately from the main User struct to prevent loading up to 2MB of binary data on every user query.
func (UserAvatar) TableName ¶ added in v2.8.1
func (UserAvatar) TableName() string
type UserHandler ¶
type UserHandler struct {
// contains filtered or unexported fields
}
UserHandler handles user management endpoints.
func (*UserHandler) CreateUser ¶
func (h *UserHandler) CreateUser(ctx context.Context, input *CreateUserInput) (*handlerutil.Out[user.User], error)
CreateUser creates a new usertypes.
func (*UserHandler) DeleteUser ¶
func (h *UserHandler) DeleteUser(ctx context.Context, input *DeleteUserInput) (*handlerutil.Out[base.MessageResponse], error)
DeleteUser deletes a usertypes.
func (*UserHandler) GetUser ¶
func (h *UserHandler) GetUser(ctx context.Context, input *GetUserInput) (*handlerutil.Out[user.User], error)
GetUser returns a user by ID.
func (*UserHandler) GetUserAvatar ¶
func (h *UserHandler) GetUserAvatar(ctx context.Context, input *GetUserAvatarInput) (*GetUserAvatarOutput, error)
GetUserAvatar returns the custom profile picture for a usertypes.
func (*UserHandler) ListUsers ¶
func (h *UserHandler) ListUsers(ctx context.Context, input *ListUsersInput) (*handlerutil.Page[user.User], error)
ListUsers returns a paginated list of users.
func (*UserHandler) UpdateUser ¶
func (h *UserHandler) UpdateUser(ctx context.Context, input *UpdateUserInput) (*handlerutil.Out[user.User], error)
UpdateUser updates a usertypes.
type UserService ¶
type UserService struct {
// contains filtered or unexported fields
}
func NewUserService ¶
func (*UserService) AttachOidcSubjectTransactional ¶
func (s *UserService) AttachOidcSubjectTransactional(ctx context.Context, userID, subject string, updateFn func(u *User)) (*User, error)
AttachOidcSubjectTransactional safely links an OIDC subject to the given user inside a DB transaction. It uses a row lock (FOR UPDATE) to prevent concurrent merges from racing and validates that the user isn't already linked to a different subject. The provided updateFn can mutate the user (e.g., roles, display name, tokens, last login) before persisting.
Note: The clause.Locking{Strength: "UPDATE"} statement is used to acquire a row-level lock. This MUST be done inside a transaction to ensure the lock is held until the update is committed.
func (*UserService) CreateDefaultAdmin ¶
func (s *UserService) CreateDefaultAdmin(ctx context.Context) error
func (*UserService) CreateUser ¶
func (*UserService) DeleteAvatar ¶
func (s *UserService) DeleteAvatar(ctx context.Context, userID string) error
DeleteAvatar removes the avatar for a user.
func (*UserService) DeleteUser ¶
func (s *UserService) DeleteUser(ctx context.Context, id string, actorPerms *authz.PermissionSet) error
DeleteUser removes the user with the given id. actorPerms identifies the caller performing the deletion; authenticated global-admin callers must also be present in ctx. Pass nil for internal service-to-service calls. A non-admin caller may not delete a global admin target.
func (*UserService) GetAvatar ¶
GetAvatar returns the raw avatar data and MIME type for a user. Returns (nil, "", nil) when the user has no custom avatar.
func (*UserService) GetUserByEmail ¶
GetUserByEmail returns the user with the given email. The schema does not enforce email uniqueness, so a lookup matching more than one account returns common.ErrAmbiguousUserEmail instead of arbitrarily selecting one.
func (*UserService) GetUserByID ¶
func (*UserService) GetUserByOidcSubjectId ¶
func (*UserService) GetUserByUsername ¶
func (*UserService) HashPassword ¶
func (*UserService) ListUsersPaginated ¶
func (s *UserService) ListUsersPaginated(ctx context.Context, params pagination.QueryParams) ([]user.User, pagination.Response, error)
func (*UserService) ResolveUserPermissions ¶
func (s *UserService) ResolveUserPermissions(ctx context.Context, userID string) (*authz.PermissionSet, error)
ResolveUserPermissions returns the effective PermissionSet for the given user ID, or nil when no role.RoleService is wired (RBAC disabled paths).
func (*UserService) SetPassword ¶
func (s *UserService) SetPassword(ctx context.Context, localUser *User, password string) (*User, error)
SetPassword hashes and persists a new password for the given user and clears the first-login password-change requirement for trusted internal callers.
func (*UserService) SetPasswordAndRevokeSessionsExcept ¶
func (s *UserService) SetPasswordAndRevokeSessionsExcept(ctx context.Context, localUser *User, password, exceptSessionID string, actorPerms *authz.PermissionSet) (*User, error)
SetPasswordAndRevokeSessionsExcept atomically sets a new password, clears the first-login password-change requirement, and revokes every session for the user except exceptSessionID. Pass an empty exceptSessionID to revoke all sessions. This is for trusted internal callers.
func (*UserService) ToUserResponseDto ¶
func (*UserService) TouchLastLogin ¶ added in v2.16.0
TouchLastLogin updates only the user's last login time.
func (*UserService) UpdateUser ¶
func (s *UserService) UpdateUser(ctx context.Context, localUser *User, actorPerms *authz.PermissionSet) (*User, error)
UpdateUser persists the given user. actorPerms identifies the caller performing the change; authenticated global-admin callers must also be present in ctx. Pass nil for internal service-to-service calls.
func (*UserService) UploadAvatar ¶
func (s *UserService) UploadAvatar(ctx context.Context, userID string, data []byte, mimeType string) error
UploadAvatar stores avatar bytes for a user, replacing any existing avatar.
func (*UserService) ValidatePassword ¶
func (s *UserService) ValidatePassword(ctx context.Context, encodedHash, password string) error