Migrate GORM to generics API, simplify user-domain relationship, refactor models
This commit is contained in:
parent
19ce2224b8
commit
560b40503a
9 changed files with 192 additions and 117 deletions
|
|
@ -80,8 +80,10 @@ type ImcUser struct {
|
|||
Username string `gorm:"uniqueIndex;size:100;not null" json:"username"` // Login username
|
||||
PasswordHash string `gorm:"size:255;not null" json:"-"` // Bcrypt hash of password (- means exclude from JSON)
|
||||
Role string `gorm:"type:enum('admin','user');default:'user'" json:"role"` // Role: admin or regular user
|
||||
DomainID uint `gorm:"not null" json:"domainId"` // Foreign key to VirtualDomain (primary domain this user manages)
|
||||
Domain *VirtualDomain `gorm:"foreignKey:DomainID" json:"domain,omitempty"` // Associated domain
|
||||
CreatedAt time.Time `json:"createdAt"` // When account was created
|
||||
Domains []ImcUserDomain `gorm:"foreignKey:UserID" json:"domains,omitempty"` // Domains this user can access
|
||||
Domains []ImcUserDomain `gorm:"foreignKey:UserID" json:"domains,omitempty"` // Additional domains this user can access (many-to-many)
|
||||
}
|
||||
|
||||
// TableName specifies the database table name for ImcUser.
|
||||
|
|
@ -104,7 +106,7 @@ func (ImcUserDomain) TableName() string { return "imc_users2domains" }
|
|||
// Used to track failed login attempts and implement rate limiting.
|
||||
type ImcLoginAttempt struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"` // Primary key
|
||||
Email string `gorm:"size:100;not null" json:"email"` // Email/username that was used
|
||||
Username string `gorm:"size:100;not null" json:"username"` // Username that was used
|
||||
IPAddress string `gorm:"size:45;not null" json:"ipAddress"` // IP address of the requester (IPv6 compatible)
|
||||
AttemptedAt time.Time `json:"attemptedAt"` // When the attempt occurred
|
||||
Successful bool `gorm:"default:false" json:"successful"` // Whether the login succeeded
|
||||
|
|
@ -132,12 +134,6 @@ type AliasWithDomain struct {
|
|||
DomainName string `json:"domainName"` // Denormalized domain name for convenience
|
||||
}
|
||||
|
||||
// UserWithDomain combines a user with their domain name for API responses.
|
||||
type UserWithDomain struct {
|
||||
VirtualUser // Embed VirtualUser struct
|
||||
DomainName string `json:"domainName"` // Denormalized domain name for convenience
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Database Connection
|
||||
// =============================================================================
|
||||
|
|
@ -196,15 +192,18 @@ func Connect(cfg *config.Config) (*DB, error) {
|
|||
func (d *DB) InitSchema() error {
|
||||
// Create imc_users table for admin accounts.
|
||||
// This table stores admin users who can log into the web interface.
|
||||
// Each user is associated with one domain they can manage.
|
||||
imcUsersSQL := `
|
||||
CREATE TABLE IF NOT EXISTS imc_users (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
username VARCHAR(100) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
role ENUM('admin','user') DEFAULT 'user',
|
||||
domain_id INT UNSIGNED NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_username (username),
|
||||
INDEX idx_role (role)
|
||||
INDEX idx_role (role),
|
||||
INDEX idx_domain_id (domain_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`
|
||||
if err := d.Exec(imcUsersSQL).Error; err != nil {
|
||||
|
|
@ -216,11 +215,11 @@ func (d *DB) InitSchema() error {
|
|||
loginAttemptsSQL := `
|
||||
CREATE TABLE IF NOT EXISTS imc_login_attempts (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
email VARCHAR(100) NOT NULL,
|
||||
username VARCHAR(100) NOT NULL,
|
||||
ip_address VARCHAR(45) NOT NULL,
|
||||
attempted_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
successful BOOLEAN DEFAULT FALSE,
|
||||
INDEX idx_email_time (email, attempted_at),
|
||||
INDEX idx_username_time (username, attempted_at),
|
||||
INDEX idx_ip_time (ip_address, attempted_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`
|
||||
|
|
@ -228,8 +227,8 @@ func (d *DB) InitSchema() error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Create imc_users2domains table for user-domain permissions.
|
||||
// This implements many-to-many: a user can access multiple domains.
|
||||
// Create imc_users2domains table for additional user-domain permissions (many-to-many).
|
||||
// A user can have access to multiple domains beyond their primary domain.
|
||||
users2DomainsSQL := `
|
||||
CREATE TABLE IF NOT EXISTS imc_users2domains (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue