3
0

Implement actionlog for applications

This commit is contained in:
Denis Arh 2020-05-26 08:40:01 +02:00
parent e8b81396ef
commit 84bb75e6f7
4 changed files with 1006 additions and 61 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/titpetric/factory"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/eventbus"
"github.com/cortezaproject/corteza-server/pkg/permissions"
"github.com/cortezaproject/corteza-server/pkg/rh"
@ -21,6 +22,8 @@ type (
ac applicationAccessController
eventbus eventDispatcher
actionlog actionlog.Recorder
application repository.ApplicationRepository
}
@ -64,71 +67,111 @@ func (svc *application) With(ctx context.Context) ApplicationService {
ac: svc.ac,
eventbus: svc.eventbus,
actionlog: DefaultActionlog,
application: repository.Application(ctx, db),
}
}
func (svc *application) FindByID(ID uint64) (app *types.Application, err error) {
if ID == 0 {
return nil, ErrInvalidID.withStack()
}
var (
aaProps = &applicationActionProps{application: &types.Application{ID: ID}}
)
if app, err = svc.application.FindByID(ID); err != nil {
return nil, err
}
err = svc.db.Transaction(func() error {
if ID == 0 {
return ApplicationErrInvalidID()
}
if !svc.ac.CanReadApplication(svc.ctx, app) {
return nil, ErrNoPermissions.withStack()
}
if app, err = svc.application.FindByID(ID); err != nil {
return ApplicationErrInvalidID().Wrap(err)
}
return app, nil
aaProps.setApplication(app)
if !svc.ac.CanReadApplication(svc.ctx, app) {
return ApplicationErrNotAllowedToRead()
}
return nil
})
return app, svc.recordAction(svc.ctx, aaProps, ApplicationActionLookup, err)
}
func (svc *application) Find(f types.ApplicationFilter) (types.ApplicationSet, types.ApplicationFilter, error) {
f.IsReadable = svc.ac.FilterReadableApplications(svc.ctx)
func (svc *application) Find(filter types.ApplicationFilter) (aa types.ApplicationSet, f types.ApplicationFilter, err error) {
var (
aaProps = &applicationActionProps{filter: &filter}
)
if f.Deleted > rh.FilterStateExcluded {
// If list with deleted applications is requested
// user must have access permissions to system (ie: is admin)
//
// not the best solution but ATM it allows us to have at least
// some kind of control over who can see deleted applications
if !svc.ac.CanAccess(svc.ctx) {
return nil, f, ErrNoPermissions.withStack()
err = svc.db.Transaction(func() error {
filter.IsReadable = svc.ac.FilterReadableApplications(svc.ctx)
if filter.Deleted > rh.FilterStateExcluded {
// If list with deleted applications is requested
// user must have access permissions to system (ie: is admin)
//
// not the best solution but ATM it allows us to have at least
// some kind of control over who can see deleted applications
if !svc.ac.CanAccess(svc.ctx) {
return ApplicationErrNotAllowedToListApplications()
}
}
}
return svc.application.Find(f)
aa, f, err = svc.application.Find(filter)
return err
})
return aa, f, svc.recordAction(svc.ctx, aaProps, ApplicationActionSearch, err)
}
func (svc *application) Create(new *types.Application) (app *types.Application, err error) {
if !svc.ac.CanCreateApplication(svc.ctx) {
return nil, ErrNoPermissions.withStack()
}
var (
aaProps = &applicationActionProps{new: new}
)
if err = svc.eventbus.WaitFor(svc.ctx, event.ApplicationBeforeCreate(new, nil)); err != nil {
return
}
err = svc.db.Transaction(func() (err error) {
if !svc.ac.CanCreateApplication(svc.ctx) {
return ApplicationErrNotAllowedToCreate()
}
if app, err = svc.application.Create(new); err != nil {
return
}
if err = svc.eventbus.WaitFor(svc.ctx, event.ApplicationBeforeCreate(new, nil)); err != nil {
return
}
defer svc.eventbus.Dispatch(svc.ctx, event.ApplicationAfterCreate(new, nil))
return
if app, err = svc.application.Create(new); err != nil {
return
}
aaProps.setApplication(app)
defer svc.eventbus.Dispatch(svc.ctx, event.ApplicationAfterCreate(new, nil))
return nil
})
return app, svc.recordAction(svc.ctx, aaProps, ApplicationActionCreate, err)
}
func (svc *application) Update(upd *types.Application) (app *types.Application, err error) {
if !svc.ac.CanUpdateApplication(svc.ctx, upd) {
return nil, ErrNoPermissions.withStack()
}
var (
aaProps = &applicationActionProps{update: upd}
)
err = svc.db.Transaction(func() (err error) {
if upd.ID == 0 {
return ApplicationErrInvalidID()
}
return app, svc.db.Transaction(func() (err error) {
if app, err = svc.application.FindByID(upd.ID); err != nil {
return
}
aaProps.setApplication(app)
if !svc.ac.CanUpdateApplication(svc.ctx, app) {
return ApplicationErrNotAllowedToUpdate()
}
if err = svc.eventbus.WaitFor(svc.ctx, event.ApplicationBeforeUpdate(upd, app)); err != nil {
return
}
@ -145,38 +188,76 @@ func (svc *application) Update(upd *types.Application) (app *types.Application,
defer svc.eventbus.Dispatch(svc.ctx, event.ApplicationAfterUpdate(upd, app))
return nil
})
return app, svc.recordAction(svc.ctx, aaProps, ApplicationActionUpdate, err)
}
func (svc *application) Delete(ID uint64) (err error) {
var (
app *types.Application
aaProps = &applicationActionProps{}
app *types.Application
)
if app, err = svc.application.FindByID(ID); err != nil {
return
}
err = svc.db.Transaction(func() (err error) {
if ID == 0 {
return ApplicationErrInvalidID()
}
if !svc.ac.CanDeleteApplication(svc.ctx, app) {
return ErrNoPermissions.withStack()
}
if err = svc.eventbus.WaitFor(svc.ctx, event.ApplicationBeforeDelete(nil, app)); err != nil {
return
}
if app, err = svc.application.FindByID(ID); err != nil {
return
}
if err = svc.application.DeleteByID(ID); err != nil {
return
}
if !svc.ac.CanDeleteApplication(svc.ctx, app) {
return ApplicationErrNotAllowedToDelete()
}
defer svc.eventbus.Dispatch(svc.ctx, event.ApplicationAfterDelete(nil, app))
return
if err = svc.eventbus.WaitFor(svc.ctx, event.ApplicationBeforeDelete(nil, app)); err != nil {
return
}
if err = svc.application.DeleteByID(ID); err != nil {
return
}
defer svc.eventbus.Dispatch(svc.ctx, event.ApplicationAfterDelete(nil, app))
return nil
})
return svc.recordAction(svc.ctx, aaProps, ApplicationActionDelete, err)
}
func (svc *application) Undelete(ID uint64) error {
app := &types.Application{ID: ID}
func (svc *application) Undelete(ID uint64) (err error) {
var (
aaProps = &applicationActionProps{}
app *types.Application
)
if !svc.ac.CanDeleteApplication(svc.ctx, app) {
return ErrNoPermissions.withStack()
}
err = svc.db.Transaction(func() (err error) {
if ID == 0 {
return ApplicationErrInvalidID()
}
return svc.application.UndeleteByID(ID)
if app, err = svc.application.FindByID(ID); err != nil {
return
}
if !svc.ac.CanDeleteApplication(svc.ctx, app) {
return ApplicationErrNotAllowedToUndelete()
}
// @todo add event
// if err = svc.eventbus.WaitFor(svc.ctx, event.ApplicationBeforeUndelete(nil, app)); err != nil {
// return
// }
if err = svc.application.UndeleteByID(ID); err != nil {
return
}
// @todo add event
// defer svc.eventbus.Dispatch(svc.ctx, event.ApplicationAfterUndelete(nil, app))
return nil
})
return svc.recordAction(svc.ctx, aaProps, ApplicationActionDelete, err)
}

View File

@ -0,0 +1,783 @@
package service
// This file is auto-generated from system/service/application_actions.yaml
//
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/system/types"
)
type (
applicationActionProps struct {
application *types.Application
new *types.Application
update *types.Application
filter *types.ApplicationFilter
}
applicationAction struct {
timestamp time.Time
resource string
action string
log string
severity actionlog.Severity
// prefix for error when action fails
errorMessage string
props *applicationActionProps
}
applicationError struct {
timestamp time.Time
error string
resource string
action string
message string
log string
severity actionlog.Severity
wrap error
props *applicationActionProps
}
)
// *********************************************************************************************************************
// *********************************************************************************************************************
// Props methods
// setApplication updates applicationActionProps's application
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *applicationActionProps) setApplication(application *types.Application) *applicationActionProps {
p.application = application
return p
}
// setNew updates applicationActionProps's new
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *applicationActionProps) setNew(new *types.Application) *applicationActionProps {
p.new = new
return p
}
// setUpdate updates applicationActionProps's update
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *applicationActionProps) setUpdate(update *types.Application) *applicationActionProps {
p.update = update
return p
}
// setFilter updates applicationActionProps's filter
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *applicationActionProps) setFilter(filter *types.ApplicationFilter) *applicationActionProps {
p.filter = filter
return p
}
// serialize converts applicationActionProps to actionlog.Meta
//
// This function is auto-generated.
//
func (p applicationActionProps) serialize() actionlog.Meta {
var (
m = make(actionlog.Meta)
str = func(i interface{}) string { return fmt.Sprintf("%v", i) }
)
if p.application != nil {
m["application.name"] = str(p.application.Name)
m["application.ID"] = str(p.application.ID)
}
if p.new != nil {
m["new.name"] = str(p.new.Name)
m["new.ID"] = str(p.new.ID)
}
if p.update != nil {
m["update.name"] = str(p.update.Name)
m["update.ID"] = str(p.update.ID)
}
if p.filter != nil {
m["filter.query"] = str(p.filter.Query)
m["filter.name"] = str(p.filter.Name)
m["filter.deleted"] = str(p.filter.Deleted)
m["filter.sort"] = str(p.filter.Sort)
}
return m
}
// tr translates string and replaces meta value placeholder with values
//
// This function is auto-generated.
//
func (p applicationActionProps) tr(in string, err error) string {
var pairs = []string{"{err}"}
if err != nil {
for {
// Unwrap errors
ue := errors.Unwrap(err)
if ue == nil {
break
}
err = ue
}
pairs = append(pairs, err.Error())
} else {
pairs = append(pairs, "nil")
}
if p.application != nil {
pairs = append(pairs, "{application}", fmt.Sprintf("%v", p.application.Name))
pairs = append(pairs, "{application.name}", fmt.Sprintf("%v", p.application.Name))
pairs = append(pairs, "{application.ID}", fmt.Sprintf("%v", p.application.ID))
}
if p.new != nil {
pairs = append(pairs, "{new}", fmt.Sprintf("%v", p.new.Name))
pairs = append(pairs, "{new.name}", fmt.Sprintf("%v", p.new.Name))
pairs = append(pairs, "{new.ID}", fmt.Sprintf("%v", p.new.ID))
}
if p.update != nil {
pairs = append(pairs, "{update}", fmt.Sprintf("%v", p.update.Name))
pairs = append(pairs, "{update.name}", fmt.Sprintf("%v", p.update.Name))
pairs = append(pairs, "{update.ID}", fmt.Sprintf("%v", p.update.ID))
}
if p.filter != nil {
pairs = append(pairs, "{filter}", fmt.Sprintf("%v", p.filter.Query))
pairs = append(pairs, "{filter.query}", fmt.Sprintf("%v", p.filter.Query))
pairs = append(pairs, "{filter.name}", fmt.Sprintf("%v", p.filter.Name))
pairs = append(pairs, "{filter.deleted}", fmt.Sprintf("%v", p.filter.Deleted))
pairs = append(pairs, "{filter.sort}", fmt.Sprintf("%v", p.filter.Sort))
}
return strings.NewReplacer(pairs...).Replace(in)
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Action methods
// String returns loggable description as string
//
// This function is auto-generated.
//
func (a *applicationAction) String() string {
var props = &applicationActionProps{}
if a.props != nil {
props = a.props
}
return props.tr(a.log, nil)
}
func (e *applicationAction) LoggableAction() *actionlog.Action {
return &actionlog.Action{
Timestamp: e.timestamp,
Resource: e.resource,
Action: e.action,
Severity: e.severity,
Description: e.String(),
Meta: e.props.serialize(),
}
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Error methods
// String returns loggable description as string
//
// It falls back to message if log is not set
//
// This function is auto-generated.
//
func (e *applicationError) String() string {
var props = &applicationActionProps{}
if e.props != nil {
props = e.props
}
if e.wrap != nil && !strings.Contains(e.log, "{err}") {
// Suffix error log with {err} to ensure
// we log the cause for this error
e.log += ": {err}"
}
return props.tr(e.log, e.wrap)
}
// Error satisfies
//
// This function is auto-generated.
//
func (e *applicationError) Error() string {
var props = &applicationActionProps{}
if e.props != nil {
props = e.props
}
return props.tr(e.message, e.wrap)
}
// Is fn for error equality check
//
// This function is auto-generated.
//
func (e *applicationError) Is(Resource error) bool {
t, ok := Resource.(*applicationError)
if !ok {
return false
}
return t.resource == e.resource && t.error == e.error
}
// Wrap wraps applicationError around another error
//
// This function is auto-generated.
//
func (e *applicationError) Wrap(err error) *applicationError {
e.wrap = err
return e
}
// Unwrap returns wrapped error
//
// This function is auto-generated.
//
func (e *applicationError) Unwrap() error {
return e.wrap
}
func (e *applicationError) LoggableAction() *actionlog.Action {
return &actionlog.Action{
Timestamp: e.timestamp,
Resource: e.resource,
Action: e.action,
Severity: e.severity,
Description: e.String(),
Error: e.Error(),
Meta: e.props.serialize(),
}
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Action constructors
// ApplicationActionSearch returns "system:application.search" error
//
// This function is auto-generated.
//
func ApplicationActionSearch(props ...*applicationActionProps) *applicationAction {
a := &applicationAction{
timestamp: time.Now(),
resource: "system:application",
action: "search",
log: "searched for applications",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// ApplicationActionLookup returns "system:application.lookup" error
//
// This function is auto-generated.
//
func ApplicationActionLookup(props ...*applicationActionProps) *applicationAction {
a := &applicationAction{
timestamp: time.Now(),
resource: "system:application",
action: "lookup",
log: "looked-up for a {application}",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// ApplicationActionCreate returns "system:application.create" error
//
// This function is auto-generated.
//
func ApplicationActionCreate(props ...*applicationActionProps) *applicationAction {
a := &applicationAction{
timestamp: time.Now(),
resource: "system:application",
action: "create",
log: "created {application}",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// ApplicationActionUpdate returns "system:application.update" error
//
// This function is auto-generated.
//
func ApplicationActionUpdate(props ...*applicationActionProps) *applicationAction {
a := &applicationAction{
timestamp: time.Now(),
resource: "system:application",
action: "update",
log: "updated {application}",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// ApplicationActionDelete returns "system:application.delete" error
//
// This function is auto-generated.
//
func ApplicationActionDelete(props ...*applicationActionProps) *applicationAction {
a := &applicationAction{
timestamp: time.Now(),
resource: "system:application",
action: "delete",
log: "deleted {application}",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// ApplicationActionUndelete returns "system:application.undelete" error
//
// This function is auto-generated.
//
func ApplicationActionUndelete(props ...*applicationActionProps) *applicationAction {
a := &applicationAction{
timestamp: time.Now(),
resource: "system:application",
action: "undelete",
log: "undeleted {application}",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Error constructors
// ApplicationErrGeneric returns "system:application.generic" audit event as actionlog.Error
//
//
// This function is auto-generated.
//
func ApplicationErrGeneric(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "generic",
action: "error",
message: "failed to complete request due to internal error",
log: "{err}",
severity: actionlog.Error,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrNonexistent returns "system:application.nonexistent" audit event as actionlog.Warning
//
//
// This function is auto-generated.
//
func ApplicationErrNonexistent(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "nonexistent",
action: "error",
message: "application does not exist",
log: "application does not exist",
severity: actionlog.Warning,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrInvalidID returns "system:application.invalidID" audit event as actionlog.Warning
//
//
// This function is auto-generated.
//
func ApplicationErrInvalidID(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "invalidID",
action: "error",
message: "invalid ID",
log: "invalid ID",
severity: actionlog.Warning,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrNotAllowedToRead returns "system:application.notAllowedToRead" audit event as actionlog.Error
//
//
// This function is auto-generated.
//
func ApplicationErrNotAllowedToRead(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "notAllowedToRead",
action: "error",
message: "not allowed to read application",
log: "failed to read {application.name}; insufficient permissions",
severity: actionlog.Error,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrNotAllowedToListApplications returns "system:application.notAllowedToListApplications" audit event as actionlog.Error
//
//
// This function is auto-generated.
//
func ApplicationErrNotAllowedToListApplications(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "notAllowedToListApplications",
action: "error",
message: "not allowed to list applications",
log: "failed to list application; insufficient permissions",
severity: actionlog.Error,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrNotAllowedToCreate returns "system:application.notAllowedToCreate" audit event as actionlog.Error
//
//
// This function is auto-generated.
//
func ApplicationErrNotAllowedToCreate(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "notAllowedToCreate",
action: "error",
message: "not allowed to create application",
log: "failed to create application; insufficient permissions",
severity: actionlog.Error,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrNotAllowedToUpdate returns "system:application.notAllowedToUpdate" audit event as actionlog.Error
//
//
// This function is auto-generated.
//
func ApplicationErrNotAllowedToUpdate(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "notAllowedToUpdate",
action: "error",
message: "not allowed to update application",
log: "failed to update {application.name}; insufficient permissions",
severity: actionlog.Error,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrNotAllowedToDelete returns "system:application.notAllowedToDelete" audit event as actionlog.Error
//
//
// This function is auto-generated.
//
func ApplicationErrNotAllowedToDelete(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "notAllowedToDelete",
action: "error",
message: "not allowed to delete application",
log: "failed to delete {application.name}; insufficient permissions",
severity: actionlog.Error,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// ApplicationErrNotAllowedToUndelete returns "system:application.notAllowedToUndelete" audit event as actionlog.Error
//
//
// This function is auto-generated.
//
func ApplicationErrNotAllowedToUndelete(props ...*applicationActionProps) *applicationError {
var e = &applicationError{
timestamp: time.Now(),
resource: "system:application",
error: "notAllowedToUndelete",
action: "error",
message: "not allowed to undelete application",
log: "failed to undelete {application.name}; insufficient permissions",
severity: actionlog.Error,
props: func() *applicationActionProps {
if len(props) > 0 {
return props[0]
}
return nil
}(),
}
if len(props) > 0 {
e.props = props[0]
}
return e
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// recordAction is a service helper function wraps function that can return error
//
// context is used to enrich audit log entry with current user info, request ID, IP address...
// props are collected action/error properties
// action (optional) fn will be used to construct applicationAction struct from given props (and error)
// err is any error that occurred while action was happening
//
// Action has success and fail (error) state:
// - when recorded without an error (4th param), action is recorded as successful.
// - when an additional error is given (4th param), action is used to wrap
// the additional error
//
// This function is auto-generated.
//
func (svc application) recordAction(ctx context.Context, props *applicationActionProps, action func(...*applicationActionProps) *applicationAction, err error) error {
var (
ok bool
// Return error
retError *applicationError
// Recorder error
recError *applicationError
)
if err != nil {
if retError, ok = err.(*applicationError); !ok {
// got non-application error, wrap it with ApplicationErrGeneric
retError = ApplicationErrGeneric(props).Wrap(err)
// copy action to returning and recording error
retError.action = action().action
// we'll use ApplicationErrGeneric for recording too
// because it can hold more info
recError = retError
} else if retError != nil {
// copy action to returning and recording error
retError.action = action().action
// start with copy of return error for recording
// this will be updated with tha root cause as we try and
// unwrap the error
recError = retError
// find the original recError for this error
// for the purpose of logging
var unwrappedError error = retError
for {
if unwrappedError = errors.Unwrap(unwrappedError); unwrappedError == nil {
// nothing wrapped
break
}
// update recError ONLY of wrapped error is of type applicationError
if unwrappedSinkError, ok := unwrappedError.(*applicationError); ok {
recError = unwrappedSinkError
}
}
if retError.props == nil {
// set props on returning error if empty
retError.props = props
}
if recError.props == nil {
// set props on recording error if empty
recError.props = props
}
}
}
if svc.actionlog != nil {
if retError != nil {
// failed action, log error
svc.actionlog.Record(ctx, recError)
} else if action != nil {
// successful
svc.actionlog.Record(ctx, action(props))
}
}
if err == nil {
// retError not an interface and that WILL (!!) cause issues
// with nil check (== nil) when it is not explicitly returned
return nil
}
return retError
}

View File

@ -0,0 +1,81 @@
# List of loggable service actions
resource: system:application
service: application
# Default sensitivity for actions
defaultActionSeverity: info
# default severity for errors
defaultErrorSeverity: error
import:
- github.com/cortezaproject/corteza-server/system/types
props:
- name: application
type: "*types.Application"
fields: [ name, ID ]
- name: new
type: "*types.Application"
fields: [ name, ID ]
- name: update
type: "*types.Application"
fields: [ name, ID ]
- name: filter
type: "*types.ApplicationFilter"
fields: [ query, name, deleted, sort ]
actions:
- action: search
log: "searched for applications"
severity: info
- action: lookup
log: "looked-up for a {application}"
severity: info
- action: create
log: "created {application}"
- action: update
log: "updated {application}"
- action: delete
log: "deleted {application}"
- action: undelete
log: "undeleted {application}"
errors:
- error: nonexistent
message: "application does not exist"
severity: warning
- error: invalidID
message: "invalid ID"
severity: warning
- error: notAllowedToRead
message: "not allowed to read application"
log: "failed to read {application.name}; insufficient permissions"
- error: notAllowedToListApplications
message: "not allowed to list applications"
log: "failed to list application; insufficient permissions"
- error: notAllowedToCreate
message: "not allowed to create application"
log: "failed to create application; insufficient permissions"
- error: notAllowedToUpdate
message: "not allowed to update application"
log: "failed to update {application.name}; insufficient permissions"
- error: notAllowedToDelete
message: "not allowed to delete application"
log: "failed to delete {application.name}; insufficient permissions"
- error: notAllowedToUndelete
message: "not allowed to undelete application"
log: "failed to undelete {application.name}; insufficient permissions"

View File

@ -80,7 +80,7 @@ func TestApplicationCreateForbidden(t *testing.T) {
FormData("name", "my-app").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("system.service.NoPermissions")).
Assert(helpers.AssertError("not allowed to create application")).
End()
}
@ -106,7 +106,7 @@ func TestApplicationUpdateForbidden(t *testing.T) {
FormData("name", "changed-name").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("system.service.NoPermissions")).
Assert(helpers.AssertError("not allowed to update application")).
End()
}
@ -137,7 +137,7 @@ func TestApplicationDeleteForbidden(t *testing.T) {
Delete(fmt.Sprintf("/application/%d", a.ID)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("system.service.NoPermissions")).
Assert(helpers.AssertError("not allowed to delete application")).
End()
}