go-quasar-partial-ssr/backend/internal/user/model.go

191 lines
7.4 KiB
Go

package users
import (
"server/internal/auth"
"time"
"gorm.io/gorm"
)
type User struct {
ID int `gorm:"primaryKey"`
Email string `json:"email" gorm:"uniqueIndex;size:255"`
Name string `json:"name" gorm:"size:255"`
Password string `json:"-" gorm:"size:255"`
Permission auth.Permission `json:"permission"`
Types UserTypes `json:"types" gorm:"type:text;serializer:json"`
Status UserStatus `json:"status" gorm:"type:text;default:'pending'"`
ActivatedAt *time.Time `json:"activatedAt" ts:"type=Nullable<Date>"`
UUID string `json:"uuid" gorm:"size:36"`
Details *UserDetails `json:"details" gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
Preferences *UserPreferences `json:"preferences" gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
Avatar *string `json:"avatar" gorm:"size:512"`
CreatedAt *time.Time `json:"createdAt,omitempty" ts:"type=Date"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" ts:"type=Date"`
DeletedAt *gorm.DeletedAt `json:"-" gorm:"index" `
}
// UserTypes is stored as JSON array (e.g. ["internal","external"]).
type UserTypes []string
// UserProfile is the safe full representation of a user returned by CRUD endpoints.
type UserProfile struct {
ID int `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Permission auth.Permission `json:"permission"`
Types UserTypes `json:"types"`
Status UserStatus `json:"status"`
ActivatedAt *time.Time `json:"activatedAt" ts:"type=Nullable<Date>"`
UUID string `json:"uuid"`
Details *UserDetails `json:"details"`
Preferences *UserPreferences `json:"preferences"`
Avatar *string `json:"avatar"`
CreatedAt *time.Time `json:"createdAt,omitempty" ts:"type=Date"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" ts:"type=Date"`
}
// ToUserProfile maps a User to a full response without exposing the password hash.
func ToUserProfile(u *User) UserProfile {
if u == nil {
return UserProfile{}
}
return UserProfile{
ID: u.ID,
Email: u.Email,
Name: u.Name,
Permission: u.Permission,
Types: u.Types,
Status: u.Status,
ActivatedAt: u.ActivatedAt,
UUID: u.UUID,
Details: u.Details,
Preferences: u.Preferences,
Avatar: u.Avatar,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
}
}
// UserPreferences holds per-user settings stored as JSON.
type UserPreferences struct {
ID int `json:"id" gorm:"primaryKey"`
UserID int `json:"userId" gorm:"index"`
UseIdle bool `json:"useIdle"`
IdleTimeout int `json:"idleTimeout"`
UseIdlePassword bool `json:"useIdlePassword"`
IdlePin string `json:"idlePin"`
UseDirectLogin bool `json:"useDirectLogin"`
UseQuadcodeLogin bool `json:"useQuadcodeLogin"`
SendNoticesMail bool `json:"sendNoticesMail"`
Language string `json:"language"`
CreatedAt *time.Time `json:"createdAt,omitempty" ts:"type=Date"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" ts:"type=Date"`
}
// UserDetails holds optional profile data.
type UserDetails struct {
ID int `json:"id" gorm:"primaryKey"`
UserID int `json:"userId" gorm:"index"`
Title string `json:"title"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Address string `json:"address"`
City string `json:"city"`
ZipCode string `json:"zipCode"`
Country string `json:"country"`
Phone string `json:"phone"`
CreatedAt *time.Time `json:"createdAt,omitempty" ts:"type=Date"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" ts:"type=Date"`
}
// UserDetails holds optional profile data.
// Session tracks logins with browser metadata.
type Session struct {
ID int `json:"id" gorm:"primaryKey"`
UserID *int `json:"userId" gorm:"index"`
Username string `json:"username" gorm:"size:255"`
AccessTokenHash string `json:"-" gorm:"size:128;index"`
RefreshTokenHash string `json:"-" gorm:"size:128;index"`
ExpiresAt time.Time `json:"expiresAt" ts:"type=Nullable<Date>" gorm:"index"`
IPAddress string `json:"ipAddress" gorm:"size:64"`
UserAgent string `json:"userAgent" gorm:"size:512"`
CreatedAt time.Time `json:"createdAt,omitempty" ts:"type=Date"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" ts:"type=Date"`
DeletedAt *gorm.DeletedAt `json:"-" gorm:"index" `
}
type PasswordResetToken struct {
ID int `json:"id" gorm:"primaryKey"`
UserID int `json:"userId" gorm:"index"`
TokenHash string `json:"-" gorm:"size:64;uniqueIndex"`
ExpiresAt time.Time `json:"expiresAt,omitempty" ts:"type=Date" gorm:"index"`
UsedAt *time.Time `json:"usedAt,omitempty" ts:"type=Date"`
CreatedAt *time.Time `json:"createdAt" ts:"type=Date"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" ts:"type=Date"`
DeletedAt *gorm.DeletedAt `json:"-" gorm:"index"`
}
// UserStatus represents lifecycle state of a user.
type UserStatus string
// Typescript: enum=UserStatus
const (
UserStatusPending UserStatus = "pending"
UserStatusActive UserStatus = "active"
UserStatusDisabled UserStatus = "disabled"
)
type LoginRequest struct {
Username string `json:"username" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
}
type RefreshRequest struct {
RefreshToken string `json:"refresh_token"`
}
type ForgotPasswordRequest struct {
Email string `json:"email" validate:"required,email"`
}
type ResetPasswordRequest struct {
Token string `json:"token" validate:"required,min=20,max=255"`
Password string `json:"password" validate:"required,min=8,max=128"`
}
type UpdatePasswordRequest struct {
Password string `json:"password" validate:"required,min=8,max=128"`
}
type UpdateUserRequest struct {
UUID string `json:"uuid" validate:"required,uuid4"`
Name string `json:"name" validate:"required,min=1,max=255"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"omitempty,min=8,max=128"`
Permission auth.Permission `json:"permission"`
Status UserStatus `json:"status"`
Types UserTypes `json:"types"`
Avatar *string `json:"avatar,omitempty"`
Details *UserDetails `json:"details,omitempty"`
Preferences *UserPreferences `json:"preferences,omitempty"`
}
// UserCreateRequest captures the minimal payload to create a user.
type UserCreateRequest struct {
Name string `json:"name" validate:"required,min=1,max=255"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
Permission auth.Permission `json:"permission"`
Status UserStatus `json:"status"`
Types UserTypes `json:"types"`
Avatar *string `json:"avatar,omitempty"`
Details *UserDetails `json:"details,omitempty"`
Preferences *UserPreferences `json:"preferences,omitempty"`
}