208 lines
7.5 KiB
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"`
|
|
}
|