user

package
v2.8.1 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: BSD-3-Clause Imports: 26 Imported by: 0

Documentation

Overview

Package user owns user persistence, password hashing, authorization guards, and the user HTTP surface.

Index

Constants

View Source
const (
	ErrCannotRemoveLastAdmin = errors.Sentinel("cannot remove the last admin user")

	// 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.Sentinel("insufficient privilege to modify this user")
)

Variables

This section is empty.

Functions

func NormalizeOptionalEmail

func NormalizeOptionalEmail(email *string) (*string, error)

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 usertypes.CreateUser
}

type CreateUserOutput

type CreateUserOutput struct {
	Body base.ApiResponse[usertypes.User]
}

type DeleteUserInput

type DeleteUserInput struct {
	UserID string `path:"userId" doc:"User ID"`
}

type DeleteUserOutput

type DeleteUserOutput struct {
	Body base.ApiResponse[base.MessageResponse]
}

type Dependencies

type Dependencies struct {
	Service                  *UserService
	InvalidateUserTokenCache func(string)
	Settings                 *settings.SettingsService
}

type GetUserAvatarInput

type GetUserAvatarInput struct {
	UserID string `path:"userId" doc:"User ID"`
}

type GetUserAvatarOutput

type GetUserAvatarOutput struct {
	ContentType         string `header:"Content-Type"`
	CacheControl        string `header:"Cache-Control"`
	XContentTypeOptions string `header:"X-Content-Type-Options"`
	Body                []byte
}

type GetUserInput

type GetUserInput struct {
	UserID string `path:"userId" doc:"User ID"`
}

type GetUserOutput

type GetUserOutput struct {
	Body base.ApiResponse[usertypes.User]
}

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 ListUsersOutput

type ListUsersOutput struct {
	Body base.Paginated[usertypes.User]
}

type Module

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

func New

func New(deps Dependencies) *Module

func (*Module) RegisterRoutes

func (m *Module) RegisterRoutes(api huma.API)

func (*Module) Service

func (m *Module) Service() *UserService

type UpdateUserInput

type UpdateUserInput struct {
	UserID string `path:"userId" doc:"User ID"`
	Body   usertypes.UpdateUser
}

type UpdateUserOutput

type UpdateUserOutput struct {
	Body base.ApiResponse[usertypes.User]
}

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) (*CreateUserOutput, error)

CreateUser creates a new usertypes.

func (*UserHandler) DeleteUser

func (h *UserHandler) DeleteUser(ctx context.Context, input *DeleteUserInput) (*DeleteUserOutput, error)

DeleteUser deletes a usertypes.

func (*UserHandler) GetUser

func (h *UserHandler) GetUser(ctx context.Context, input *GetUserInput) (*GetUserOutput, 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) (*ListUsersOutput, error)

ListUsers returns a paginated list of users.

func (*UserHandler) UpdateUser

func (h *UserHandler) UpdateUser(ctx context.Context, input *UpdateUserInput) (*UpdateUserOutput, error)

UpdateUser updates a usertypes.

type UserService

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

func NewUserService

func NewUserService(db *database.DB) *UserService

func (*UserService) AttachOidcSubjectTransactional

func (s *UserService) AttachOidcSubjectTransactional(ctx context.Context, userID string, subject string, updateFn func(u *common.User)) (*common.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 (s *UserService) CreateUser(ctx context.Context, user *common.User) (*common.User, error)

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

func (s *UserService) GetAvatar(ctx context.Context, userID string) ([]byte, string, error)

GetAvatar returns the raw avatar data and MIME type for a user. Returns (nil, "", nil) when the user has no custom avatar.

func (*UserService) GetUser

func (s *UserService) GetUser(ctx context.Context, userID string) (*common.User, error)

func (*UserService) GetUserByEmail

func (s *UserService) GetUserByEmail(ctx context.Context, email string) (*common.User, error)

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 (s *UserService) GetUserByID(ctx context.Context, id string) (*common.User, error)

func (*UserService) GetUserByOidcSubjectId

func (s *UserService) GetUserByOidcSubjectId(ctx context.Context, subjectId string) (*common.User, error)

func (*UserService) GetUserByUsername

func (s *UserService) GetUserByUsername(ctx context.Context, username string) (*common.User, error)

func (*UserService) HashPassword

func (s *UserService) HashPassword(password string) (string, error)

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, user *common.User, password string) (*common.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, user *common.User, password, exceptSessionID string) (*common.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 (s *UserService) ToUserResponseDto(ctx context.Context, u common.User) (user.User, error)

func (*UserService) UpdateUser

func (s *UserService) UpdateUser(ctx context.Context, user *common.User, actorPerms *authz.PermissionSet) (*common.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(encodedHash, password string) error

func (*UserService) WithRoleService

func (s *UserService) WithRoleService(roleService *role.RoleService) *UserService

WithRoleService wires the role.RoleService dependency. Separated from the constructor so the bootstrap can construct UserService first (role.RoleService itself has no UserService dependency).

Jump to

Keyboard shortcuts

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