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

214 lines
7.5 KiB
Go

package models
import (
"time"
"gorm.io/gorm"
)
// UserRoles is stored as JSON array of strings.
// Typescript: type
type UserRoles []string
// Typescript: type
type UsersShort []UserShort
type User struct {
ID int `json:"id" gorm:"primaryKey"`
Email string `json:"email" gorm:"uniqueIndex;size:255"`
Name string `json:"name" gorm:"size:255"`
Password string `json:"password" gorm:"size:255"`
Roles UserRoles `json:"roles" gorm:"type:text;serializer:json"`
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=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" ts:"type=Date"`
UpdatedAt time.Time `json:"updatedAt" ts:"type=Date"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index" ts:"type=Date"`
}
// UserCreateInput captures the minimal payload to create a user.
// Typescript: interface
type UserCreateInput 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"`
Roles UserRoles `json:"roles"`
Status UserStatus `json:"status"`
Types UserTypes `json:"types"`
Avatar *string `json:"avatar"`
Details *UserDetailsShort `json:"details" `
Preferences *UserPreferencesShort `json:"preferences" `
}
// UserTypes is stored as JSON array (e.g. ["internal","external"]).
type UserTypes []string
// UserShort is a lightweight representation of User without sensitive data.
// Typescript: interface
type UserShort struct {
Email string `json:"email" `
Name string `json:"name" `
Roles UserRoles `json:"roles" `
Status UserStatus `json:"status" `
UUID string `json:"uuid" `
Details *UserDetailsShort `json:"details" `
Preferences *UserPreferencesShort `json:"preferences" `
Avatar *string `json:"avatar" `
}
// ToUserShort maps a User to the lightweight view.
func ToUserShort(u *User) UserShort {
if u == nil {
return UserShort{}
}
return UserShort{
Email: u.Email,
Name: u.Name,
Roles: u.Roles,
Status: u.Status,
UUID: u.UUID,
Details: ToUserDetailsShort(u.Details),
Preferences: ToUserPreferencesShort(u.Preferences),
Avatar: u.Avatar,
}
}
// ToUserDetailsShort maps UserDetails to the short version.
func ToUserDetailsShort(d *UserDetails) *UserDetailsShort {
if d == nil {
return nil
}
return &UserDetailsShort{
Title: d.Title,
FirstName: d.FirstName,
LastName: d.LastName,
Address: d.Address,
City: d.City,
ZipCode: d.ZipCode,
Country: d.Country,
Phone: d.Phone,
}
}
// ToUserPreferencesShort maps UserPreferences to the short version.
func ToUserPreferencesShort(p *UserPreferences) *UserPreferencesShort {
if p == nil {
return nil
}
return &UserPreferencesShort{
UseIdle: p.UseIdle,
IdleTimeout: p.IdleTimeout,
UseIdlePassword: p.UseIdlePassword,
IdlePin: p.IdlePin,
UseDirectLogin: p.UseDirectLogin,
UseQuadcodeLogin: p.UseQuadcodeLogin,
SendNoticesMail: p.SendNoticesMail,
Language: p.Language,
}
}
// 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" ts:"type=Date"`
UpdatedAt time.Time `json:"updatedAt" ts:"type=Date"`
}
// UserPreferences holds per-user settings stored as JSON.
// Typescript: interface
type UserPreferencesShort struct {
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"`
}
// 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" ts:"type=Date"`
UpdatedAt time.Time `json:"updatedAt" ts:"type=Date"`
}
// UserDetails holds optional profile data.
// Typescript: interface
type UserDetailsShort struct {
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"`
}
// 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=Date" gorm:"index"`
IPAddress string `json:"ipAddress" gorm:"size:64"`
UserAgent string `json:"userAgent" gorm:"size:512"`
CreatedAt time.Time `json:"createdAt" ts:"type=Date"`
UpdatedAt time.Time `json:"updatedAt" 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" ts:"type=Date" gorm:"index"`
UsedAt *time.Time `json:"usedAt" ts:"type=Date"`
CreatedAt time.Time `json:"createdAt" ts:"type=Date"`
UpdatedAt time.Time `json:"updatedAt" 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"
)