package repository import ( "errors" "fmt" "strings" "github.com/wmms/wmms/internal/model" "github.com/wmms/wmms/pkg/database" ) type OrganizationRepository struct{} var ErrProtectedRole = errors.New("super administrator role cannot be changed") func NewOrganizationRepository() *OrganizationRepository { return &OrganizationRepository{} } func (r *OrganizationRepository) List() ([]model.Organization, error) { rows, err := database.DB.Query(`SELECT id, code, name, status, default_timezone, created_at, updated_at FROM organizations ORDER BY id`) if err != nil { return nil, err } defer rows.Close() organizations := make([]model.Organization, 0) for rows.Next() { var item model.Organization if err := rows.Scan(&item.ID, &item.Code, &item.Name, &item.Status, &item.DefaultTimezone, &item.CreatedAt, &item.UpdatedAt); err != nil { return nil, err } organizations = append(organizations, item) } return organizations, rows.Err() } func (r *OrganizationRepository) Create(item *model.Organization) error { result, err := database.DB.Exec(`INSERT INTO organizations (code, name, status, default_timezone) VALUES (?, ?, ?, ?)`, item.Code, item.Name, item.Status, item.DefaultTimezone) if err != nil { return err } item.ID, err = result.LastInsertId() return err } func (r *OrganizationRepository) Update(item *model.Organization) error { _, err := database.DB.Exec(`UPDATE organizations SET name = ?, status = ?, default_timezone = ? WHERE id = ?`, item.Name, item.Status, item.DefaultTimezone, item.ID) return err } func (r *OrganizationRepository) ListRoles() ([]model.Role, error) { rows, err := database.DB.Query(`SELECT id, code, name, enabled, created_at, updated_at FROM roles ORDER BY id`) if err != nil { return nil, err } defer rows.Close() roles := make([]model.Role, 0) roleIndexes := make(map[int64]int) for rows.Next() { var item model.Role if err := rows.Scan(&item.ID, &item.Code, &item.Name, &item.Enabled, &item.CreatedAt, &item.UpdatedAt); err != nil { return nil, err } item.Permissions = []model.Permission{} roleIndexes[item.ID] = len(roles) roles = append(roles, item) } if err := rows.Err(); err != nil { return nil, err } permissionRows, err := database.DB.Query(`SELECT rp.role_id, p.id, p.code, p.name FROM role_permissions rp JOIN permissions p ON p.id = rp.permission_id ORDER BY rp.role_id, p.code`) if err != nil { return nil, err } defer permissionRows.Close() for permissionRows.Next() { var roleID int64 var permission model.Permission if err := permissionRows.Scan(&roleID, &permission.ID, &permission.Code, &permission.Name); err != nil { return nil, err } if index, ok := roleIndexes[roleID]; ok { roles[index].Permissions = append(roles[index].Permissions, permission) } } return roles, permissionRows.Err() } func (r *OrganizationRepository) ListPermissions() ([]model.Permission, error) { rows, err := database.DB.Query(`SELECT id, code, name FROM permissions ORDER BY code`) if err != nil { return nil, err } defer rows.Close() permissions := make([]model.Permission, 0) for rows.Next() { var permission model.Permission if err := rows.Scan(&permission.ID, &permission.Code, &permission.Name); err != nil { return nil, err } permissions = append(permissions, permission) } return permissions, rows.Err() } func (r *OrganizationRepository) UpdateRole(roleID int64, name string, enabled bool, permissionCodes []string) (err error) { tx, err := database.DB.Begin() if err != nil { return err } defer func() { if err != nil { _ = tx.Rollback() } }() var roleCode string if err = tx.QueryRow(`SELECT code FROM roles WHERE id = ? FOR UPDATE`, roleID).Scan(&roleCode); err != nil { return err } if roleCode == "super_admin" { return ErrProtectedRole } if _, err = tx.Exec(`UPDATE roles SET name = ?, enabled = ? WHERE id = ?`, name, enabled, roleID); err != nil { return err } if _, err = tx.Exec(`DELETE FROM role_permissions WHERE role_id = ?`, roleID); err != nil { return err } permissionCodes = uniqueStrings(permissionCodes) if len(permissionCodes) > 0 { placeholders := strings.TrimSuffix(strings.Repeat("?, ", len(permissionCodes)), ", ") query := fmt.Sprintf(`INSERT INTO role_permissions (role_id, permission_id) SELECT ?, id FROM permissions WHERE code IN (%s)`, placeholders) args := make([]interface{}, 0, len(permissionCodes)+1) args = append(args, roleID) for _, code := range permissionCodes { args = append(args, code) } result, execErr := tx.Exec(query, args...) if execErr != nil { err = execErr return err } var affected int64 affected, err = result.RowsAffected() if err != nil { return err } if affected != int64(len(permissionCodes)) { return fmt.Errorf("one or more permission codes do not exist") } } return tx.Commit() } func uniqueStrings(values []string) []string { seen := make(map[string]struct{}, len(values)) result := make([]string, 0, len(values)) for _, value := range values { value = strings.TrimSpace(value) if value == "" { continue } if _, exists := seen[value]; exists { continue } seen[value] = struct{}{} result = append(result, value) } return result }