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

208 lines
7.5 KiB
Go

package users
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// BeforeCreate will set a UUID rather than numeric ID.
func (base *User) BeforeCreate(tx *gorm.DB) error {
if base.ID == "" {
id, err := uuid.NewRandom()
if err != nil {
return err
}
base.ID = id.String()
}
return nil
}
type User struct {
ID string `json:"id" gorm:"type:uuid;primary_key;"`
Email string `json:"email" gorm:"uniqueIndex;size:255"`
Name string `json:"name" gorm:"size:255"`
Password string `json:"-" gorm:"size:255"`
Permission string `json:"permission"`
Type UserType `json:"type"`
Status UserStatus `json:"status" gorm:"type:text;default:'pending'"`
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"`
ActivatedAt *time.Time `json:"activatedAt" ts:"type=Nullable<Date>"`
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 UpdateUserProfileRequest struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Permission string `json:"permission"`
Type UserType `json:"type"`
Status UserStatus `json:"status"`
}
type UpdateUserAvatarRequest struct {
ID string `json:"id" validate:"required,uuid4"`
Img []byte `json:"img"`
}
// UserPreferences holds per-user settings stored as JSON.
type UserPreferences struct {
ID int `json:"id" gorm:"primaryKey"`
UserID string `json:"userId" gorm:"type:uuid;column:user_foreign_key;not null;"`
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"`
}
type UpdateUserPreferencesRequest struct {
ID int `json:"id"`
UserID string `json:"userId"`
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 string `json:"userId" gorm:"type:uuid;column:user_foreign_key;not null;"`
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"`
}
type UpdateUserDetailsRequest struct {
ID int `json:"id"`
UserID string `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"`
}
// UserDetails holds optional profile data.
// Session tracks logins with browser metadata.
type Session struct {
ID int `gorm:"primaryKey"`
UserID *string `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 `gorm:"primaryKey"`
UserID string `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"
)
// UserTypes represents different types of a user.
type UserType string
// Typescript: enum=UserTypes
const (
UserTypeInternal UserType = "internal"
UserTypeExternal UserType = "external"
UserTypeSurveyor UserType = "surveyor"
)
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 {
ID string `json:"id" validate:"required,uuid4"`
Password string `json:"password" validate:"required,min=8,max=128"`
}
type UpdateUserRequest struct {
ID string `json:"id" 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 string `json:"permission"`
Status UserStatus `json:"status"`
Type UserType `json:"type"`
}
// 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 string `json:"permission"`
Status UserStatus `json:"status"`
Type UserType `json:"type"`
Avatar *string `json:"avatar,omitempty"`
Details *UserDetails `json:"details,omitempty"`
Preferences *UserPreferences `json:"preferences,omitempty"`
}