From ebb9b70bfe3d5eb5b147caf9d571567e47a667a3 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Sun, 29 Dec 2019 07:25:26 +0100 Subject: [PATCH] Add REST API endpoints for manual automation script triggering --- api/compose/spec.json | 147 ++++++++++++++++++++++++++ api/compose/spec/automation.json | 57 ++++++++++ api/compose/spec/module.json | 24 +++++ api/compose/spec/namespace.json | 24 +++++ api/compose/spec/page.json | 24 +++++ api/compose/spec/record.json | 24 +++++ api/system/spec.json | 123 ++++++++++++++++++++++ api/system/spec/application.json | 24 +++++ api/system/spec/automation.json | 57 ++++++++++ api/system/spec/role.json | 24 +++++ api/system/spec/user.json | 24 +++++ compose/rest/automation.go | 41 ++++++++ compose/rest/handlers/automation.go | 93 ++++++++++++++++ compose/rest/handlers/module.go | 33 +++++- compose/rest/handlers/namespace.go | 33 +++++- compose/rest/handlers/page.go | 39 +++++-- compose/rest/handlers/record.go | 23 ++++ compose/rest/handlers/trigger.go | 93 ++++++++++++++++ compose/rest/module.go | 29 ++++- compose/rest/namespace.go | 14 +++ compose/rest/page.go | 20 ++++ compose/rest/record.go | 26 +++++ compose/rest/request/automation.go | 158 ++++++++++++++++++++++++++++ compose/rest/request/module.go | 59 +++++++++++ compose/rest/request/namespace.go | 56 ++++++++++ compose/rest/request/page.go | 59 +++++++++++ compose/rest/request/record.go | 62 +++++++++++ compose/rest/request/trigger.go | 150 ++++++++++++++++++++++++++ compose/rest/router.go | 2 + docs/compose/README.md | 115 ++++++++++++++++++++ docs/system/README.md | 95 +++++++++++++++++ system/rest/application.go | 14 +++ system/rest/automation.go | 40 +++++++ system/rest/handlers/application.go | 35 ++++-- system/rest/handlers/automation.go | 93 ++++++++++++++++ system/rest/handlers/role.go | 23 ++++ system/rest/handlers/trigger.go | 93 ++++++++++++++++ system/rest/handlers/user.go | 23 ++++ system/rest/request/application.go | 56 ++++++++++ system/rest/request/automation.go | 158 ++++++++++++++++++++++++++++ system/rest/request/role.go | 56 ++++++++++ system/rest/request/trigger.go | 150 ++++++++++++++++++++++++++ system/rest/request/user.go | 56 ++++++++++ system/rest/role.go | 14 +++ system/rest/router.go | 1 + system/rest/user.go | 14 +++ system/service/event/auth.gen.go | 29 ----- system/service/event/events.yaml | 3 +- system/service/event/mail.gen.go | 27 +++++ 49 files changed, 2578 insertions(+), 59 deletions(-) create mode 100644 api/compose/spec/automation.json create mode 100644 api/system/spec/automation.json create mode 100644 compose/rest/automation.go create mode 100644 compose/rest/handlers/automation.go create mode 100644 compose/rest/handlers/trigger.go create mode 100644 compose/rest/request/automation.go create mode 100644 compose/rest/request/trigger.go create mode 100644 system/rest/automation.go create mode 100644 system/rest/handlers/automation.go create mode 100644 system/rest/handlers/trigger.go create mode 100644 system/rest/request/automation.go create mode 100644 system/rest/request/trigger.go diff --git a/api/compose/spec.json b/api/compose/spec.json index 7b74d21d1..204004c25 100644 --- a/api/compose/spec.json +++ b/api/compose/spec.json @@ -167,6 +167,30 @@ } ] } + }, + { + "name": "fireTrigger", + "method": "POST", + "title": "Fire compose:namespace trigger", + "path": "/{namespaceID}/trigger", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "namespaceID", + "required": true, + "title": "ID" + } + ], + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, @@ -438,6 +462,30 @@ } ] } + }, + { + "name": "fireTrigger", + "method": "POST", + "title": "Fire compose:page trigger", + "path": "/{pageID}/trigger", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "pageID", + "required": true, + "title": "Page ID" + } + ], + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, @@ -626,6 +674,30 @@ } ] } + }, + { + "name": "fireTrigger", + "method": "POST", + "title": "Fire compose:module trigger", + "path": "/{moduleID}/trigger", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "moduleID", + "required": true, + "title": "ID" + } + ], + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, @@ -942,6 +1014,30 @@ } ] } + }, + { + "name": "trigger", + "method": "POST", + "title": "Fire compose:record trigger", + "path": "/{recordID}/trigger", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "recordID", + "required": true, + "title": "ID" + } + ], + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, @@ -1510,5 +1606,56 @@ "path": "/current" } ] + }, + { + "title": "Compose automation scripts", + "path": "/automation", + "entrypoint": "automation", + "apis": [ + { + "name": "list", + "method": "GET", + "title": "List all available automation scripts for compose resources", + "path": "/", + "parameters": { + "get": [ + { + "name": "resourceTypes", + "type": "[]string", + "title": "Filter by resource type" + }, + { + "name": "eventTypes", + "type": "[]string", + "title": "Filter by event type" + }, + { + "name": "excludeClientScripts", + "type": "bool", + "title": "Do not include client scripts" + }, + { + "name": "excludeServerScripts", + "type": "bool", + "title": "Do not include server scripts" + } + ] + } + }, + { + "name": "trigger", + "method": "POST", + "title": "Triggers execution of a specific script on a system service level", + "path": "/trigger", + "parameters": { + "post": [{ + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + }] + } + } + ] } ] diff --git a/api/compose/spec/automation.json b/api/compose/spec/automation.json new file mode 100644 index 000000000..f64bf958e --- /dev/null +++ b/api/compose/spec/automation.json @@ -0,0 +1,57 @@ +{ + "Title": "Compose automation scripts", + "Interface": "Automation", + "Struct": null, + "Parameters": null, + "Protocol": "", + "Authentication": null, + "Path": "/automation", + "APIs": [ + { + "Name": "list", + "Method": "GET", + "Title": "List all available automation scripts for compose resources", + "Path": "/", + "Parameters": { + "get": [ + { + "name": "resourceTypes", + "title": "Filter by resource type", + "type": "[]string" + }, + { + "name": "eventTypes", + "title": "Filter by event type", + "type": "[]string" + }, + { + "name": "excludeClientScripts", + "title": "Do not include client scripts", + "type": "bool" + }, + { + "name": "excludeServerScripts", + "title": "Do not include server scripts", + "type": "bool" + } + ] + } + }, + { + "Name": "trigger", + "Method": "POST", + "Title": "Triggers execution of a specific script on a system service level", + "Path": "/trigger", + "Parameters": { + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/api/compose/spec/module.json b/api/compose/spec/module.json index a289b7c8b..3f1c55d7f 100644 --- a/api/compose/spec/module.json +++ b/api/compose/spec/module.json @@ -184,6 +184,30 @@ } ] } + }, + { + "Name": "fireTrigger", + "Method": "POST", + "Title": "Fire compose:module trigger", + "Path": "/{moduleID}/trigger", + "Parameters": { + "path": [ + { + "name": "moduleID", + "required": true, + "title": "ID", + "type": "uint64" + } + ], + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/api/compose/spec/namespace.json b/api/compose/spec/namespace.json index 12802d39d..43c3f046b 100644 --- a/api/compose/spec/namespace.json +++ b/api/compose/spec/namespace.json @@ -167,6 +167,30 @@ } ] } + }, + { + "Name": "fireTrigger", + "Method": "POST", + "Title": "Fire compose:namespace trigger", + "Path": "/{namespaceID}/trigger", + "Parameters": { + "path": [ + { + "name": "namespaceID", + "required": true, + "title": "ID", + "type": "uint64" + } + ], + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/api/compose/spec/page.json b/api/compose/spec/page.json index b062987ca..bb67d9b52 100644 --- a/api/compose/spec/page.json +++ b/api/compose/spec/page.json @@ -267,6 +267,30 @@ } ] } + }, + { + "Name": "fireTrigger", + "Method": "POST", + "Title": "Fire compose:page trigger", + "Path": "/{pageID}/trigger", + "Parameters": { + "path": [ + { + "name": "pageID", + "required": true, + "title": "Page ID", + "type": "uint64" + } + ], + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/api/compose/spec/record.json b/api/compose/spec/record.json index 43f95e228..7eb38591e 100644 --- a/api/compose/spec/record.json +++ b/api/compose/spec/record.json @@ -312,6 +312,30 @@ } ] } + }, + { + "Name": "trigger", + "Method": "POST", + "Title": "Fire compose:record trigger", + "Path": "/{recordID}/trigger", + "Parameters": { + "path": [ + { + "name": "recordID", + "required": true, + "title": "ID", + "type": "uint64" + } + ], + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/api/system/spec.json b/api/system/spec.json index de459226d..8941c5930 100644 --- a/api/system/spec.json +++ b/api/system/spec.json @@ -716,6 +716,30 @@ } ] } + }, + { + "name": "fireTrigger", + "method": "POST", + "title": "Fire system:role trigger", + "path": "/{roleID}/trigger", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "roleID", + "required": true, + "title": "ID" + } + ], + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, @@ -1069,6 +1093,30 @@ } ] } + }, + { + "name": "fireTrigger", + "method": "POST", + "title": "Fire system:user trigger", + "path": "/{userID}/trigger", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "userID", + "required": true, + "title": "ID" + } + ], + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, @@ -1254,6 +1302,30 @@ } ] } + }, + { + "name": "fireTrigger", + "method": "POST", + "title": "Fire system:application trigger", + "path": "/{applicationID}/trigger", + "parameters": { + "path": [ + { + "type": "uint64", + "name": "applicationID", + "required": true, + "title": "ID" + } + ], + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, @@ -1609,5 +1681,56 @@ "parameters": {} } ] + }, + { + "title": "System automation scripts", + "path": "/automation", + "entrypoint": "automation", + "apis": [ + { + "name": "list", + "method": "GET", + "title": "List all available automation scripts for system resources", + "path": "/", + "parameters": { + "get": [ + { + "name": "resourceTypes", + "type": "[]string", + "title": "Filter by resource type" + }, + { + "name": "eventTypes", + "type": "[]string", + "title": "Filter by event type" + }, + { + "name": "excludeClientScripts", + "type": "bool", + "title": "Do not include client scripts" + }, + { + "name": "excludeServerScripts", + "type": "bool", + "title": "Do not include server scripts" + } + ] + } + }, + { + "name": "trigger", + "method": "POST", + "title": "Triggers execution of a specific script on a system service level", + "path": "/trigger", + "parameters": { + "post": [{ + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + }] + } + } + ] } ] diff --git a/api/system/spec/application.json b/api/system/spec/application.json index 8ea633496..b40287467 100644 --- a/api/system/spec/application.json +++ b/api/system/spec/application.json @@ -182,6 +182,30 @@ } ] } + }, + { + "Name": "fireTrigger", + "Method": "POST", + "Title": "Fire system:application trigger", + "Path": "/{applicationID}/trigger", + "Parameters": { + "path": [ + { + "name": "applicationID", + "required": true, + "title": "ID", + "type": "uint64" + } + ], + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/api/system/spec/automation.json b/api/system/spec/automation.json new file mode 100644 index 000000000..be991e39c --- /dev/null +++ b/api/system/spec/automation.json @@ -0,0 +1,57 @@ +{ + "Title": "System automation scripts", + "Interface": "Automation", + "Struct": null, + "Parameters": null, + "Protocol": "", + "Authentication": null, + "Path": "/automation", + "APIs": [ + { + "Name": "list", + "Method": "GET", + "Title": "List all available automation scripts for system resources", + "Path": "/", + "Parameters": { + "get": [ + { + "name": "resourceTypes", + "title": "Filter by resource type", + "type": "[]string" + }, + { + "name": "eventTypes", + "title": "Filter by event type", + "type": "[]string" + }, + { + "name": "excludeClientScripts", + "title": "Do not include client scripts", + "type": "bool" + }, + { + "name": "excludeServerScripts", + "title": "Do not include server scripts", + "type": "bool" + } + ] + } + }, + { + "Name": "trigger", + "Method": "POST", + "Title": "Triggers execution of a specific script on a system service level", + "Path": "/trigger", + "Parameters": { + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/api/system/spec/role.json b/api/system/spec/role.json index 74f32ba02..8d295873f 100644 --- a/api/system/spec/role.json +++ b/api/system/spec/role.json @@ -308,6 +308,30 @@ } ] } + }, + { + "Name": "fireTrigger", + "Method": "POST", + "Title": "Fire system:role trigger", + "Path": "/{roleID}/trigger", + "Parameters": { + "path": [ + { + "name": "roleID", + "required": true, + "title": "ID", + "type": "uint64" + } + ], + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/api/system/spec/user.json b/api/system/spec/user.json index 2dd3ca8c3..6bc81d8f6 100644 --- a/api/system/spec/user.json +++ b/api/system/spec/user.json @@ -350,6 +350,30 @@ } ] } + }, + { + "Name": "fireTrigger", + "Method": "POST", + "Title": "Fire system:user trigger", + "Path": "/{userID}/trigger", + "Parameters": { + "path": [ + { + "name": "userID", + "required": true, + "title": "ID", + "type": "uint64" + } + ], + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/compose/rest/automation.go b/compose/rest/automation.go new file mode 100644 index 000000000..c834cac5b --- /dev/null +++ b/compose/rest/automation.go @@ -0,0 +1,41 @@ +package rest + +import ( + "context" + + "github.com/pkg/errors" + "github.com/titpetric/factory/resputil" + + "github.com/cortezaproject/corteza-server/compose/rest/request" + "github.com/cortezaproject/corteza-server/compose/service/event" + "github.com/cortezaproject/corteza-server/pkg/corredor" +) + +var _ = errors.Wrap + +type Automation struct { + // xxx service.XXXService +} + +func (Automation) New() *Automation { + return &Automation{} +} + +func (ctrl *Automation) List(ctx context.Context, r *request.AutomationList) (interface{}, error) { + f := corredor.ManualScriptFilter{ + ResourceTypes: r.ResourceTypes, + EventTypes: r.EventTypes, + ExcludeServerScripts: r.ExcludeServerScripts, + ExcludeClientScripts: r.ExcludeClientScripts, + } + + f.PrefixResource("compose") + + scripts, _, err := corredor.Service().FindOnManual(f) + + return scripts, err +} + +func (ctrl *Automation) Trigger(ctx context.Context, r *request.AutomationTrigger) (interface{}, error) { + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.ComposeOnManual()) +} diff --git a/compose/rest/handlers/automation.go b/compose/rest/handlers/automation.go new file mode 100644 index 000000000..0b723d407 --- /dev/null +++ b/compose/rest/handlers/automation.go @@ -0,0 +1,93 @@ +package handlers + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `automation.go`, `automation.util.go` or `automation_test.go` to + implement your API calls, helper functions and tests. The file `automation.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "context" + + "net/http" + + "github.com/go-chi/chi" + "github.com/titpetric/factory/resputil" + + "github.com/cortezaproject/corteza-server/compose/rest/request" + "github.com/cortezaproject/corteza-server/pkg/logger" +) + +// Internal API interface +type AutomationAPI interface { + List(context.Context, *request.AutomationList) (interface{}, error) + Trigger(context.Context, *request.AutomationTrigger) (interface{}, error) +} + +// HTTP API interface +type Automation struct { + List func(http.ResponseWriter, *http.Request) + Trigger func(http.ResponseWriter, *http.Request) +} + +func NewAutomation(h AutomationAPI) *Automation { + return &Automation{ + List: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewAutomationList() + if err := params.Fill(r); err != nil { + logger.LogParamError("Automation.List", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.List(r.Context(), params) + if err != nil { + logger.LogControllerError("Automation.List", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Automation.List", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + Trigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewAutomationTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Automation.Trigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.Trigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Automation.Trigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Automation.Trigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + } +} + +func (h Automation) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { + r.Group(func(r chi.Router) { + r.Use(middlewares...) + r.Get("/automation/", h.List) + r.Post("/automation/trigger", h.Trigger) + }) +} diff --git a/compose/rest/handlers/module.go b/compose/rest/handlers/module.go index 03e420c17..d52b1353a 100644 --- a/compose/rest/handlers/module.go +++ b/compose/rest/handlers/module.go @@ -34,15 +34,17 @@ type ModuleAPI interface { Read(context.Context, *request.ModuleRead) (interface{}, error) Update(context.Context, *request.ModuleUpdate) (interface{}, error) Delete(context.Context, *request.ModuleDelete) (interface{}, error) + FireTrigger(context.Context, *request.ModuleFireTrigger) (interface{}, error) } // HTTP API interface type Module struct { - List func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) - Read func(http.ResponseWriter, *http.Request) - Update func(http.ResponseWriter, *http.Request) - Delete func(http.ResponseWriter, *http.Request) + List func(http.ResponseWriter, *http.Request) + Create func(http.ResponseWriter, *http.Request) + Read func(http.ResponseWriter, *http.Request) + Update func(http.ResponseWriter, *http.Request) + Delete func(http.ResponseWriter, *http.Request) + FireTrigger func(http.ResponseWriter, *http.Request) } func NewModule(h ModuleAPI) *Module { @@ -147,6 +149,26 @@ func NewModule(h ModuleAPI) *Module { resputil.JSON(w, value) } }, + FireTrigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewModuleFireTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Module.FireTrigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.FireTrigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Module.FireTrigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Module.FireTrigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -158,5 +180,6 @@ func (h Module) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http r.Get("/namespace/{namespaceID}/module/{moduleID}", h.Read) r.Post("/namespace/{namespaceID}/module/{moduleID}", h.Update) r.Delete("/namespace/{namespaceID}/module/{moduleID}", h.Delete) + r.Post("/namespace/{namespaceID}/module/{moduleID}/trigger", h.FireTrigger) }) } diff --git a/compose/rest/handlers/namespace.go b/compose/rest/handlers/namespace.go index 588835faf..ab9de8ad5 100644 --- a/compose/rest/handlers/namespace.go +++ b/compose/rest/handlers/namespace.go @@ -34,15 +34,17 @@ type NamespaceAPI interface { Read(context.Context, *request.NamespaceRead) (interface{}, error) Update(context.Context, *request.NamespaceUpdate) (interface{}, error) Delete(context.Context, *request.NamespaceDelete) (interface{}, error) + FireTrigger(context.Context, *request.NamespaceFireTrigger) (interface{}, error) } // HTTP API interface type Namespace struct { - List func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) - Read func(http.ResponseWriter, *http.Request) - Update func(http.ResponseWriter, *http.Request) - Delete func(http.ResponseWriter, *http.Request) + List func(http.ResponseWriter, *http.Request) + Create func(http.ResponseWriter, *http.Request) + Read func(http.ResponseWriter, *http.Request) + Update func(http.ResponseWriter, *http.Request) + Delete func(http.ResponseWriter, *http.Request) + FireTrigger func(http.ResponseWriter, *http.Request) } func NewNamespace(h NamespaceAPI) *Namespace { @@ -147,6 +149,26 @@ func NewNamespace(h NamespaceAPI) *Namespace { resputil.JSON(w, value) } }, + FireTrigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewNamespaceFireTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Namespace.FireTrigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.FireTrigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Namespace.FireTrigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Namespace.FireTrigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -158,5 +180,6 @@ func (h Namespace) MountRoutes(r chi.Router, middlewares ...func(http.Handler) h r.Get("/namespace/{namespaceID}", h.Read) r.Post("/namespace/{namespaceID}", h.Update) r.Delete("/namespace/{namespaceID}", h.Delete) + r.Post("/namespace/{namespaceID}/trigger", h.FireTrigger) }) } diff --git a/compose/rest/handlers/page.go b/compose/rest/handlers/page.go index db6dd9a15..5988fcbe0 100644 --- a/compose/rest/handlers/page.go +++ b/compose/rest/handlers/page.go @@ -37,18 +37,20 @@ type PageAPI interface { Reorder(context.Context, *request.PageReorder) (interface{}, error) Delete(context.Context, *request.PageDelete) (interface{}, error) Upload(context.Context, *request.PageUpload) (interface{}, error) + FireTrigger(context.Context, *request.PageFireTrigger) (interface{}, error) } // HTTP API interface type Page struct { - List func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) - Read func(http.ResponseWriter, *http.Request) - Tree func(http.ResponseWriter, *http.Request) - Update func(http.ResponseWriter, *http.Request) - Reorder func(http.ResponseWriter, *http.Request) - Delete func(http.ResponseWriter, *http.Request) - Upload func(http.ResponseWriter, *http.Request) + List func(http.ResponseWriter, *http.Request) + Create func(http.ResponseWriter, *http.Request) + Read func(http.ResponseWriter, *http.Request) + Tree func(http.ResponseWriter, *http.Request) + Update func(http.ResponseWriter, *http.Request) + Reorder func(http.ResponseWriter, *http.Request) + Delete func(http.ResponseWriter, *http.Request) + Upload func(http.ResponseWriter, *http.Request) + FireTrigger func(http.ResponseWriter, *http.Request) } func NewPage(h PageAPI) *Page { @@ -213,6 +215,26 @@ func NewPage(h PageAPI) *Page { resputil.JSON(w, value) } }, + FireTrigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewPageFireTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Page.FireTrigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.FireTrigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Page.FireTrigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Page.FireTrigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -227,5 +249,6 @@ func (h Page) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.H r.Post("/namespace/{namespaceID}/page/{selfID}/reorder", h.Reorder) r.Delete("/namespace/{namespaceID}/page/{pageID}", h.Delete) r.Post("/namespace/{namespaceID}/page/{pageID}/attachment", h.Upload) + r.Post("/namespace/{namespaceID}/page/{pageID}/trigger", h.FireTrigger) }) } diff --git a/compose/rest/handlers/record.go b/compose/rest/handlers/record.go index 4c87bdf12..46c8d3a2c 100644 --- a/compose/rest/handlers/record.go +++ b/compose/rest/handlers/record.go @@ -41,6 +41,7 @@ type RecordAPI interface { Update(context.Context, *request.RecordUpdate) (interface{}, error) Delete(context.Context, *request.RecordDelete) (interface{}, error) Upload(context.Context, *request.RecordUpload) (interface{}, error) + Trigger(context.Context, *request.RecordTrigger) (interface{}, error) } // HTTP API interface @@ -57,6 +58,7 @@ type Record struct { Update func(http.ResponseWriter, *http.Request) Delete func(http.ResponseWriter, *http.Request) Upload func(http.ResponseWriter, *http.Request) + Trigger func(http.ResponseWriter, *http.Request) } func NewRecord(h RecordAPI) *Record { @@ -301,6 +303,26 @@ func NewRecord(h RecordAPI) *Record { resputil.JSON(w, value) } }, + Trigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewRecordTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Record.Trigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.Trigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Record.Trigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Record.Trigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -319,5 +341,6 @@ func (h Record) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http r.Post("/namespace/{namespaceID}/module/{moduleID}/record/{recordID}", h.Update) r.Delete("/namespace/{namespaceID}/module/{moduleID}/record/{recordID}", h.Delete) r.Post("/namespace/{namespaceID}/module/{moduleID}/record/attachment", h.Upload) + r.Post("/namespace/{namespaceID}/module/{moduleID}/record/{recordID}/trigger", h.Trigger) }) } diff --git a/compose/rest/handlers/trigger.go b/compose/rest/handlers/trigger.go new file mode 100644 index 000000000..e0db0db98 --- /dev/null +++ b/compose/rest/handlers/trigger.go @@ -0,0 +1,93 @@ +package handlers + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `trigger.go`, `trigger.util.go` or `trigger_test.go` to + implement your API calls, helper functions and tests. The file `trigger.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "context" + + "net/http" + + "github.com/go-chi/chi" + "github.com/titpetric/factory/resputil" + + "github.com/cortezaproject/corteza-server/compose/rest/request" + "github.com/cortezaproject/corteza-server/pkg/logger" +) + +// Internal API interface +type TriggerAPI interface { + List(context.Context, *request.TriggerList) (interface{}, error) + Fire(context.Context, *request.TriggerFire) (interface{}, error) +} + +// HTTP API interface +type Trigger struct { + List func(http.ResponseWriter, *http.Request) + Fire func(http.ResponseWriter, *http.Request) +} + +func NewTrigger(h TriggerAPI) *Trigger { + return &Trigger{ + List: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewTriggerList() + if err := params.Fill(r); err != nil { + logger.LogParamError("Trigger.List", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.List(r.Context(), params) + if err != nil { + logger.LogControllerError("Trigger.List", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Trigger.List", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + Fire: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewTriggerFire() + if err := params.Fill(r); err != nil { + logger.LogParamError("Trigger.Fire", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.Fire(r.Context(), params) + if err != nil { + logger.LogControllerError("Trigger.Fire", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Trigger.Fire", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + } +} + +func (h Trigger) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { + r.Group(func(r chi.Router) { + r.Use(middlewares...) + r.Get("/trigger/", h.List) + r.Post("/trigger/", h.Fire) + }) +} diff --git a/compose/rest/module.go b/compose/rest/module.go index 4df6112c7..ce78661d7 100644 --- a/compose/rest/module.go +++ b/compose/rest/module.go @@ -7,7 +7,9 @@ import ( "github.com/cortezaproject/corteza-server/compose/rest/request" "github.com/cortezaproject/corteza-server/compose/service" + "github.com/cortezaproject/corteza-server/compose/service/event" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/corredor" "github.com/cortezaproject/corteza-server/pkg/rh" ) @@ -41,8 +43,9 @@ type ( } Module struct { - module service.ModuleService - ac moduleAccessController + module service.ModuleService + namespace service.NamespaceService + ac moduleAccessController } moduleAccessController interface { @@ -64,8 +67,9 @@ type ( func (Module) New() *Module { return &Module{ - module: service.DefaultModule, - ac: service.DefaultAccessControl, + module: service.DefaultModule, + namespace: service.DefaultNamespace, + ac: service.DefaultAccessControl, } } @@ -132,6 +136,23 @@ func (ctrl *Module) Delete(ctx context.Context, r *request.ModuleDelete) (interf return resputil.OK(), ctrl.module.With(ctx).DeleteByID(r.NamespaceID, r.ModuleID) } +func (ctrl *Module) FireTrigger(ctx context.Context, r *request.ModuleFireTrigger) (rsp interface{}, err error) { + var ( + module *types.Module + namespace *types.Namespace + ) + + if module, err = ctrl.module.With(ctx).FindByID(r.NamespaceID, r.ModuleID); err != nil { + return + } + + if namespace, err = ctrl.namespace.With(ctx).FindByID(r.NamespaceID); err != nil { + return + } + + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.ModuleOnManual(module, nil, namespace)) +} + func (ctrl Module) makePayload(ctx context.Context, m *types.Module, err error) (*modulePayload, error) { if err != nil || m == nil { return nil, err diff --git a/compose/rest/namespace.go b/compose/rest/namespace.go index 3d4aba50c..32d9a2dc4 100644 --- a/compose/rest/namespace.go +++ b/compose/rest/namespace.go @@ -7,7 +7,9 @@ import ( "github.com/cortezaproject/corteza-server/compose/rest/request" "github.com/cortezaproject/corteza-server/compose/service" + "github.com/cortezaproject/corteza-server/compose/service/event" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/corredor" "github.com/cortezaproject/corteza-server/pkg/rh" ) @@ -122,6 +124,18 @@ func (ctrl Namespace) Delete(ctx context.Context, r *request.NamespaceDelete) (i return resputil.OK(), ctrl.namespace.With(ctx).DeleteByID(r.NamespaceID) } +func (ctrl *Namespace) FireTrigger(ctx context.Context, r *request.NamespaceFireTrigger) (rsp interface{}, err error) { + var ( + namespace *types.Namespace + ) + + if namespace, err = ctrl.namespace.With(ctx).FindByID(r.NamespaceID); err != nil { + return + } + + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.NamespaceOnManual(namespace, nil)) +} + func (ctrl Namespace) makePayload(ctx context.Context, ns *types.Namespace, err error) (*namespacePayload, error) { if err != nil || ns == nil { return nil, err diff --git a/compose/rest/page.go b/compose/rest/page.go index 2e5ee3cd3..f32da9a43 100644 --- a/compose/rest/page.go +++ b/compose/rest/page.go @@ -7,7 +7,9 @@ import ( "github.com/cortezaproject/corteza-server/compose/rest/request" "github.com/cortezaproject/corteza-server/compose/service" + "github.com/cortezaproject/corteza-server/compose/service/event" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/corredor" "github.com/cortezaproject/corteza-server/pkg/payload" "github.com/cortezaproject/corteza-server/pkg/rh" ) @@ -30,6 +32,7 @@ type ( Page struct { page service.PageService + namespace service.NamespaceService attachment service.AttachmentService ac pageAccessController } @@ -45,6 +48,7 @@ type ( func (Page) New() *Page { return &Page{ page: service.DefaultPage, + namespace: service.DefaultNamespace, attachment: service.DefaultAttachment, ac: service.DefaultAccessControl, } @@ -153,6 +157,22 @@ func (ctrl *Page) Upload(ctx context.Context, r *request.PageUpload) (interface{ return makeAttachmentPayload(ctx, a, err) } +func (ctrl *Page) FireTrigger(ctx context.Context, r *request.PageFireTrigger) (rsp interface{}, err error) { + var ( + page *types.Page + namespace *types.Namespace + ) + + if page, err = ctrl.page.FindByID(r.NamespaceID, r.PageID); err != nil { + return + } + if namespace, err = ctrl.namespace.With(ctx).FindByID(r.NamespaceID); err != nil { + return + } + + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.PageOnManual(page, nil, namespace)) +} + func (ctrl Page) makePayload(ctx context.Context, c *types.Page, err error) (*pagePayload, error) { if err != nil || c == nil { return nil, err diff --git a/compose/rest/record.go b/compose/rest/record.go index cbbbbd96c..4b28b2ede 100644 --- a/compose/rest/record.go +++ b/compose/rest/record.go @@ -17,7 +17,9 @@ import ( "github.com/cortezaproject/corteza-server/compose/repository" "github.com/cortezaproject/corteza-server/compose/rest/request" "github.com/cortezaproject/corteza-server/compose/service" + "github.com/cortezaproject/corteza-server/compose/service/event" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/corredor" "github.com/cortezaproject/corteza-server/pkg/mime" "github.com/cortezaproject/corteza-server/pkg/rh" ) @@ -41,6 +43,7 @@ type ( importSession service.ImportSessionService record service.RecordService module service.ModuleService + namespace service.NamespaceService attachment service.AttachmentService ac recordAccessController } @@ -56,6 +59,7 @@ func (Record) New() *Record { importSession: service.DefaultImportSession, record: service.DefaultRecord, module: service.DefaultModule, + namespace: service.DefaultNamespace, attachment: service.DefaultAttachment, ac: service.DefaultAccessControl, } @@ -372,6 +376,28 @@ func (ctrl Record) Exec(ctx context.Context, r *request.RecordExec) (interface{} return nil, nil } +func (ctrl *Record) Trigger(ctx context.Context, r *request.RecordTrigger) (rsp interface{}, err error) { + var ( + record *types.Record + module *types.Module + namespace *types.Namespace + ) + + if record, err = ctrl.record.With(ctx).FindByID(r.NamespaceID, r.RecordID); err != nil { + return + } + + if module, err = ctrl.module.With(ctx).FindByID(r.NamespaceID, r.ModuleID); err != nil { + return + } + + if namespace, err = ctrl.namespace.With(ctx).FindByID(r.NamespaceID); err != nil { + return + } + + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.RecordOnManual(record, nil, module, namespace)) +} + func (ctrl Record) makePayload(ctx context.Context, m *types.Module, r *types.Record, err error) (*recordPayload, error) { if err != nil || r == nil { return nil, err diff --git a/compose/rest/request/automation.go b/compose/rest/request/automation.go new file mode 100644 index 000000000..99c3e7cd1 --- /dev/null +++ b/compose/rest/request/automation.go @@ -0,0 +1,158 @@ +package request + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `automation.go`, `automation.util.go` or `automation_test.go` to + implement your API calls, helper functions and tests. The file `automation.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "io" + "strings" + + "encoding/json" + "mime/multipart" + "net/http" + + "github.com/go-chi/chi" + "github.com/pkg/errors" +) + +var _ = chi.URLParam +var _ = multipart.FileHeader{} + +// Automation list request parameters +type AutomationList struct { + ResourceTypes []string + EventTypes []string + ExcludeClientScripts bool + ExcludeServerScripts bool +} + +func NewAutomationList() *AutomationList { + return &AutomationList{} +} + +func (r AutomationList) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["resourceTypes"] = r.ResourceTypes + out["eventTypes"] = r.EventTypes + out["excludeClientScripts"] = r.ExcludeClientScripts + out["excludeServerScripts"] = r.ExcludeServerScripts + + return out +} + +func (r *AutomationList) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := urlQuery["resourceTypes[]"]; ok { + r.ResourceTypes = parseStrings(val) + } else if val, ok = urlQuery["resourceTypes"]; ok { + r.ResourceTypes = parseStrings(val) + } + + if val, ok := urlQuery["eventTypes[]"]; ok { + r.EventTypes = parseStrings(val) + } else if val, ok = urlQuery["eventTypes"]; ok { + r.EventTypes = parseStrings(val) + } + + if val, ok := get["excludeClientScripts"]; ok { + r.ExcludeClientScripts = parseBool(val) + } + if val, ok := get["excludeServerScripts"]; ok { + r.ExcludeServerScripts = parseBool(val) + } + + return err +} + +var _ RequestFiller = NewAutomationList() + +// Automation trigger request parameters +type AutomationTrigger struct { + Script string +} + +func NewAutomationTrigger() *AutomationTrigger { + return &AutomationTrigger{} +} + +func (r AutomationTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["script"] = r.Script + + return out +} + +func (r *AutomationTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewAutomationTrigger() diff --git a/compose/rest/request/module.go b/compose/rest/request/module.go index d05d9e385..75c29f255 100644 --- a/compose/rest/request/module.go +++ b/compose/rest/request/module.go @@ -375,3 +375,62 @@ func (r *ModuleDelete) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewModuleDelete() + +// Module fireTrigger request parameters +type ModuleFireTrigger struct { + ModuleID uint64 `json:",string"` + NamespaceID uint64 `json:",string"` + Script string +} + +func NewModuleFireTrigger() *ModuleFireTrigger { + return &ModuleFireTrigger{} +} + +func (r ModuleFireTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["moduleID"] = r.ModuleID + out["namespaceID"] = r.NamespaceID + out["script"] = r.Script + + return out +} + +func (r *ModuleFireTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + r.ModuleID = parseUInt64(chi.URLParam(req, "moduleID")) + r.NamespaceID = parseUInt64(chi.URLParam(req, "namespaceID")) + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewModuleFireTrigger() diff --git a/compose/rest/request/namespace.go b/compose/rest/request/namespace.go index 031feda3f..f9efee08f 100644 --- a/compose/rest/request/namespace.go +++ b/compose/rest/request/namespace.go @@ -360,3 +360,59 @@ func (r *NamespaceDelete) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewNamespaceDelete() + +// Namespace fireTrigger request parameters +type NamespaceFireTrigger struct { + NamespaceID uint64 `json:",string"` + Script string +} + +func NewNamespaceFireTrigger() *NamespaceFireTrigger { + return &NamespaceFireTrigger{} +} + +func (r NamespaceFireTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["namespaceID"] = r.NamespaceID + out["script"] = r.Script + + return out +} + +func (r *NamespaceFireTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + r.NamespaceID = parseUInt64(chi.URLParam(req, "namespaceID")) + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewNamespaceFireTrigger() diff --git a/compose/rest/request/page.go b/compose/rest/request/page.go index 1ec9e8815..119d58c86 100644 --- a/compose/rest/request/page.go +++ b/compose/rest/request/page.go @@ -572,3 +572,62 @@ func (r *PageUpload) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewPageUpload() + +// Page fireTrigger request parameters +type PageFireTrigger struct { + PageID uint64 `json:",string"` + NamespaceID uint64 `json:",string"` + Script string +} + +func NewPageFireTrigger() *PageFireTrigger { + return &PageFireTrigger{} +} + +func (r PageFireTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["pageID"] = r.PageID + out["namespaceID"] = r.NamespaceID + out["script"] = r.Script + + return out +} + +func (r *PageFireTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + r.PageID = parseUInt64(chi.URLParam(req, "pageID")) + r.NamespaceID = parseUInt64(chi.URLParam(req, "namespaceID")) + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewPageFireTrigger() diff --git a/compose/rest/request/record.go b/compose/rest/request/record.go index 9b4268e2b..9ba06ce00 100644 --- a/compose/rest/request/record.go +++ b/compose/rest/request/record.go @@ -794,3 +794,65 @@ func (r *RecordUpload) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewRecordUpload() + +// Record trigger request parameters +type RecordTrigger struct { + RecordID uint64 `json:",string"` + NamespaceID uint64 `json:",string"` + ModuleID uint64 `json:",string"` + Script string +} + +func NewRecordTrigger() *RecordTrigger { + return &RecordTrigger{} +} + +func (r RecordTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["recordID"] = r.RecordID + out["namespaceID"] = r.NamespaceID + out["moduleID"] = r.ModuleID + out["script"] = r.Script + + return out +} + +func (r *RecordTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + r.RecordID = parseUInt64(chi.URLParam(req, "recordID")) + r.NamespaceID = parseUInt64(chi.URLParam(req, "namespaceID")) + r.ModuleID = parseUInt64(chi.URLParam(req, "moduleID")) + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewRecordTrigger() diff --git a/compose/rest/request/trigger.go b/compose/rest/request/trigger.go new file mode 100644 index 000000000..b3998cc01 --- /dev/null +++ b/compose/rest/request/trigger.go @@ -0,0 +1,150 @@ +package request + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `trigger.go`, `trigger.util.go` or `trigger_test.go` to + implement your API calls, helper functions and tests. The file `trigger.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "io" + "strings" + + "encoding/json" + "mime/multipart" + "net/http" + + "github.com/go-chi/chi" + "github.com/pkg/errors" +) + +var _ = chi.URLParam +var _ = multipart.FileHeader{} + +// Trigger list request parameters +type TriggerList struct { + ResourceTypes []string + ExcludeClientScripts bool + ExcludeServerScripts bool +} + +func NewTriggerList() *TriggerList { + return &TriggerList{} +} + +func (r TriggerList) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["resourceTypes"] = r.ResourceTypes + out["excludeClientScripts"] = r.ExcludeClientScripts + out["excludeServerScripts"] = r.ExcludeServerScripts + + return out +} + +func (r *TriggerList) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := urlQuery["resourceTypes[]"]; ok { + r.ResourceTypes = parseStrings(val) + } else if val, ok = urlQuery["resourceTypes"]; ok { + r.ResourceTypes = parseStrings(val) + } + + if val, ok := get["excludeClientScripts"]; ok { + r.ExcludeClientScripts = parseBool(val) + } + if val, ok := get["excludeServerScripts"]; ok { + r.ExcludeServerScripts = parseBool(val) + } + + return err +} + +var _ RequestFiller = NewTriggerList() + +// Trigger fire request parameters +type TriggerFire struct { + Trigger string +} + +func NewTriggerFire() *TriggerFire { + return &TriggerFire{} +} + +func (r TriggerFire) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["trigger"] = r.Trigger + + return out +} + +func (r *TriggerFire) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := post["trigger"]; ok { + r.Trigger = val + } + + return err +} + +var _ RequestFiller = NewTriggerFire() diff --git a/compose/rest/router.go b/compose/rest/router.go index 2268e99aa..4fc850b45 100644 --- a/compose/rest/router.go +++ b/compose/rest/router.go @@ -16,6 +16,7 @@ func MountRoutes(r chi.Router) { chart = Chart{}.New() notification = Notification{}.New() attachment = Attachment{}.New() + automation = Automation{}.New() ) // Initialize handlers & controllers. @@ -31,6 +32,7 @@ func MountRoutes(r chi.Router) { handlers.NewNamespace(namespace).MountRoutes(r) handlers.NewPage(page).MountRoutes(r) + handlers.NewAutomation(automation).MountRoutes(r) handlers.NewModule(module).MountRoutes(r) handlers.NewRecord(record).MountRoutes(r) handlers.NewChart(chart).MountRoutes(r) diff --git a/docs/compose/README.md b/docs/compose/README.md index 0dd81825e..37abc51bc 100644 --- a/docs/compose/README.md +++ b/docs/compose/README.md @@ -111,6 +111,53 @@ +# Compose automation scripts + +| Method | Endpoint | Purpose | +| ------ | -------- | ------- | +| `GET` | `/automation/` | List all available automation scripts for compose resources | +| `POST` | `/automation/trigger` | Triggers execution of a specific script on a system service level | + +## List all available automation scripts for compose resources + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/automation/` | HTTP/S | GET | +Warning: implode(): Invalid arguments passed in /private/tmp/Users/darh/Work.crust/corteza-server/codegen/templates/README.tpl on line 32 + | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| resourceTypes | []string | GET | Filter by resource type | N/A | NO | +| eventTypes | []string | GET | Filter by event type | N/A | NO | +| excludeClientScripts | bool | GET | Do not include client scripts | N/A | NO | +| excludeServerScripts | bool | GET | Do not include server scripts | N/A | NO | + +## Triggers execution of a specific script on a system service level + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/automation/trigger` | HTTP/S | POST | +Warning: implode(): Invalid arguments passed in /private/tmp/Users/darh/Work.crust/corteza-server/codegen/templates/README.tpl on line 32 + | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| script | string | POST | Script to execute | N/A | YES | + +--- + + + + # Charts | Method | Endpoint | Purpose | @@ -222,6 +269,7 @@ Compose module definitions | `GET` | `/namespace/{namespaceID}/module/{moduleID}` | Read module | | `POST` | `/namespace/{namespaceID}/module/{moduleID}` | Update module | | `DELETE` | `/namespace/{namespaceID}/module/{moduleID}` | Delete module | +| `POST` | `/namespace/{namespaceID}/module/{moduleID}/trigger` | Fire compose:module trigger | ## List modules @@ -311,6 +359,22 @@ Compose module definitions | moduleID | uint64 | PATH | Module ID | N/A | YES | | namespaceID | uint64 | PATH | Namespace ID | N/A | YES | +## Fire compose:module trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/namespace/{namespaceID}/module/{moduleID}/trigger` | HTTP/S | POST | | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| moduleID | uint64 | PATH | ID | N/A | YES | +| namespaceID | uint64 | PATH | Namespace ID | N/A | YES | +| script | string | POST | Script to execute | N/A | YES | + --- @@ -325,6 +389,7 @@ Compose module definitions | `GET` | `/namespace/{namespaceID}` | Read namespace | | `POST` | `/namespace/{namespaceID}` | Update namespace | | `DELETE` | `/namespace/{namespaceID}` | Delete namespace | +| `POST` | `/namespace/{namespaceID}/trigger` | Fire compose:namespace trigger | ## List namespaces @@ -408,6 +473,21 @@ Compose module definitions | --------- | ---- | ------ | ----------- | ------- | --------- | | namespaceID | uint64 | PATH | ID | N/A | YES | +## Fire compose:namespace trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/namespace/{namespaceID}/trigger` | HTTP/S | POST | | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| namespaceID | uint64 | PATH | ID | N/A | YES | +| script | string | POST | Script to execute | N/A | YES | + --- @@ -459,6 +539,7 @@ Compose pages | `POST` | `/namespace/{namespaceID}/page/{selfID}/reorder` | Reorder pages | | `Delete` | `/namespace/{namespaceID}/page/{pageID}` | Delete page | | `POST` | `/namespace/{namespaceID}/page/{pageID}/attachment` | Uploads attachment to page | +| `POST` | `/namespace/{namespaceID}/page/{pageID}/trigger` | Fire compose:page trigger | ## List available pages @@ -599,6 +680,22 @@ Compose pages | namespaceID | uint64 | PATH | Namespace ID | N/A | YES | | upload | *multipart.FileHeader | POST | File to upload | N/A | YES | +## Fire compose:page trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/namespace/{namespaceID}/page/{pageID}/trigger` | HTTP/S | POST | | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| pageID | uint64 | PATH | Page ID | N/A | YES | +| namespaceID | uint64 | PATH | Namespace ID | N/A | YES | +| script | string | POST | Script to execute | N/A | YES | + --- @@ -707,6 +804,7 @@ Compose records | `POST` | `/namespace/{namespaceID}/module/{moduleID}/record/{recordID}` | Update records in module section | | `DELETE` | `/namespace/{namespaceID}/module/{moduleID}/record/{recordID}` | Delete record row from module section | | `POST` | `/namespace/{namespaceID}/module/{moduleID}/record/attachment` | Uploads attachment and validates it against record field requirements | +| `POST` | `/namespace/{namespaceID}/module/{moduleID}/record/{recordID}/trigger` | Fire compose:record trigger | ## Generates report from module records @@ -914,6 +1012,23 @@ Compose records | namespaceID | uint64 | PATH | Namespace ID | N/A | YES | | moduleID | uint64 | PATH | Module ID | N/A | YES | +## Fire compose:record trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/namespace/{namespaceID}/module/{moduleID}/record/{recordID}/trigger` | HTTP/S | POST | | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| recordID | uint64 | PATH | ID | N/A | YES | +| namespaceID | uint64 | PATH | Namespace ID | N/A | YES | +| moduleID | uint64 | PATH | Module ID | N/A | YES | +| script | string | POST | Script to execute | N/A | YES | + --- diff --git a/docs/system/README.md b/docs/system/README.md index cb08b9951..264746c62 100644 --- a/docs/system/README.md +++ b/docs/system/README.md @@ -8,6 +8,7 @@ | `GET` | `/application/{applicationID}` | Read application details | | `DELETE` | `/application/{applicationID}` | Remove application | | `POST` | `/application/{applicationID}/undelete` | Undelete application | +| `POST` | `/application/{applicationID}/trigger` | Fire system:application trigger | ## List applications @@ -105,6 +106,21 @@ | --------- | ---- | ------ | ----------- | ------- | --------- | | applicationID | uint64 | PATH | Application ID | N/A | YES | +## Fire system:application trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/application/{applicationID}/trigger` | HTTP/S | POST | | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| applicationID | uint64 | PATH | ID | N/A | YES | +| script | string | POST | Script to execute | N/A | YES | + --- @@ -299,6 +315,53 @@ +# System automation scripts + +| Method | Endpoint | Purpose | +| ------ | -------- | ------- | +| `GET` | `/automation/` | List all available automation scripts for system resources | +| `POST` | `/automation/trigger` | Triggers execution of a specific script on a system service level | + +## List all available automation scripts for system resources + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/automation/` | HTTP/S | GET | +Warning: implode(): Invalid arguments passed in /private/tmp/Users/darh/Work.crust/corteza-server/codegen/templates/README.tpl on line 32 + | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| resourceTypes | []string | GET | Filter by resource type | N/A | NO | +| eventTypes | []string | GET | Filter by event type | N/A | NO | +| excludeClientScripts | bool | GET | Do not include client scripts | N/A | NO | +| excludeServerScripts | bool | GET | Do not include server scripts | N/A | NO | + +## Triggers execution of a specific script on a system service level + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/automation/trigger` | HTTP/S | POST | +Warning: implode(): Invalid arguments passed in /private/tmp/Users/darh/Work.crust/corteza-server/codegen/templates/README.tpl on line 32 + | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| script | string | POST | Script to execute | N/A | YES | + +--- + + + + # Organisations Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment. @@ -638,6 +701,7 @@ An organisation may have many roles. Roles may have many channels available. Acc | `GET` | `/roles/{roleID}/members` | Returns all role members | | `POST` | `/roles/{roleID}/member/{userID}` | Add member to a role | | `DELETE` | `/roles/{roleID}/member/{userID}` | Remove member from a role | +| `POST` | `/roles/{roleID}/trigger` | Fire system:role trigger | ## List roles @@ -835,6 +899,21 @@ An organisation may have many roles. Roles may have many channels available. Acc | roleID | uint64 | PATH | Source Role ID | N/A | YES | | userID | uint64 | PATH | User ID | N/A | YES | +## Fire system:role trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/roles/{roleID}/trigger` | HTTP/S | POST | Client ID, Session ID | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| roleID | uint64 | PATH | ID | N/A | YES | +| script | string | POST | Script to execute | N/A | YES | + --- @@ -976,6 +1055,7 @@ Warning: implode(): Invalid arguments passed in /private/tmp/Users/darh/Work.cru | `GET` | `/users/{userID}/membership` | Add member to a role | | `POST` | `/users/{userID}/membership/{roleID}` | Add role to a user | | `DELETE` | `/users/{userID}/membership/{roleID}` | Remove role from a user | +| `POST` | `/users/{userID}/trigger` | Fire system:user trigger | ## Search users (Directory) @@ -1168,4 +1248,19 @@ Warning: implode(): Invalid arguments passed in /private/tmp/Users/darh/Work.cru | roleID | uint64 | PATH | Role ID | N/A | YES | | userID | uint64 | PATH | User ID | N/A | YES | +## Fire system:user trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/users/{userID}/trigger` | HTTP/S | POST | Client ID, Session ID | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| userID | uint64 | PATH | ID | N/A | YES | +| script | string | POST | Script to execute | N/A | YES | + --- \ No newline at end of file diff --git a/system/rest/application.go b/system/rest/application.go index 1e631ac5e..ca73af435 100644 --- a/system/rest/application.go +++ b/system/rest/application.go @@ -5,9 +5,11 @@ import ( "github.com/titpetric/factory/resputil" + "github.com/cortezaproject/corteza-server/pkg/corredor" "github.com/cortezaproject/corteza-server/pkg/rh" "github.com/cortezaproject/corteza-server/system/rest/request" "github.com/cortezaproject/corteza-server/system/service" + "github.com/cortezaproject/corteza-server/system/service/event" "github.com/cortezaproject/corteza-server/system/types" "github.com/pkg/errors" @@ -118,6 +120,18 @@ func (ctrl *Application) Undelete(ctx context.Context, r *request.ApplicationUnd return resputil.OK(), ctrl.application.With(ctx).Undelete(r.ApplicationID) } +func (ctrl *Application) FireTrigger(ctx context.Context, r *request.ApplicationFireTrigger) (rsp interface{}, err error) { + var ( + application *types.Application + ) + + if application, err = ctrl.application.With(ctx).FindByID(r.ApplicationID); err != nil { + return + } + + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.ApplicationOnManual(application, nil)) +} + func (ctrl Application) makePayload(ctx context.Context, m *types.Application, err error) (*applicationPayload, error) { if err != nil || m == nil { return nil, err diff --git a/system/rest/automation.go b/system/rest/automation.go new file mode 100644 index 000000000..86c21c213 --- /dev/null +++ b/system/rest/automation.go @@ -0,0 +1,40 @@ +package rest + +import ( + "context" + + "github.com/pkg/errors" + "github.com/titpetric/factory/resputil" + + "github.com/cortezaproject/corteza-server/pkg/corredor" + "github.com/cortezaproject/corteza-server/system/rest/request" + "github.com/cortezaproject/corteza-server/system/service/event" +) + +var _ = errors.Wrap + +type Automation struct { + // xxx service.XXXService +} + +func (Automation) New() *Automation { + return &Automation{} +} + +func (ctrl *Automation) List(ctx context.Context, r *request.AutomationList) (interface{}, error) { + f := corredor.ManualScriptFilter{ + ResourceTypes: r.ResourceTypes, + ExcludeServerScripts: r.ExcludeServerScripts, + ExcludeClientScripts: r.ExcludeClientScripts, + } + + f.PrefixResource("system") + + scripts, _, err := corredor.Service().FindOnManual(f) + + return scripts, err +} + +func (ctrl *Automation) Trigger(ctx context.Context, r *request.AutomationTrigger) (interface{}, error) { + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.SystemOnManual()) +} diff --git a/system/rest/handlers/application.go b/system/rest/handlers/application.go index 4da58a668..2492acc6c 100644 --- a/system/rest/handlers/application.go +++ b/system/rest/handlers/application.go @@ -35,16 +35,18 @@ type ApplicationAPI interface { Read(context.Context, *request.ApplicationRead) (interface{}, error) Delete(context.Context, *request.ApplicationDelete) (interface{}, error) Undelete(context.Context, *request.ApplicationUndelete) (interface{}, error) + FireTrigger(context.Context, *request.ApplicationFireTrigger) (interface{}, error) } // HTTP API interface type Application struct { - List func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) - Update func(http.ResponseWriter, *http.Request) - Read func(http.ResponseWriter, *http.Request) - Delete func(http.ResponseWriter, *http.Request) - Undelete func(http.ResponseWriter, *http.Request) + List func(http.ResponseWriter, *http.Request) + Create func(http.ResponseWriter, *http.Request) + Update func(http.ResponseWriter, *http.Request) + Read func(http.ResponseWriter, *http.Request) + Delete func(http.ResponseWriter, *http.Request) + Undelete func(http.ResponseWriter, *http.Request) + FireTrigger func(http.ResponseWriter, *http.Request) } func NewApplication(h ApplicationAPI) *Application { @@ -169,6 +171,26 @@ func NewApplication(h ApplicationAPI) *Application { resputil.JSON(w, value) } }, + FireTrigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewApplicationFireTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Application.FireTrigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.FireTrigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Application.FireTrigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Application.FireTrigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -181,5 +203,6 @@ func (h Application) MountRoutes(r chi.Router, middlewares ...func(http.Handler) r.Get("/application/{applicationID}", h.Read) r.Delete("/application/{applicationID}", h.Delete) r.Post("/application/{applicationID}/undelete", h.Undelete) + r.Post("/application/{applicationID}/trigger", h.FireTrigger) }) } diff --git a/system/rest/handlers/automation.go b/system/rest/handlers/automation.go new file mode 100644 index 000000000..008f91b2a --- /dev/null +++ b/system/rest/handlers/automation.go @@ -0,0 +1,93 @@ +package handlers + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `automation.go`, `automation.util.go` or `automation_test.go` to + implement your API calls, helper functions and tests. The file `automation.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "context" + + "net/http" + + "github.com/go-chi/chi" + "github.com/titpetric/factory/resputil" + + "github.com/cortezaproject/corteza-server/pkg/logger" + "github.com/cortezaproject/corteza-server/system/rest/request" +) + +// Internal API interface +type AutomationAPI interface { + List(context.Context, *request.AutomationList) (interface{}, error) + Trigger(context.Context, *request.AutomationTrigger) (interface{}, error) +} + +// HTTP API interface +type Automation struct { + List func(http.ResponseWriter, *http.Request) + Trigger func(http.ResponseWriter, *http.Request) +} + +func NewAutomation(h AutomationAPI) *Automation { + return &Automation{ + List: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewAutomationList() + if err := params.Fill(r); err != nil { + logger.LogParamError("Automation.List", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.List(r.Context(), params) + if err != nil { + logger.LogControllerError("Automation.List", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Automation.List", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + Trigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewAutomationTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Automation.Trigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.Trigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Automation.Trigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Automation.Trigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + } +} + +func (h Automation) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { + r.Group(func(r chi.Router) { + r.Use(middlewares...) + r.Get("/automation/", h.List) + r.Post("/automation/trigger", h.Trigger) + }) +} diff --git a/system/rest/handlers/role.go b/system/rest/handlers/role.go index ff3d81420..c55818ac3 100644 --- a/system/rest/handlers/role.go +++ b/system/rest/handlers/role.go @@ -42,6 +42,7 @@ type RoleAPI interface { MemberList(context.Context, *request.RoleMemberList) (interface{}, error) MemberAdd(context.Context, *request.RoleMemberAdd) (interface{}, error) MemberRemove(context.Context, *request.RoleMemberRemove) (interface{}, error) + FireTrigger(context.Context, *request.RoleFireTrigger) (interface{}, error) } // HTTP API interface @@ -59,6 +60,7 @@ type Role struct { MemberList func(http.ResponseWriter, *http.Request) MemberAdd func(http.ResponseWriter, *http.Request) MemberRemove func(http.ResponseWriter, *http.Request) + FireTrigger func(http.ResponseWriter, *http.Request) } func NewRole(h RoleAPI) *Role { @@ -323,6 +325,26 @@ func NewRole(h RoleAPI) *Role { resputil.JSON(w, value) } }, + FireTrigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewRoleFireTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("Role.FireTrigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.FireTrigger(r.Context(), params) + if err != nil { + logger.LogControllerError("Role.FireTrigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Role.FireTrigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -342,5 +364,6 @@ func (h Role) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.H r.Get("/roles/{roleID}/members", h.MemberList) r.Post("/roles/{roleID}/member/{userID}", h.MemberAdd) r.Delete("/roles/{roleID}/member/{userID}", h.MemberRemove) + r.Post("/roles/{roleID}/trigger", h.FireTrigger) }) } diff --git a/system/rest/handlers/trigger.go b/system/rest/handlers/trigger.go new file mode 100644 index 000000000..cfec68909 --- /dev/null +++ b/system/rest/handlers/trigger.go @@ -0,0 +1,93 @@ +package handlers + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `trigger.go`, `trigger.util.go` or `trigger_test.go` to + implement your API calls, helper functions and tests. The file `trigger.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "context" + + "net/http" + + "github.com/go-chi/chi" + "github.com/titpetric/factory/resputil" + + "github.com/cortezaproject/corteza-server/pkg/logger" + "github.com/cortezaproject/corteza-server/system/rest/request" +) + +// Internal API interface +type TriggerAPI interface { + List(context.Context, *request.TriggerList) (interface{}, error) + Fire(context.Context, *request.TriggerFire) (interface{}, error) +} + +// HTTP API interface +type Trigger struct { + List func(http.ResponseWriter, *http.Request) + Fire func(http.ResponseWriter, *http.Request) +} + +func NewTrigger(h TriggerAPI) *Trigger { + return &Trigger{ + List: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewTriggerList() + if err := params.Fill(r); err != nil { + logger.LogParamError("Trigger.List", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.List(r.Context(), params) + if err != nil { + logger.LogControllerError("Trigger.List", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Trigger.List", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + Fire: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewTriggerFire() + if err := params.Fill(r); err != nil { + logger.LogParamError("Trigger.Fire", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.Fire(r.Context(), params) + if err != nil { + logger.LogControllerError("Trigger.Fire", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Trigger.Fire", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + } +} + +func (h Trigger) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { + r.Group(func(r chi.Router) { + r.Use(middlewares...) + r.Get("/trigger/", h.List) + r.Post("/trigger/", h.Fire) + }) +} diff --git a/system/rest/handlers/user.go b/system/rest/handlers/user.go index 7f4f78d7e..8dd2de9e8 100644 --- a/system/rest/handlers/user.go +++ b/system/rest/handlers/user.go @@ -41,6 +41,7 @@ type UserAPI interface { MembershipList(context.Context, *request.UserMembershipList) (interface{}, error) MembershipAdd(context.Context, *request.UserMembershipAdd) (interface{}, error) MembershipRemove(context.Context, *request.UserMembershipRemove) (interface{}, error) + FireTrigger(context.Context, *request.UserFireTrigger) (interface{}, error) } // HTTP API interface @@ -57,6 +58,7 @@ type User struct { MembershipList func(http.ResponseWriter, *http.Request) MembershipAdd func(http.ResponseWriter, *http.Request) MembershipRemove func(http.ResponseWriter, *http.Request) + FireTrigger func(http.ResponseWriter, *http.Request) } func NewUser(h UserAPI) *User { @@ -301,6 +303,26 @@ func NewUser(h UserAPI) *User { resputil.JSON(w, value) } }, + FireTrigger: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewUserFireTrigger() + if err := params.Fill(r); err != nil { + logger.LogParamError("User.FireTrigger", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.FireTrigger(r.Context(), params) + if err != nil { + logger.LogControllerError("User.FireTrigger", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("User.FireTrigger", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -319,5 +341,6 @@ func (h User) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.H r.Get("/users/{userID}/membership", h.MembershipList) r.Post("/users/{userID}/membership/{roleID}", h.MembershipAdd) r.Delete("/users/{userID}/membership/{roleID}", h.MembershipRemove) + r.Post("/users/{userID}/trigger", h.FireTrigger) }) } diff --git a/system/rest/request/application.go b/system/rest/request/application.go index 43786e3a7..2fbc59bbd 100644 --- a/system/rest/request/application.go +++ b/system/rest/request/application.go @@ -413,3 +413,59 @@ func (r *ApplicationUndelete) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewApplicationUndelete() + +// Application fireTrigger request parameters +type ApplicationFireTrigger struct { + ApplicationID uint64 `json:",string"` + Script string +} + +func NewApplicationFireTrigger() *ApplicationFireTrigger { + return &ApplicationFireTrigger{} +} + +func (r ApplicationFireTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["applicationID"] = r.ApplicationID + out["script"] = r.Script + + return out +} + +func (r *ApplicationFireTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + r.ApplicationID = parseUInt64(chi.URLParam(req, "applicationID")) + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewApplicationFireTrigger() diff --git a/system/rest/request/automation.go b/system/rest/request/automation.go new file mode 100644 index 000000000..99c3e7cd1 --- /dev/null +++ b/system/rest/request/automation.go @@ -0,0 +1,158 @@ +package request + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `automation.go`, `automation.util.go` or `automation_test.go` to + implement your API calls, helper functions and tests. The file `automation.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "io" + "strings" + + "encoding/json" + "mime/multipart" + "net/http" + + "github.com/go-chi/chi" + "github.com/pkg/errors" +) + +var _ = chi.URLParam +var _ = multipart.FileHeader{} + +// Automation list request parameters +type AutomationList struct { + ResourceTypes []string + EventTypes []string + ExcludeClientScripts bool + ExcludeServerScripts bool +} + +func NewAutomationList() *AutomationList { + return &AutomationList{} +} + +func (r AutomationList) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["resourceTypes"] = r.ResourceTypes + out["eventTypes"] = r.EventTypes + out["excludeClientScripts"] = r.ExcludeClientScripts + out["excludeServerScripts"] = r.ExcludeServerScripts + + return out +} + +func (r *AutomationList) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := urlQuery["resourceTypes[]"]; ok { + r.ResourceTypes = parseStrings(val) + } else if val, ok = urlQuery["resourceTypes"]; ok { + r.ResourceTypes = parseStrings(val) + } + + if val, ok := urlQuery["eventTypes[]"]; ok { + r.EventTypes = parseStrings(val) + } else if val, ok = urlQuery["eventTypes"]; ok { + r.EventTypes = parseStrings(val) + } + + if val, ok := get["excludeClientScripts"]; ok { + r.ExcludeClientScripts = parseBool(val) + } + if val, ok := get["excludeServerScripts"]; ok { + r.ExcludeServerScripts = parseBool(val) + } + + return err +} + +var _ RequestFiller = NewAutomationList() + +// Automation trigger request parameters +type AutomationTrigger struct { + Script string +} + +func NewAutomationTrigger() *AutomationTrigger { + return &AutomationTrigger{} +} + +func (r AutomationTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["script"] = r.Script + + return out +} + +func (r *AutomationTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewAutomationTrigger() diff --git a/system/rest/request/role.go b/system/rest/request/role.go index 81fa255a0..f87a17e08 100644 --- a/system/rest/request/role.go +++ b/system/rest/request/role.go @@ -764,3 +764,59 @@ func (r *RoleMemberRemove) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewRoleMemberRemove() + +// Role fireTrigger request parameters +type RoleFireTrigger struct { + RoleID uint64 `json:",string"` + Script string +} + +func NewRoleFireTrigger() *RoleFireTrigger { + return &RoleFireTrigger{} +} + +func (r RoleFireTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["roleID"] = r.RoleID + out["script"] = r.Script + + return out +} + +func (r *RoleFireTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + r.RoleID = parseUInt64(chi.URLParam(req, "roleID")) + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewRoleFireTrigger() diff --git a/system/rest/request/trigger.go b/system/rest/request/trigger.go new file mode 100644 index 000000000..b3998cc01 --- /dev/null +++ b/system/rest/request/trigger.go @@ -0,0 +1,150 @@ +package request + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `trigger.go`, `trigger.util.go` or `trigger_test.go` to + implement your API calls, helper functions and tests. The file `trigger.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "io" + "strings" + + "encoding/json" + "mime/multipart" + "net/http" + + "github.com/go-chi/chi" + "github.com/pkg/errors" +) + +var _ = chi.URLParam +var _ = multipart.FileHeader{} + +// Trigger list request parameters +type TriggerList struct { + ResourceTypes []string + ExcludeClientScripts bool + ExcludeServerScripts bool +} + +func NewTriggerList() *TriggerList { + return &TriggerList{} +} + +func (r TriggerList) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["resourceTypes"] = r.ResourceTypes + out["excludeClientScripts"] = r.ExcludeClientScripts + out["excludeServerScripts"] = r.ExcludeServerScripts + + return out +} + +func (r *TriggerList) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := urlQuery["resourceTypes[]"]; ok { + r.ResourceTypes = parseStrings(val) + } else if val, ok = urlQuery["resourceTypes"]; ok { + r.ResourceTypes = parseStrings(val) + } + + if val, ok := get["excludeClientScripts"]; ok { + r.ExcludeClientScripts = parseBool(val) + } + if val, ok := get["excludeServerScripts"]; ok { + r.ExcludeServerScripts = parseBool(val) + } + + return err +} + +var _ RequestFiller = NewTriggerList() + +// Trigger fire request parameters +type TriggerFire struct { + Trigger string +} + +func NewTriggerFire() *TriggerFire { + return &TriggerFire{} +} + +func (r TriggerFire) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["trigger"] = r.Trigger + + return out +} + +func (r *TriggerFire) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + if val, ok := post["trigger"]; ok { + r.Trigger = val + } + + return err +} + +var _ RequestFiller = NewTriggerFire() diff --git a/system/rest/request/user.go b/system/rest/request/user.go index 921cd28a2..9fa7b5fbb 100644 --- a/system/rest/request/user.go +++ b/system/rest/request/user.go @@ -764,3 +764,59 @@ func (r *UserMembershipRemove) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewUserMembershipRemove() + +// User fireTrigger request parameters +type UserFireTrigger struct { + UserID uint64 `json:",string"` + Script string +} + +func NewUserFireTrigger() *UserFireTrigger { + return &UserFireTrigger{} +} + +func (r UserFireTrigger) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["userID"] = r.UserID + out["script"] = r.Script + + return out +} + +func (r *UserFireTrigger) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = req.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := req.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := req.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + r.UserID = parseUInt64(chi.URLParam(req, "userID")) + if val, ok := post["script"]; ok { + r.Script = val + } + + return err +} + +var _ RequestFiller = NewUserFireTrigger() diff --git a/system/rest/role.go b/system/rest/role.go index b42596a2a..481959d83 100644 --- a/system/rest/role.go +++ b/system/rest/role.go @@ -6,10 +6,12 @@ import ( "github.com/pkg/errors" "github.com/titpetric/factory/resputil" + "github.com/cortezaproject/corteza-server/pkg/corredor" "github.com/cortezaproject/corteza-server/pkg/payload" "github.com/cortezaproject/corteza-server/pkg/rh" "github.com/cortezaproject/corteza-server/system/rest/request" "github.com/cortezaproject/corteza-server/system/service" + "github.com/cortezaproject/corteza-server/system/service/event" "github.com/cortezaproject/corteza-server/system/types" ) @@ -174,6 +176,18 @@ func (ctrl Role) MemberRemove(ctx context.Context, r *request.RoleMemberRemove) return resputil.OK(), ctrl.role.With(ctx).MemberRemove(r.RoleID, r.UserID) } +func (ctrl *Role) FireTrigger(ctx context.Context, r *request.RoleFireTrigger) (rsp interface{}, err error) { + var ( + role *types.Role + ) + + if role, err = ctrl.role.With(ctx).FindByID(r.RoleID); err != nil { + return + } + + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.RoleOnManual(role, nil)) +} + func (ctrl Role) makePayload(ctx context.Context, m *types.Role, err error) (*rolePayload, error) { if err != nil || m == nil { return nil, err diff --git a/system/rest/router.go b/system/rest/router.go index 19743578c..e3bf17445 100644 --- a/system/rest/router.go +++ b/system/rest/router.go @@ -27,6 +27,7 @@ func MountRoutes(r chi.Router) { r.Group(func(r chi.Router) { r.Use(auth.MiddlewareValidOnly) + handlers.NewAutomation(Automation{}.New()).MountRoutes(r) handlers.NewSubscription(Subscription{}.New()).MountRoutes(r) handlers.NewUser(User{}.New()).MountRoutes(r) handlers.NewRole(Role{}.New()).MountRoutes(r) diff --git a/system/rest/user.go b/system/rest/user.go index bf3e5cff2..acaa2929a 100644 --- a/system/rest/user.go +++ b/system/rest/user.go @@ -6,10 +6,12 @@ import ( "github.com/pkg/errors" "github.com/titpetric/factory/resputil" + "github.com/cortezaproject/corteza-server/pkg/corredor" "github.com/cortezaproject/corteza-server/pkg/payload" "github.com/cortezaproject/corteza-server/pkg/rh" "github.com/cortezaproject/corteza-server/system/rest/request" "github.com/cortezaproject/corteza-server/system/service" + "github.com/cortezaproject/corteza-server/system/service/event" "github.com/cortezaproject/corteza-server/system/types" ) @@ -130,6 +132,18 @@ func (ctrl User) MembershipRemove(ctx context.Context, r *request.UserMembership return resputil.OK(), ctrl.role.With(ctx).MemberRemove(r.RoleID, r.UserID) } +func (ctrl *User) FireTrigger(ctx context.Context, r *request.UserFireTrigger) (rsp interface{}, err error) { + var ( + user *types.User + ) + + if user, err = ctrl.user.With(ctx).FindByID(r.UserID); err != nil { + return + } + + return resputil.OK(), corredor.Service().ExecOnManual(ctx, r.Script, event.UserOnManual(user, nil)) +} + func (ctrl User) makeFilterPayload(ctx context.Context, uu types.UserSet, f types.UserFilter, err error) (*userSetPayload, error) { if err != nil { return nil, err diff --git a/system/service/event/auth.gen.go b/system/service/event/auth.gen.go index c82897a79..1f6186038 100644 --- a/system/service/event/auth.gen.go +++ b/system/service/event/auth.gen.go @@ -25,13 +25,6 @@ type ( invoker auth.Identifiable } - // authOnManual - // - // This type is auto-generated. - authOnManual struct { - *authBase - } - // authBeforeLogin // // This type is auto-generated. @@ -68,13 +61,6 @@ func (authBase) ResourceType() string { return "system:auth" } -// EventType on authOnManual returns "onManual" -// -// This function is auto-generated. -func (authOnManual) EventType() string { - return "onManual" -} - // EventType on authBeforeLogin returns "beforeLogin" // // This function is auto-generated. @@ -103,21 +89,6 @@ func (authAfterSignup) EventType() string { return "afterSignup" } -// AuthOnManual creates onManual for system:auth resource -// -// This function is auto-generated. -func AuthOnManual( - argUser *types.User, - argProvider *types.AuthProvider, -) *authOnManual { - return &authOnManual{ - authBase: &authBase{ - user: argUser, - provider: argProvider, - }, - } -} - // AuthBeforeLogin creates beforeLogin for system:auth resource // // This function is auto-generated. diff --git a/system/service/event/events.yaml b/system/service/event/events.yaml index 7fe222de1..03b16e9e0 100644 --- a/system/service/event/events.yaml +++ b/system/service/event/events.yaml @@ -8,13 +8,12 @@ system:sink: type: '*types.SinkRequest' system:mail: - on: ['receive', 'send'] + on: ['manual', 'receive', 'send'] props: - name: 'request' type: '*types.MailMessage' system:auth: - on: ['manual'] ba: ['login', 'signup'] props: - name: 'user' diff --git a/system/service/event/mail.gen.go b/system/service/event/mail.gen.go index ea593dce7..cca479be1 100644 --- a/system/service/event/mail.gen.go +++ b/system/service/event/mail.gen.go @@ -24,6 +24,13 @@ type ( invoker auth.Identifiable } + // mailOnManual + // + // This type is auto-generated. + mailOnManual struct { + *mailBase + } + // mailOnReceive // // This type is auto-generated. @@ -46,6 +53,13 @@ func (mailBase) ResourceType() string { return "system:mail" } +// EventType on mailOnManual returns "onManual" +// +// This function is auto-generated. +func (mailOnManual) EventType() string { + return "onManual" +} + // EventType on mailOnReceive returns "onReceive" // // This function is auto-generated. @@ -60,6 +74,19 @@ func (mailOnSend) EventType() string { return "onSend" } +// MailOnManual creates onManual for system:mail resource +// +// This function is auto-generated. +func MailOnManual( + argRequest *types.MailMessage, +) *mailOnManual { + return &mailOnManual{ + mailBase: &mailBase{ + request: argRequest, + }, + } +} + // MailOnReceive creates onReceive for system:mail resource // // This function is auto-generated.