- permissions (the four Winter codes and manage_privileged_groups), the user navigation item and the embedded admin YAML - Users controller: list with deactivated users, row states, the groups, created date and activated filters, and the form's name, surname and email - a member of a group in golem15.user.privileged_groups (default admin) keeps their email, password and row unless the administrator holds golem15.users.manage_privileged_groups; the refusal is a 403 that saves nothing
119 lines
3.4 KiB
Go
119 lines
3.4 KiB
Go
package classes
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/compass"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// PermissionManagePrivilegedGroups is the backend permission an administrator
|
|
// needs, on top of golem15.users.access_users, to change the email or the
|
|
// password of a member of a privileged group, or to delete such a user for
|
|
// good.
|
|
const PermissionManagePrivilegedGroups = "golem15.users.manage_privileged_groups"
|
|
|
|
// privilegedGroupsKey is the config list of privileged group codes.
|
|
const privilegedGroupsKey = "golem15.user.privileged_groups"
|
|
|
|
// defaultPrivilegedGroup is the only privileged code when the config names
|
|
// none: the site-admin group.
|
|
const defaultPrivilegedGroup = "admin"
|
|
|
|
// PrivilegedGroupCodes returns the group codes whose members are protected,
|
|
// read from golem15.user.privileged_groups on every call so a config change
|
|
// applies without a restart. A nil config or a missing key gives the single
|
|
// code admin. Blank entries are dropped; a key that is present and empty
|
|
// means that no group is privileged.
|
|
func PrivilegedGroupCodes(cfg *compass.Config) []string {
|
|
if cfg == nil {
|
|
return []string{defaultPrivilegedGroup}
|
|
}
|
|
raw, ok := cfg.Lookup(privilegedGroupsKey)
|
|
if !ok {
|
|
return []string{defaultPrivilegedGroup}
|
|
}
|
|
var entries []string
|
|
switch v := raw.(type) {
|
|
case []string:
|
|
entries = v
|
|
case []any:
|
|
for _, item := range v {
|
|
if s, ok := item.(string); ok {
|
|
entries = append(entries, s)
|
|
}
|
|
}
|
|
case string:
|
|
// An environment override arrives as one comma-separated string.
|
|
entries = strings.Split(v, ",")
|
|
}
|
|
codes := make([]string, 0, len(entries))
|
|
for _, entry := range entries {
|
|
if code := strings.TrimSpace(entry); code != "" {
|
|
codes = append(codes, code)
|
|
}
|
|
}
|
|
return codes
|
|
}
|
|
|
|
// IsPrivilegedCode reports whether a group's code is in codes. Codes compare
|
|
// case-sensitively, as HasGroupCode does, and a group without a code is
|
|
// never privileged.
|
|
func IsPrivilegedCode(codes []string, code *string) bool {
|
|
if code == nil || *code == "" {
|
|
return false
|
|
}
|
|
for _, privileged := range codes {
|
|
if privileged == *code {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// PrivilegedGroupIDs returns the ids of the user_groups rows whose code is in
|
|
// codes, ordered by id.
|
|
func PrivilegedGroupIDs(ctx context.Context, db *gorm.DB, codes []string) ([]uint, error) {
|
|
if db == nil {
|
|
return nil, fmt.Errorf("golem15.user: gorm handle is missing")
|
|
}
|
|
ids := []uint{}
|
|
if len(codes) == 0 {
|
|
return ids, nil
|
|
}
|
|
err := db.Session(&gorm.Session{NewDB: true}).WithContext(ctx).
|
|
Table("user_groups").
|
|
Where("code IN ?", codes).
|
|
Order("id").
|
|
Pluck("id", &ids).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ids, nil
|
|
}
|
|
|
|
// IsPrivilegedMember reports whether the user belongs to at least one group
|
|
// whose code is in codes. A user in no group, and a group without a code,
|
|
// give false. A deactivated user's membership counts: it survives the soft
|
|
// delete.
|
|
func IsPrivilegedMember(ctx context.Context, db *gorm.DB, codes []string, userID uint) (bool, error) {
|
|
if db == nil {
|
|
return false, fmt.Errorf("golem15.user: gorm handle is missing")
|
|
}
|
|
if len(codes) == 0 || userID == 0 {
|
|
return false, nil
|
|
}
|
|
held, err := UserGroupCodes(ctx, db.Session(&gorm.Session{NewDB: true}), userID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for i := range held {
|
|
if IsPrivilegedCode(codes, &held[i]) {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|