Files
Steve Munene 7fb5dd7b55 NOISSUE - Refactor listing for rules and reports (#433)
* add access control to rules engine

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* update authorization method

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* revert code

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* initial implementation

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* remove domain from method

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix failing linter

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* fix userid parameter

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* update checksuperadmin method

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* revert changes

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

* address comments

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>

---------

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
2026-03-16 14:39:49 +01:00

239 lines
6.8 KiB
Go

// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package re
import (
"context"
"time"
grpcReadersV1 "github.com/absmach/magistrala/api/grpc/readers/v1"
"github.com/absmach/magistrala/pkg/emailer"
pkglog "github.com/absmach/magistrala/pkg/logger"
"github.com/absmach/magistrala/pkg/ticker"
"github.com/absmach/magistrala/re/operations"
"github.com/absmach/supermq"
"github.com/absmach/supermq/pkg/authn"
"github.com/absmach/supermq/pkg/errors"
svcerr "github.com/absmach/supermq/pkg/errors/service"
"github.com/absmach/supermq/pkg/messaging"
"github.com/absmach/supermq/pkg/policies"
"github.com/absmach/supermq/pkg/roles"
)
var (
ErrGoroutinesNotAllowed = errors.New("goroutines are not allowed in Go scripts")
ErrPanicNotAllowed = errors.New("panic is not allowed in Go scripts")
)
type re struct {
repo Repository
runInfo chan pkglog.RunInfo
idp supermq.IDProvider
rePubSub messaging.PubSub
writersPub messaging.Publisher
alarmsPub messaging.Publisher
ticker ticker.Ticker
email emailer.Emailer
readers grpcReadersV1.ReadersServiceClient
roles.ProvisionManageService
}
func NewService(repo Repository, runInfo chan pkglog.RunInfo, policy policies.Service, idp supermq.IDProvider, rePubSub messaging.PubSub, writersPub, alarmsPub messaging.Publisher, tck ticker.Ticker, emailer emailer.Emailer, readers grpcReadersV1.ReadersServiceClient, availableActions []roles.Action, builtInRoles map[roles.BuiltInRoleName][]roles.Action) (Service, error) {
rpms, err := roles.NewProvisionManageService(operations.EntityType, repo, policy, idp, availableActions, builtInRoles)
if err != nil {
return nil, err
}
return &re{
repo: repo,
idp: idp,
runInfo: runInfo,
rePubSub: rePubSub,
writersPub: writersPub,
alarmsPub: alarmsPub,
ticker: tck,
email: emailer,
readers: readers,
ProvisionManageService: rpms,
}, nil
}
func (re *re) AddRule(ctx context.Context, session authn.Session, r Rule) (retRule Rule, retRps []roles.RoleProvision, retErr error) {
if r.Logic.Type == GoType && goKeywordRegex.MatchString(r.Logic.Value) {
return Rule{}, nil, errors.Wrap(svcerr.ErrMalformedEntity, ErrGoroutinesNotAllowed)
}
if r.Logic.Type == GoType && panicRegex.MatchString(r.Logic.Value) {
return Rule{}, nil, errors.Wrap(svcerr.ErrMalformedEntity, ErrPanicNotAllowed)
}
id, err := re.idp.ID()
if err != nil {
return Rule{}, nil, err
}
now := time.Now().UTC()
r.CreatedAt = now
r.ID = id
r.CreatedBy = session.UserID
r.DomainID = session.DomainID
r.Status = EnabledStatus
if !r.Schedule.StartDateTime.IsZero() {
r.Schedule.StartDateTime = now
}
r.Schedule.Time = r.Schedule.StartDateTime
rule, err := re.repo.AddRule(ctx, r)
if err != nil {
return Rule{}, nil, errors.Wrap(svcerr.ErrCreateEntity, err)
}
defer func() {
if retErr != nil {
if errRollBack := re.repo.RemoveRule(ctx, rule.ID); errRollBack != nil {
retErr = errors.Wrap(retErr, errors.Wrap(svcerr.ErrRollbackRepo, errRollBack))
}
}
}()
newBuiltInRoleMembers := map[roles.BuiltInRoleName][]roles.Member{
BuiltInRoleAdmin: {roles.Member(session.UserID)},
}
optionalPolicies := []policies.Policy{
{
SubjectType: policies.DomainType,
Subject: session.DomainID,
Relation: policies.DomainRelation,
ObjectType: operations.EntityType,
Object: rule.ID,
},
}
rps, err := re.AddNewEntitiesRoles(ctx, session.DomainID, session.UserID, []string{rule.ID}, optionalPolicies, newBuiltInRoleMembers)
if err != nil {
return Rule{}, nil, errors.Wrap(svcerr.ErrAddPolicies, err)
}
return rule, rps, nil
}
func (re *re) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (Rule, error) {
var rule Rule
var err error
switch withRoles {
case true:
rule, err = re.repo.RetrieveByIDWithRoles(ctx, id, session.UserID)
default:
rule, err = re.repo.ViewRule(ctx, id)
}
if err != nil {
return Rule{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
return rule, nil
}
func (re *re) UpdateRule(ctx context.Context, session authn.Session, r Rule) (Rule, error) {
if r.Logic.Type == GoType && goKeywordRegex.MatchString(r.Logic.Value) {
return Rule{}, errors.Wrap(svcerr.ErrMalformedEntity, ErrGoroutinesNotAllowed)
}
if r.Logic.Type == GoType && panicRegex.MatchString(r.Logic.Value) {
return Rule{}, errors.Wrap(svcerr.ErrMalformedEntity, ErrPanicNotAllowed)
}
r.UpdatedAt = time.Now().UTC()
r.UpdatedBy = session.UserID
rule, err := re.repo.UpdateRule(ctx, r)
if err != nil {
return Rule{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return rule, nil
}
func (re *re) UpdateRuleTags(ctx context.Context, session authn.Session, r Rule) (Rule, error) {
r.UpdatedAt = time.Now().UTC()
r.UpdatedBy = session.UserID
rule, err := re.repo.UpdateRuleTags(ctx, r)
if err != nil {
return Rule{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return rule, nil
}
func (re *re) UpdateRuleSchedule(ctx context.Context, session authn.Session, r Rule) (Rule, error) {
r.UpdatedAt = time.Now().UTC()
r.UpdatedBy = session.UserID
rule, err := re.repo.UpdateRuleSchedule(ctx, r)
if err != nil {
return Rule{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return rule, nil
}
func (re *re) ListRules(ctx context.Context, session authn.Session, pm PageMeta) (Page, error) {
pm.Domain = session.DomainID
if session.SuperAdmin {
page, err := re.repo.ListAllRules(ctx, pm)
if err != nil {
return Page{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
return page, nil
}
page, err := re.repo.ListUserRules(ctx, session.UserID, pm)
if err != nil {
return Page{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
return page, nil
}
func (re *re) RemoveRule(ctx context.Context, session authn.Session, id string) error {
if err := re.repo.RemoveRule(ctx, id); err != nil {
return errors.Wrap(svcerr.ErrRemoveEntity, err)
}
return nil
}
func (re *re) EnableRule(ctx context.Context, session authn.Session, id string) (Rule, error) {
status, err := ToStatus(Enabled)
if err != nil {
return Rule{}, err
}
r := Rule{
ID: id,
UpdatedAt: time.Now().UTC(),
UpdatedBy: session.UserID,
Status: status,
}
rule, err := re.repo.UpdateRuleStatus(ctx, r)
if err != nil {
return Rule{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return rule, nil
}
func (re *re) DisableRule(ctx context.Context, session authn.Session, id string) (Rule, error) {
status, err := ToStatus(Disabled)
if err != nil {
return Rule{}, err
}
r := Rule{
ID: id,
UpdatedAt: time.Now().UTC(),
UpdatedBy: session.UserID,
Status: status,
}
rule, err := re.repo.UpdateRuleStatus(ctx, r)
if err != nil {
return Rule{}, errors.Wrap(svcerr.ErrUpdateEntity, err)
}
return rule, nil
}
func (re *re) Cancel() error {
return nil
}