snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
434
server/system/automation/roles_handler.go
Normal file
434
server/system/automation/roles_handler.go
Normal file
@@ -0,0 +1,434 @@
|
||||
package automation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
. "github.com/cortezaproject/corteza/server/pkg/expr"
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/pkg/wfexec"
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type (
|
||||
roleService interface {
|
||||
FindByID(ctx context.Context, roleID uint64) (*types.Role, error)
|
||||
FindByHandle(ctx context.Context, handle string) (*types.Role, error)
|
||||
Find(ctx context.Context, filter types.RoleFilter) (set types.RoleSet, f types.RoleFilter, err error)
|
||||
|
||||
Create(ctx context.Context, role *types.Role) (*types.Role, error)
|
||||
Update(ctx context.Context, role *types.Role) (*types.Role, error)
|
||||
|
||||
Delete(ctx context.Context, id uint64) error
|
||||
Archive(ctx context.Context, id uint64) error
|
||||
Unarchive(ctx context.Context, id uint64) error
|
||||
Undelete(ctx context.Context, id uint64) error
|
||||
|
||||
Membership(ctx context.Context, userID uint64) (types.RoleMemberSet, error)
|
||||
MemberList(ctx context.Context, roleID uint64) (types.RoleMemberSet, error)
|
||||
MemberAdd(ctx context.Context, roleID, userID uint64) error
|
||||
MemberRemove(ctx context.Context, roleID, userID uint64) error
|
||||
}
|
||||
|
||||
rolesHandler struct {
|
||||
reg rolesHandlerRegistry
|
||||
rSvc roleService
|
||||
uSvc userService
|
||||
}
|
||||
|
||||
roleSetIterator struct {
|
||||
// Item buffer, current item pointer, and total items traversed
|
||||
ptr uint
|
||||
buffer types.RoleSet
|
||||
total uint
|
||||
|
||||
// When filter limit is set, this constraints it
|
||||
iterLimit uint
|
||||
useIterLimit bool
|
||||
|
||||
// Item loader for additional chunks
|
||||
filter types.RoleFilter
|
||||
loader func() error
|
||||
|
||||
// Total reported by the first page
|
||||
resTotal uint
|
||||
}
|
||||
|
||||
roleLookup interface {
|
||||
GetLookup() (bool, uint64, string, *types.Role)
|
||||
}
|
||||
)
|
||||
|
||||
func RolesHandler(reg rolesHandlerRegistry, rSvc roleService, uSvc userService) *rolesHandler {
|
||||
h := &rolesHandler{
|
||||
reg: reg,
|
||||
rSvc: rSvc,
|
||||
uSvc: uSvc,
|
||||
}
|
||||
|
||||
h.register()
|
||||
return h
|
||||
}
|
||||
|
||||
func (h rolesHandler) lookup(ctx context.Context, args *rolesLookupArgs) (results *rolesLookupResults, err error) {
|
||||
results = &rolesLookupResults{}
|
||||
results.Role, err = lookupRole(ctx, h.rSvc, args)
|
||||
return
|
||||
}
|
||||
|
||||
func (h rolesHandler) searchMembers(ctx context.Context, args *rolesSearchMembersArgs) (results *rolesSearchMembersResults, err error) {
|
||||
results = &rolesSearchMembersResults{}
|
||||
|
||||
rl, err := lookupRole(ctx, h.rSvc, args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if rl == nil {
|
||||
return nil, fmt.Errorf("role not found")
|
||||
}
|
||||
|
||||
// Get membership info
|
||||
mm, err := h.rSvc.MemberList(ctx, rl.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(mm) == 0 {
|
||||
results.Users = []*types.User{}
|
||||
return
|
||||
}
|
||||
|
||||
// Get actual users
|
||||
uu := make([]string, len(mm))
|
||||
for i, m := range mm {
|
||||
uu[i] = cast.ToString(rbac.ResourceID(m.Resource))
|
||||
}
|
||||
results.Users, _, err = h.uSvc.Find(ctx, types.UserFilter{
|
||||
UserID: uu,
|
||||
})
|
||||
results.Total = uint64(len(results.Users))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (h rolesHandler) eachMember(ctx context.Context, args *rolesEachMemberArgs) (out wfexec.IteratorHandler, err error) {
|
||||
var (
|
||||
i = &userSetIterator{}
|
||||
)
|
||||
|
||||
rl, err := lookupRole(ctx, h.rSvc, args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if rl == nil {
|
||||
return nil, fmt.Errorf("role not found")
|
||||
}
|
||||
|
||||
// Get membership info
|
||||
mm, err := h.rSvc.MemberList(ctx, rl.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(mm) == 0 {
|
||||
i.buffer = []*types.User{}
|
||||
i.filter = types.UserFilter{}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// Get actual users
|
||||
uu := make([]string, len(mm))
|
||||
for i, m := range mm {
|
||||
uu[i] = cast.ToString(rbac.ResourceID(m.Resource))
|
||||
}
|
||||
i.buffer, i.filter, err = h.uSvc.Find(ctx, types.UserFilter{
|
||||
UserID: uu,
|
||||
})
|
||||
return i, err
|
||||
}
|
||||
|
||||
func (h rolesHandler) addMember(ctx context.Context, args *rolesAddMemberArgs) (err error) {
|
||||
role, err := lookupRole(ctx, h.rSvc, &rolesLookupArgs{
|
||||
hasLookup: args.hasRole,
|
||||
Lookup: args.Role,
|
||||
lookupID: args.roleID,
|
||||
lookupHandle: args.roleHandle,
|
||||
lookupRes: args.roleRes,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if role == nil {
|
||||
return fmt.Errorf("role not found")
|
||||
}
|
||||
|
||||
user, err := lookupUser(ctx, h.uSvc, &usersLookupArgs{
|
||||
hasLookup: args.hasUser,
|
||||
Lookup: args.User,
|
||||
lookupID: args.userID,
|
||||
lookupHandle: args.userHandle,
|
||||
lookupEmail: args.userEmail,
|
||||
lookupRes: args.userRes,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if role == nil {
|
||||
return fmt.Errorf("user not found")
|
||||
}
|
||||
|
||||
return h.rSvc.MemberAdd(ctx, role.ID, user.ID)
|
||||
}
|
||||
|
||||
func (h rolesHandler) removeMember(ctx context.Context, args *rolesRemoveMemberArgs) (err error) {
|
||||
role, err := lookupRole(ctx, h.rSvc, &rolesLookupArgs{
|
||||
hasLookup: args.hasRole,
|
||||
Lookup: args.Role,
|
||||
lookupID: args.roleID,
|
||||
lookupHandle: args.roleHandle,
|
||||
lookupRes: args.roleRes,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if role == nil {
|
||||
return fmt.Errorf("role not found")
|
||||
}
|
||||
|
||||
user, err := lookupUser(ctx, h.uSvc, &usersLookupArgs{
|
||||
hasLookup: args.hasUser,
|
||||
Lookup: args.User,
|
||||
lookupID: args.userID,
|
||||
lookupHandle: args.userHandle,
|
||||
lookupEmail: args.userEmail,
|
||||
lookupRes: args.userRes,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if role == nil {
|
||||
return fmt.Errorf("user not found")
|
||||
}
|
||||
|
||||
return h.rSvc.MemberRemove(ctx, role.ID, user.ID)
|
||||
}
|
||||
|
||||
func (h rolesHandler) search(ctx context.Context, args *rolesSearchArgs) (results *rolesSearchResults, err error) {
|
||||
results = &rolesSearchResults{}
|
||||
|
||||
var (
|
||||
f = types.RoleFilter{
|
||||
Query: args.Query,
|
||||
MemberID: args.MemberID,
|
||||
Name: args.Name,
|
||||
Handle: args.Handle,
|
||||
Labels: args.Labels,
|
||||
Deleted: filter.State(args.Deleted),
|
||||
Archived: filter.State(args.Archived),
|
||||
}
|
||||
)
|
||||
|
||||
if args.hasSort {
|
||||
if err = f.Sort.Set(args.Sort); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if args.hasPageCursor && args.PageCursor != "" {
|
||||
f.PageCursor = &filter.PagingCursor{}
|
||||
if err = f.PageCursor.UnmarshalJSON([]byte(args.PageCursor)); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if args.hasLabels {
|
||||
f.Labels = args.Labels
|
||||
}
|
||||
|
||||
if args.hasLimit {
|
||||
f.Limit = uint(args.Limit)
|
||||
}
|
||||
|
||||
// Total cannot be fetched together with a page cursor
|
||||
f.IncTotal = args.IncTotal && f.PageCursor == nil
|
||||
|
||||
var auxf types.RoleFilter
|
||||
results.Roles, auxf, err = h.rSvc.Find(ctx, f)
|
||||
results.Total = uint64(auxf.Total)
|
||||
return
|
||||
}
|
||||
|
||||
func (h rolesHandler) each(ctx context.Context, args *rolesEachArgs) (out wfexec.IteratorHandler, err error) {
|
||||
var (
|
||||
i = &roleSetIterator{}
|
||||
f = types.RoleFilter{
|
||||
Query: args.Query,
|
||||
MemberID: args.MemberID,
|
||||
Name: args.Name,
|
||||
Handle: args.Handle,
|
||||
Labels: args.Labels,
|
||||
Deleted: filter.State(args.Deleted),
|
||||
Archived: filter.State(args.Archived),
|
||||
}
|
||||
)
|
||||
|
||||
if args.hasSort {
|
||||
if err = f.Sort.Set(args.Sort); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if args.hasPageCursor && args.PageCursor != "" {
|
||||
f.NextPage = &filter.PagingCursor{}
|
||||
if err = f.NextPage.UnmarshalJSON([]byte(args.PageCursor)); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if args.hasLabels {
|
||||
f.Labels = args.Labels
|
||||
}
|
||||
|
||||
if args.hasLimit {
|
||||
i.useIterLimit = true
|
||||
i.iterLimit = uint(args.Limit)
|
||||
|
||||
f.Limit = uint(args.Limit)
|
||||
|
||||
if args.Limit > uint64(wfexec.MaxIteratorBufferSize) {
|
||||
f.Limit = wfexec.MaxIteratorBufferSize
|
||||
}
|
||||
i.iterLimit = uint(args.Limit)
|
||||
} else {
|
||||
f.Limit = wfexec.MaxIteratorBufferSize
|
||||
}
|
||||
|
||||
f.IncTotal = args.IncTotal
|
||||
|
||||
i.filter = f
|
||||
i.loader = func() (err error) {
|
||||
// Edgecase
|
||||
if i.filter.PageCursor != nil && i.filter.NextPage == nil {
|
||||
return
|
||||
}
|
||||
|
||||
i.total += i.ptr
|
||||
i.ptr = 0
|
||||
|
||||
i.filter.PageCursor = i.filter.NextPage
|
||||
i.filter.NextPage = nil
|
||||
|
||||
// Total is fetched with the first page only; a paged query cannot carry it
|
||||
i.filter.IncTotal = i.filter.IncTotal && i.filter.PageCursor == nil
|
||||
|
||||
i.buffer, i.filter, err = h.rSvc.Find(ctx, i.filter)
|
||||
if i.filter.IncTotal {
|
||||
i.resTotal = i.filter.Total
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Initial load
|
||||
return i, i.loader()
|
||||
}
|
||||
|
||||
func (h rolesHandler) create(ctx context.Context, args *rolesCreateArgs) (results *rolesCreateResults, err error) {
|
||||
results = &rolesCreateResults{}
|
||||
results.Role, err = h.rSvc.Create(ctx, args.Role)
|
||||
return
|
||||
}
|
||||
|
||||
func (h rolesHandler) update(ctx context.Context, args *rolesUpdateArgs) (results *rolesUpdateResults, err error) {
|
||||
results = &rolesUpdateResults{}
|
||||
results.Role, err = h.rSvc.Update(ctx, args.Role)
|
||||
return
|
||||
}
|
||||
|
||||
func (h rolesHandler) delete(ctx context.Context, args *rolesDeleteArgs) error {
|
||||
if id, err := getRoleID(ctx, h.rSvc, args); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return h.rSvc.Delete(ctx, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (h rolesHandler) recover(ctx context.Context, args *rolesRecoverArgs) error {
|
||||
if id, err := getRoleID(ctx, h.rSvc, args); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return h.rSvc.Undelete(ctx, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (h rolesHandler) archive(ctx context.Context, args *rolesArchiveArgs) error {
|
||||
if id, err := getRoleID(ctx, h.rSvc, args); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return h.rSvc.Archive(ctx, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (h rolesHandler) unarchive(ctx context.Context, args *rolesUnarchiveArgs) error {
|
||||
if id, err := getRoleID(ctx, h.rSvc, args); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return h.rSvc.Unarchive(ctx, id)
|
||||
}
|
||||
}
|
||||
|
||||
func getRoleID(ctx context.Context, svc roleService, args roleLookup) (uint64, error) {
|
||||
_, ID, _, _ := args.GetLookup()
|
||||
|
||||
if ID > 0 {
|
||||
return ID, nil
|
||||
}
|
||||
|
||||
role, err := lookupRole(ctx, svc, args)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return role.ID, nil
|
||||
|
||||
}
|
||||
|
||||
func lookupRole(ctx context.Context, svc roleService, args roleLookup) (*types.Role, error) {
|
||||
_, ID, handle, role := args.GetLookup()
|
||||
|
||||
switch {
|
||||
case role != nil:
|
||||
return role, nil
|
||||
case ID > 0:
|
||||
return svc.FindByID(ctx, ID)
|
||||
case len(handle) > 0:
|
||||
return svc.FindByHandle(ctx, handle)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("empty lookup params")
|
||||
}
|
||||
|
||||
func (i *roleSetIterator) More(context.Context, *Vars) (bool, error) {
|
||||
a := wfexec.GenericResourceNextCheck(i.useIterLimit, i.ptr, uint(len(i.buffer)), i.total, i.iterLimit, i.filter.NextPage != nil)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (i *roleSetIterator) Start(context.Context, *Vars) error { i.ptr = 0; return nil }
|
||||
|
||||
func (i *roleSetIterator) Next(context.Context, *Vars) (out *Vars, err error) {
|
||||
if len(i.buffer)-int(i.ptr) <= 0 {
|
||||
if err = i.loader(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
out = &Vars{}
|
||||
out.Set("role", Must(NewRole(i.buffer[i.ptr])))
|
||||
out.Set("index", Must(NewInteger(i.total+i.ptr)))
|
||||
out.Set("total", Must(NewInteger(i.resTotal)))
|
||||
|
||||
i.ptr++
|
||||
return out, nil
|
||||
}
|
||||
Reference in New Issue
Block a user