rebuilt security definitions as a YAML-driven data interface, a lot more like the original code
This commit is contained in:
+161
-123
@@ -10,7 +10,11 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"slices"
|
_ "embed"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
/* securityScope defines nested "scopes" within the security level system. Each scope is numerically nested
|
/* securityScope defines nested "scopes" within the security level system. Each scope is numerically nested
|
||||||
@@ -44,11 +48,136 @@ var scopelist = []securityScope{
|
|||||||
{30000, 31999, 33000, 34999},
|
{30000, 31999, 33000, 34999},
|
||||||
}
|
}
|
||||||
|
|
||||||
// unrestrictedUserLevel is a user level that is above all "low" bands but below all "high" bands.
|
// CfgScope is a configured scope.
|
||||||
const unrestrictedUserLevel uint16 = 32500
|
type CfgScope struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Index int `yaml:"index"`
|
||||||
|
bounds *securityScope
|
||||||
|
}
|
||||||
|
|
||||||
// noAccessLevel is the level used to specify "no access," as it's above the highest value in the topmost scope.
|
// CfgRole is a configured role.
|
||||||
const noAccessLevel uint16 = 65500
|
type CfgRole struct {
|
||||||
|
Internal string `yaml:"name"`
|
||||||
|
Display string `yaml:"display"`
|
||||||
|
Scope string `yaml:"scope"`
|
||||||
|
Value string `yaml:"value"`
|
||||||
|
level uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// CfgDefault is a configured default value.
|
||||||
|
type CfgDefault struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Role string `yaml:"role"`
|
||||||
|
roleptr *CfgRole
|
||||||
|
}
|
||||||
|
|
||||||
|
// CfgRoleList is a configured role list.
|
||||||
|
type CfgRoleList struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
DDefault string `yaml:"default"`
|
||||||
|
DRoles []string `yaml:"roles"`
|
||||||
|
defptr *CfgRole
|
||||||
|
roleptrs []*CfgRole
|
||||||
|
}
|
||||||
|
|
||||||
|
// CfgPermission is a configured permission.
|
||||||
|
type CfgPermission struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Role string `yaml:"role"`
|
||||||
|
level uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// CfgSecurityDefs is the master structure for security definitions.
|
||||||
|
type CfgSecurityDefs struct {
|
||||||
|
Scopes []CfgScope `yaml:"scopes"`
|
||||||
|
Roles []CfgRole `yaml:"roles"`
|
||||||
|
Defaults []CfgDefault `yaml:"defaults"`
|
||||||
|
Lists []CfgRoleList `yaml:"lists"`
|
||||||
|
Permissions []CfgPermission `yaml:"permissions"`
|
||||||
|
scopeMap map[string]*CfgScope
|
||||||
|
roleMap map[string]*CfgRole
|
||||||
|
defaultsMap map[string]*CfgDefault
|
||||||
|
listsMap map[string]*CfgRoleList
|
||||||
|
permsMap map[string]*CfgPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed securitydefs.yaml
|
||||||
|
var initSecurityData []byte
|
||||||
|
|
||||||
|
// securityRoot contains the root-level security information.
|
||||||
|
var securityRoot CfgSecurityDefs
|
||||||
|
|
||||||
|
// parseLevelValue is a helper which parses the role level definition strings.
|
||||||
|
func parseLevelValue(scope *securityScope, value string) uint16 {
|
||||||
|
switch value {
|
||||||
|
case "LMIN":
|
||||||
|
return scope.lowbandLow
|
||||||
|
case "LMAX":
|
||||||
|
return scope.lowbandHigh
|
||||||
|
case "HMIN":
|
||||||
|
return scope.highbandLow
|
||||||
|
case "HMAX":
|
||||||
|
return scope.highbandHigh
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(value, "L+") {
|
||||||
|
v, err := strconv.Atoi(value[2:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return scope.lowbandLow + uint16(v)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(value, "H+") {
|
||||||
|
v, err := strconv.Atoi(value[2:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return scope.highbandLow + uint16(v)
|
||||||
|
}
|
||||||
|
v, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return uint16(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// init sets up all the security data.
|
||||||
|
func init() {
|
||||||
|
if err := yaml.Unmarshal(initSecurityData, &securityRoot); err != nil {
|
||||||
|
panic(err) // can't happen
|
||||||
|
}
|
||||||
|
securityRoot.scopeMap = make(map[string]*CfgScope)
|
||||||
|
for i, sc := range securityRoot.Scopes {
|
||||||
|
securityRoot.Scopes[i].bounds = &(scopelist[sc.Index])
|
||||||
|
securityRoot.scopeMap[sc.Name] = &(securityRoot.Scopes[i])
|
||||||
|
}
|
||||||
|
securityRoot.roleMap = make(map[string]*CfgRole)
|
||||||
|
for i, ro := range securityRoot.Roles {
|
||||||
|
scope := securityRoot.scopeMap[ro.Scope]
|
||||||
|
securityRoot.Roles[i].level = parseLevelValue(scope.bounds, ro.Value)
|
||||||
|
securityRoot.roleMap[ro.Internal] = &(securityRoot.Roles[i])
|
||||||
|
}
|
||||||
|
securityRoot.defaultsMap = make(map[string]*CfgDefault)
|
||||||
|
for i, def := range securityRoot.Defaults {
|
||||||
|
securityRoot.Defaults[i].roleptr = securityRoot.roleMap[def.Role]
|
||||||
|
securityRoot.defaultsMap[def.Name] = &(securityRoot.Defaults[i])
|
||||||
|
}
|
||||||
|
securityRoot.listsMap = make(map[string]*CfgRoleList)
|
||||||
|
for i, li := range securityRoot.Lists {
|
||||||
|
if li.DDefault != "" {
|
||||||
|
securityRoot.Lists[i].defptr = securityRoot.roleMap[li.DDefault]
|
||||||
|
}
|
||||||
|
securityRoot.Lists[i].roleptrs = make([]*CfgRole, len(li.DRoles))
|
||||||
|
for j, rn := range li.DRoles {
|
||||||
|
securityRoot.Lists[i].roleptrs[j] = securityRoot.roleMap[rn]
|
||||||
|
}
|
||||||
|
securityRoot.listsMap[li.Name] = &(securityRoot.Lists[i])
|
||||||
|
}
|
||||||
|
securityRoot.permsMap = make(map[string]*CfgPermission)
|
||||||
|
for i, pm := range securityRoot.Permissions {
|
||||||
|
securityRoot.Permissions[i].level = securityRoot.roleMap[pm.Role].level
|
||||||
|
securityRoot.permsMap[pm.Name] = &(securityRoot.Permissions[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Role defines a security role.
|
// Role defines a security role.
|
||||||
type Role interface {
|
type Role interface {
|
||||||
@@ -57,25 +186,15 @@ type Role interface {
|
|||||||
Level() uint16
|
Level() uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// amRole is the internal implementation of the Role.
|
func (r *CfgRole) ID() string {
|
||||||
type amRole struct {
|
return r.Internal
|
||||||
id string
|
|
||||||
name string
|
|
||||||
level uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID returns the string identifier of the role.
|
func (r *CfgRole) Name() string {
|
||||||
func (r *amRole) ID() string {
|
return r.Display
|
||||||
return r.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the textual name of the role.
|
func (r *CfgRole) Level() uint16 {
|
||||||
func (r *amRole) Name() string {
|
|
||||||
return r.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Level returns the access level of the role.
|
|
||||||
func (r *amRole) Level() uint16 {
|
|
||||||
return r.level
|
return r.level
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,50 +204,16 @@ type RoleList interface {
|
|||||||
Default() Role
|
Default() Role
|
||||||
}
|
}
|
||||||
|
|
||||||
// amRoleList is the internal implementation of RoleList.
|
func (r *CfgRoleList) Roles() []Role {
|
||||||
type amRoleList struct {
|
rc := make([]Role, len(r.roleptrs))
|
||||||
roleList []Role
|
for i := range r.roleptrs {
|
||||||
defaultRole Role
|
rc[i] = r.roleptrs[i]
|
||||||
|
}
|
||||||
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roles returns the list of roles for a given RoleList.
|
func (r *CfgRoleList) Default() Role {
|
||||||
func (rl *amRoleList) Roles() []Role {
|
return r.defptr
|
||||||
return rl.roleList
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default returns the default role in a given RoleList.
|
|
||||||
func (rl *amRoleList) Default() Role {
|
|
||||||
return rl.defaultRole
|
|
||||||
}
|
|
||||||
|
|
||||||
// roles holds all the defined roles.
|
|
||||||
var roles map[string]Role
|
|
||||||
|
|
||||||
// roleDefaults assigns roles to symbolic default names.
|
|
||||||
var roleDefaults map[string]Role
|
|
||||||
|
|
||||||
// roleLists holds all the defined role lists.
|
|
||||||
var roleLists map[string]RoleList
|
|
||||||
|
|
||||||
// permissions assigns roles to specific named permissions.
|
|
||||||
var permissions map[string]Role
|
|
||||||
|
|
||||||
// defineRole defines a role and adds it to the roles map.
|
|
||||||
func defineRole(id string, name string, level uint16) Role {
|
|
||||||
r := amRole{id: id, name: name, level: level}
|
|
||||||
roles[id] = &r
|
|
||||||
return &r
|
|
||||||
}
|
|
||||||
|
|
||||||
// defineRoleList defines a role list and adds it to the roleLists map.
|
|
||||||
func defineRoleList(id string, roles []Role, defaultRole Role) {
|
|
||||||
slices.SortFunc(roles, func(a Role, b Role) int {
|
|
||||||
leva := int(a.Level())
|
|
||||||
levb := int(b.Level())
|
|
||||||
return leva - levb
|
|
||||||
})
|
|
||||||
rl := amRoleList{roleList: roles, defaultRole: defaultRole}
|
|
||||||
roleLists[id] = &rl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AmRole returns a Role given a string ID.
|
/* AmRole returns a Role given a string ID.
|
||||||
@@ -138,17 +223,27 @@ func defineRoleList(id string, roles []Role, defaultRole Role) {
|
|||||||
* The specified role.
|
* The specified role.
|
||||||
*/
|
*/
|
||||||
func AmRole(id string) Role {
|
func AmRole(id string) Role {
|
||||||
return roles[id]
|
return securityRoot.roleMap[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AmDefaultRole returns a Role diven a default ID.
|
/* AmDefaultRole returns a Role given a default ID.
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* id - ID of the default to look up.
|
* id - ID of the default to look up.
|
||||||
* Returns:
|
* Returns:
|
||||||
* The specified role.
|
* The specified role.
|
||||||
*/
|
*/
|
||||||
func AmDefaultRole(id string) Role {
|
func AmDefaultRole(id string) Role {
|
||||||
return roleDefaults[id]
|
return securityRoot.defaultsMap[id].roleptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AmRoleList returns a RoleList given a list ID.
|
||||||
|
* Parameters:
|
||||||
|
* id - ID of the list to look up.
|
||||||
|
* Returns:
|
||||||
|
* The specified role list.
|
||||||
|
*/
|
||||||
|
func AmRoleList(id string) RoleList {
|
||||||
|
return securityRoot.listsMap[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AmTestPermission tests a specified access level to see if it satisfies the given permission.
|
/* AmTestPermission tests a specified access level to see if it satisfies the given permission.
|
||||||
@@ -159,62 +254,5 @@ func AmDefaultRole(id string) Role {
|
|||||||
* true if the permission test is satisfied, false if not.
|
* true if the permission test is satisfied, false if not.
|
||||||
*/
|
*/
|
||||||
func AmTestPermission(id string, level uint16) bool {
|
func AmTestPermission(id string, level uint16) bool {
|
||||||
return permissions[id].Level() < level
|
return securityRoot.permsMap[id].level < level
|
||||||
}
|
|
||||||
|
|
||||||
// init initializes all the security data.
|
|
||||||
func init() {
|
|
||||||
// Initialize the roles.
|
|
||||||
roles = make(map[string]Role)
|
|
||||||
not := defineRole("NotInList", "Not in List", 0)
|
|
||||||
uu := defineRole("UnrestrictedUser", "Unrestricted User", unrestrictedUserLevel)
|
|
||||||
none := defineRole("NoAccess", "No Access", noAccessLevel)
|
|
||||||
g_anon := defineRole("Global.Anonymous", "Anonymous User", scopelist[0].lowbandLow+100)
|
|
||||||
g_unverf := defineRole("Global.Unverified", "Unauthenticated User", scopelist[0].lowbandLow+500)
|
|
||||||
g_normal := defineRole("Global.Normal", "Normal User", scopelist[0].lowbandLow+1000)
|
|
||||||
g_anyadmin := defineRole("Global.AnyAdmin", "Any System Administrator", scopelist[0].highbandLow)
|
|
||||||
g_PFY := defineRole("Global.PFY", "System Assistant Administrator", scopelist[0].highbandLow+1000)
|
|
||||||
g_BOFH := defineRole("Global.BOFH", "Global System Administrator", scopelist[0].highbandHigh)
|
|
||||||
com_member := defineRole("Community.Member", "Community Member", scopelist[1].lowbandLow+500)
|
|
||||||
com_anyadmin := defineRole("Community.AnyAdmin", "Any Community Administrator", scopelist[1].highbandLow)
|
|
||||||
com_cohost := defineRole("Community.Cohost", "Community Co-Host", scopelist[1].highbandLow+1000)
|
|
||||||
com_host := defineRole("Community.Host", "Community Host", scopelist[1].highbandLow+1500)
|
|
||||||
|
|
||||||
// Initialize the defaults list.
|
|
||||||
roleDefaults = make(map[string]Role)
|
|
||||||
roleDefaults["Global.NewUser"] = g_unverf
|
|
||||||
roleDefaults["Global.AfterVerify"] = g_normal
|
|
||||||
roleDefaults["Global.AfterEmailChange"] = g_unverf
|
|
||||||
roleDefaults["Community.NewUser"] = com_member
|
|
||||||
roleDefaults["Community.Creator"] = com_host
|
|
||||||
|
|
||||||
// Initialize the roles lists.
|
|
||||||
roleLists = make(map[string]RoleList)
|
|
||||||
defineRoleList("Global.UserLevels", []Role{g_anon, g_unverf, g_normal, uu}, nil)
|
|
||||||
defineRoleList("Global.UserLevelsPFY", []Role{g_anon, g_unverf, g_normal, uu, g_PFY}, nil)
|
|
||||||
defineRoleList("Global.CreateCommunity", []Role{g_normal, uu, g_anyadmin, g_PFY, g_BOFH}, g_normal)
|
|
||||||
defineRoleList("Community.Read", []Role{g_anon, g_unverf, g_normal, com_member, uu, com_anyadmin, com_cohost, com_host, g_anyadmin}, com_member)
|
|
||||||
defineRoleList("Community.Write", []Role{com_anyadmin, com_cohost, com_host, g_anyadmin, g_PFY, g_BOFH}, com_cohost)
|
|
||||||
defineRoleList("Community.Create", []Role{g_normal, com_member, uu, com_anyadmin, com_cohost, com_host, g_anyadmin}, com_cohost)
|
|
||||||
defineRoleList("Community.Delete", []Role{com_anyadmin, com_cohost, com_host, g_anyadmin, g_PFY, g_BOFH, none}, com_host)
|
|
||||||
defineRoleList("Community.Join", []Role{g_anon, g_unverf, g_normal}, g_normal)
|
|
||||||
defineRoleList("Community.UserLevels", []Role{not, g_anon, g_unverf, g_normal, com_member, uu, com_cohost}, nil)
|
|
||||||
|
|
||||||
// Initialize the permissions lists.
|
|
||||||
permissions = make(map[string]Role)
|
|
||||||
permissions["Global.ShowHiddenCategories"] = g_anyadmin
|
|
||||||
permissions["Global.NoEmailVerify"] = g_anyadmin
|
|
||||||
permissions["Global.SeeHiddenContactInfo"] = g_anyadmin
|
|
||||||
permissions["Global.SearchHiddenCommunities"] = g_anyadmin
|
|
||||||
permissions["Global.ShowHiddenCommunities"] = g_anyadmin
|
|
||||||
permissions["Global.SearchHiddenCategories"] = g_anyadmin
|
|
||||||
permissions["Global.SysAdminAccess"] = g_anyadmin
|
|
||||||
permissions["Global.PublishFP"] = g_anyadmin
|
|
||||||
permissions["Global.DesignatePFY"] = g_BOFH
|
|
||||||
permissions["Community.ShowAdmin"] = com_anyadmin
|
|
||||||
permissions["Community.NoJoinRequired"] = g_anyadmin
|
|
||||||
permissions["Community.NoKeyRequired"] = g_anyadmin
|
|
||||||
permissions["Community.ShowHiddenMembers"] = com_anyadmin
|
|
||||||
permissions["Community.ShowHiddenObjects"] = com_anyadmin
|
|
||||||
permissions["Community.MassMail"] = com_anyadmin
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
#
|
||||||
|
# Amsterdam Web Communities System
|
||||||
|
# Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||||
|
#
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
#
|
||||||
|
scopes:
|
||||||
|
- name: Global
|
||||||
|
index: 0
|
||||||
|
- name: Community
|
||||||
|
index: 1
|
||||||
|
roles:
|
||||||
|
- name: "NotInList"
|
||||||
|
display: "Not In List"
|
||||||
|
scope: Global
|
||||||
|
value: "0"
|
||||||
|
- name: "UnrestrictedUser"
|
||||||
|
display: "Unrestricted User"
|
||||||
|
scope: Global
|
||||||
|
value: "32500"
|
||||||
|
- name: "NoAccess"
|
||||||
|
display: "No Access"
|
||||||
|
scope: Global
|
||||||
|
value: "65500"
|
||||||
|
- name: "Global.Anonymous"
|
||||||
|
display: "Anonymous User"
|
||||||
|
scope: Global
|
||||||
|
value: "L+100"
|
||||||
|
- name: "Global.Unverified"
|
||||||
|
display: "Unauthenticated User"
|
||||||
|
scope: Global
|
||||||
|
value: "L+500"
|
||||||
|
- name: "Global.Normal"
|
||||||
|
display: "Normal User"
|
||||||
|
scope: Global
|
||||||
|
value: "L+1000"
|
||||||
|
- name: "Global.AnyAdmin"
|
||||||
|
display: "Any System Administrator"
|
||||||
|
scope: Global
|
||||||
|
value: "HMIN"
|
||||||
|
- name: "Global.PFY"
|
||||||
|
display: "System Assistant Administrator"
|
||||||
|
scope: Global
|
||||||
|
value: "H+1000"
|
||||||
|
- name: "Global.BOFH"
|
||||||
|
display: "Global System Administrator"
|
||||||
|
scope: Global
|
||||||
|
value: "HMAX"
|
||||||
|
- name: "Community.Member"
|
||||||
|
display: "Community Member"
|
||||||
|
scope: Community
|
||||||
|
value: "L+500"
|
||||||
|
- name: "Community.AnyAdmin"
|
||||||
|
display: "Any Community Administrator"
|
||||||
|
scope: Community
|
||||||
|
value: "HMIN"
|
||||||
|
- name: "Community.Cohost"
|
||||||
|
display: "Community Co-Host"
|
||||||
|
scope: Community
|
||||||
|
value: "H+1000"
|
||||||
|
- name: "Community.Host"
|
||||||
|
display: "Community Host"
|
||||||
|
scope: Community
|
||||||
|
value: "H+1500"
|
||||||
|
defaults:
|
||||||
|
- name: "Global.NewUser"
|
||||||
|
role: "Global.Unverified"
|
||||||
|
- name: "Global.AfterVerify"
|
||||||
|
role: "Global.Normal"
|
||||||
|
- name: "Global.AfterEmailChange"
|
||||||
|
role: "Global.Unverified"
|
||||||
|
- name: "Community.NewUser"
|
||||||
|
role: "Community.Member"
|
||||||
|
- name: "Community.Creator"
|
||||||
|
role: "Community.Host"
|
||||||
|
lists:
|
||||||
|
- name: "Global.UserLevels"
|
||||||
|
roles:
|
||||||
|
- "Global.Anonymous"
|
||||||
|
- "Global.Unverified"
|
||||||
|
- "Global.Normal"
|
||||||
|
- "UnrestrictedUser"
|
||||||
|
- name: "Global.UserLevelsPFY"
|
||||||
|
roles:
|
||||||
|
- "Global.Anonymous"
|
||||||
|
- "Global.Unverified"
|
||||||
|
- "Global.Normal"
|
||||||
|
- "UnrestrictedUser"
|
||||||
|
- "Global.PFY"
|
||||||
|
- name: "Global.CreateCommunity"
|
||||||
|
default: "Global.Normal"
|
||||||
|
roles:
|
||||||
|
- "Global.Normal"
|
||||||
|
- "UnrestrictedUser"
|
||||||
|
- "Global.AnyAdmin"
|
||||||
|
- "Global.PFY"
|
||||||
|
- "Global.BOFH"
|
||||||
|
- name: "Community.Read"
|
||||||
|
default: "Community.Member"
|
||||||
|
roles:
|
||||||
|
- "Global.Anonymous"
|
||||||
|
- "Global.Unverified"
|
||||||
|
- "Global.Normal"
|
||||||
|
- "Community.Member"
|
||||||
|
- "UnrestrictedUser"
|
||||||
|
- "Community.AnyAdmin"
|
||||||
|
- "Community.Cohost"
|
||||||
|
- "Community.Host"
|
||||||
|
- "Global.AnyAdmin"
|
||||||
|
- name: "Community.Write"
|
||||||
|
default: "Community.Cohost"
|
||||||
|
roles:
|
||||||
|
- "Community.AnyAdmin"
|
||||||
|
- "Community.Cohost"
|
||||||
|
- "Community.Host"
|
||||||
|
- "Global.AnyAdmin"
|
||||||
|
- "Global.PFY"
|
||||||
|
- "Global.BOFH"
|
||||||
|
- name: "Community.Create"
|
||||||
|
default: "Community.Cohost"
|
||||||
|
roles:
|
||||||
|
- "Global.Normal"
|
||||||
|
- "Community.Member"
|
||||||
|
- "UnrestrictedUser"
|
||||||
|
- "Community.AnyAdmin"
|
||||||
|
- "Community.Cohost"
|
||||||
|
- "Community.Host"
|
||||||
|
- "Global.AnyAdmin"
|
||||||
|
- name: "Community.Delete"
|
||||||
|
default: "Community.Host"
|
||||||
|
roles:
|
||||||
|
- "Community.AnyAdmin"
|
||||||
|
- "Community.Cohost"
|
||||||
|
- "Community.Host"
|
||||||
|
- "Global.AnyAdmin"
|
||||||
|
- "Global.PFY"
|
||||||
|
- "Global.BOFH"
|
||||||
|
- "NoAccess"
|
||||||
|
- name: "Community.Join"
|
||||||
|
default: "Global.Normal"
|
||||||
|
roles:
|
||||||
|
- "Global.Anonymous"
|
||||||
|
- "Global.Unverified"
|
||||||
|
- "Global.Normal"
|
||||||
|
- name: "Community.Userlevels"
|
||||||
|
roles:
|
||||||
|
- "NotInList"
|
||||||
|
- "Global.Anonymous"
|
||||||
|
- "Global.Unverified"
|
||||||
|
- "Global.Normal"
|
||||||
|
- "Community.Member"
|
||||||
|
- "UnrestrictedUser"
|
||||||
|
- "Community.Cohost"
|
||||||
|
permissions:
|
||||||
|
- name: "Global.ShowHiddenCategories"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.NoEmailVerify"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.SeeHiddenContactInfo"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.SearchHiddenCommunities"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.ShowHiddenCommunities"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.SearchHiddenCategories"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.SysAdminAccess"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.PublishFP"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Global.DesignatePFY"
|
||||||
|
role: "Global.BOFH"
|
||||||
|
- name: "Community.ShowAdmin"
|
||||||
|
role: "Community.AnyAdmin"
|
||||||
|
- name: "Community.NoJoinRequired"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Community.NoKeyRequired"
|
||||||
|
role: "Global.AnyAdmin"
|
||||||
|
- name: "Community.ShowHiddenMembers"
|
||||||
|
role: "Community.AnyAdmin"
|
||||||
|
- name: "Community.ShowHiddenObjects"
|
||||||
|
role: "Community.AnyAdmin"
|
||||||
|
- name: "Community.MassMail"
|
||||||
|
role: "Community.AnyAdmin"
|
||||||
Reference in New Issue
Block a user