214 lines
7.5 KiB
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"
|
|
)
|