feat(09-02): add admin create and reset-password commands
- Commands hash with bcrypt, validate role codes, and revoke tokens on reset - Generated app main appends cabana.RuntimeCommands exactly once
This commit is contained in:
@@ -5,8 +5,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.golem15.com/golem15/summercms/cabana"
|
||||
"git.golem15.com/golem15/summercms/party"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"gorm.io/gorm"
|
||||
@@ -169,7 +169,7 @@ func TestBackendAdminWinterRow(t *testing.T) {
|
||||
if err := Migrate(gdb, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var role cabana.BackendUserRole
|
||||
var role winterRole
|
||||
if err := gdb.Where("code = ?", "developer").First(&role).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -181,7 +181,7 @@ func TestBackendAdminWinterRow(t *testing.T) {
|
||||
VALUES ('Ada', 'Lovelace', 'ada', 'Ada@Example.Test', 'winter-hash', 'act', 'persist', 'reset', '{"backend.manage_access":1}', TRUE, FALSE, NULL, NULL, NULL, NOW(), NOW())`).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var user cabana.BackendUser
|
||||
var user winterUser
|
||||
if err := gdb.Preload("Role").Where("login = ?", "ada").First(&user).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -202,10 +202,10 @@ func TestBackendAdminWinterRow(t *testing.T) {
|
||||
if err := gdb.Delete(&user).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := gdb.Where("login = ?", "ada").First(&cabana.BackendUser{}).Error; err == nil {
|
||||
if err := gdb.Where("login = ?", "ada").First(&winterUser{}).Error; err == nil {
|
||||
t.Fatal("soft-deleted backend user remained visible")
|
||||
}
|
||||
if err := gdb.Unscoped().Where("login = ?", "ada").First(&cabana.BackendUser{}).Error; err != nil {
|
||||
if err := gdb.Unscoped().Where("login = ?", "ada").First(&winterUser{}).Error; err != nil {
|
||||
t.Fatalf("unscoped load: %v", err)
|
||||
}
|
||||
if err := gdb.Exec(`INSERT INTO backend_user_roles (name, code, is_system, created_at, updated_at) VALUES ('Editor A', 'shared', FALSE, NOW(), NOW())`).Error; err != nil {
|
||||
@@ -216,6 +216,37 @@ func TestBackendAdminWinterRow(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// winterUser mirrors cabana.BackendUser's column contract without importing
|
||||
// cabana. Cabana commands call lagoon.OpenFromApp, so a lagoon test cannot
|
||||
// import cabana.
|
||||
type winterRole struct {
|
||||
ID uint `gorm:"column:id;primaryKey"`
|
||||
Name string `gorm:"column:name"`
|
||||
Code string `gorm:"column:code"`
|
||||
IsSystem bool `gorm:"column:is_system"`
|
||||
}
|
||||
|
||||
func (winterRole) TableName() string { return "backend_user_roles" }
|
||||
|
||||
type winterUser struct {
|
||||
ID uint `gorm:"column:id;primaryKey"`
|
||||
FirstName string `gorm:"column:first_name"`
|
||||
LastName string `gorm:"column:last_name"`
|
||||
Login string `gorm:"column:login"`
|
||||
Email string `gorm:"column:email"`
|
||||
Password string `gorm:"column:password"`
|
||||
Permissions string `gorm:"column:permissions"`
|
||||
IsActivated bool `gorm:"column:is_activated"`
|
||||
IsSuperuser bool `gorm:"column:is_superuser"`
|
||||
RoleID *uint `gorm:"column:role_id"`
|
||||
LastLogin *time.Time `gorm:"column:last_login"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at"`
|
||||
TokensValidAfter *time.Time `gorm:"column:tokens_valid_after"`
|
||||
Role winterRole
|
||||
}
|
||||
|
||||
func (winterUser) TableName() string { return "backend_users" }
|
||||
|
||||
type systemRole struct {
|
||||
id int
|
||||
system bool
|
||||
|
||||
Reference in New Issue
Block a user