// internal/models/user.go - FIXED VERSION package models import ( "lost-and-found/internal/utils" "time" "gorm.io/gorm" ) // User represents a user in the system type User struct { ID uint `gorm:"primaryKey" json:"id"` Name string `gorm:"type:varchar(100);not null" json:"name"` Email string `gorm:"type:varchar(100);uniqueIndex;not null" json:"email"` Password string `gorm:"type:varchar(255);not null" json:"-"` NRP string `gorm:"type:varchar(20)" json:"nrp"` // ✅ Plain text Phone string `gorm:"type:varchar(20)" json:"phone"` // ✅ Plain text RoleID uint `gorm:"not null;default:3" json:"role_id"` Role Role `gorm:"foreignKey:RoleID" json:"role,omitempty"` Status string `gorm:"type:varchar(20);default:'active'" json:"status"` LastLogin *time.Time `json:"last_login"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` } // TableName specifies the table name func (User) TableName() string { return "users" } // User status constants const ( UserStatusActive = "active" UserStatusBlocked = "blocked" ) // IsActive checks if user is active func (u *User) IsActive() bool { return u.Status == UserStatusActive } // IsBlocked checks if user is blocked func (u *User) IsBlocked() bool { return u.Status == UserStatusBlocked } // IsAdmin checks if user is admin func (u *User) IsAdmin() bool { return u.Role.Name == "admin" } // IsManager checks if user is manager func (u *User) IsManager() bool { return u.Role.Name == "manager" } func (u *User) HasPermission(permissionSlug string) bool { // Jika Role atau Permissions belum di-load, return false (fail safe) if u.Role.ID == 0 { return false } // Admin (Role ID 1) biasanya bypass semua check, tapi sebaiknya tetap cek list // untuk konsistensi database. for _, perm := range u.Role.Permissions { if perm.Slug == permissionSlug { return true } } return false } // IsUser checks if user is regular user func (u *User) IsUser() bool { return u.Role.Name == "user" } // UserResponse represents user data for API responses type UserResponse struct { ID uint `json:"id"` Name string `json:"name"` Email string `json:"email"` NRP string `json:"nrp,omitempty"` // ✅ Langsung dari database Phone string `json:"phone,omitempty"` // ✅ Langsung dari database Role string `json:"role"` Status string `json:"status"` LastLogin *time.Time `json:"last_login,omitempty"` CreatedAt time.Time `json:"created_at"` } // ✅ ToResponse converts User to UserResponse dengan DEKRIPSI func (u *User) ToResponse() UserResponse { response := UserResponse{ ID: u.ID, Name: u.Name, Email: u.Email, NRP: u.NRP, // ✅ Langsung assign Phone: u.Phone, // ✅ Langsung assign Status: u.Status, LastLogin: u.LastLogin, CreatedAt: u.CreatedAt, } // Set role name if u.Role.ID != 0 { response.Role = u.Role.Name } // ✅ DEKRIPSI NRP if u.NRP != "" { decryptedNRP, err := utils.DecryptString(u.NRP) if err == nil { response.NRP = decryptedNRP } else { // Jika dekripsi gagal, kembalikan nilai asli (untuk backward compatibility) response.NRP = u.NRP } } // ✅ DEKRIPSI Phone if u.Phone != "" { decryptedPhone, err := utils.DecryptString(u.Phone) if err == nil { response.Phone = decryptedPhone } else { // Jika dekripsi gagal, kembalikan nilai asli (untuk backward compatibility) response.Phone = u.Phone } } return response } // ✅ ToPublicResponse - untuk public access (hide sensitive data) func (u *User) ToPublicResponse() UserResponse { return UserResponse{ ID: u.ID, Name: u.Name, Role: u.Role.Name, Status: u.Status, CreatedAt: u.CreatedAt, // NRP & Phone tidak disertakan untuk security } }