From 6e5047bd227349d1df464c5a436699206849dbcd Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Thu, 26 Mar 2020 15:30:01 +0100 Subject: [PATCH] Add ability to manually trigger record iterator via API --- api/compose/spec.json | 16 +++++++++ api/compose/spec/record.json | 16 +++++++++ compose/rest/handlers/record.go | 51 ++++++++++++++++++++-------- compose/rest/record.go | 21 ++++++++++++ compose/rest/request/record.go | 59 +++++++++++++++++++++++++++++++++ docs/compose/README.md | 18 ++++++++++ 6 files changed, 167 insertions(+), 14 deletions(-) diff --git a/api/compose/spec.json b/api/compose/spec.json index ef069152b..1dce8061c 100644 --- a/api/compose/spec.json +++ b/api/compose/spec.json @@ -1073,6 +1073,22 @@ } ] } + }, + { + "name": "triggerScriptOnList", + "method": "POST", + "title": "Fire compose:record trigger", + "path": "/trigger", + "parameters": { + "post": [ + { + "name": "script", + "type": "string", + "title": "Script to execute", + "required": true + } + ] + } } ] }, diff --git a/api/compose/spec/record.json b/api/compose/spec/record.json index abace7375..6b689b938 100644 --- a/api/compose/spec/record.json +++ b/api/compose/spec/record.json @@ -364,6 +364,22 @@ } ] } + }, + { + "Name": "triggerScriptOnList", + "Method": "POST", + "Title": "Fire compose:record trigger", + "Path": "/trigger", + "Parameters": { + "post": [ + { + "name": "script", + "required": true, + "title": "Script to execute", + "type": "string" + } + ] + } } ] } \ No newline at end of file diff --git a/compose/rest/handlers/record.go b/compose/rest/handlers/record.go index 62b4b3961..a81041177 100644 --- a/compose/rest/handlers/record.go +++ b/compose/rest/handlers/record.go @@ -43,24 +43,26 @@ type RecordAPI interface { Delete(context.Context, *request.RecordDelete) (interface{}, error) Upload(context.Context, *request.RecordUpload) (interface{}, error) TriggerScript(context.Context, *request.RecordTriggerScript) (interface{}, error) + TriggerScriptOnList(context.Context, *request.RecordTriggerScriptOnList) (interface{}, error) } // HTTP API interface type Record struct { - Report func(http.ResponseWriter, *http.Request) - List func(http.ResponseWriter, *http.Request) - ImportInit func(http.ResponseWriter, *http.Request) - ImportRun func(http.ResponseWriter, *http.Request) - ImportProgress func(http.ResponseWriter, *http.Request) - Export func(http.ResponseWriter, *http.Request) - Exec func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) - Read func(http.ResponseWriter, *http.Request) - Update func(http.ResponseWriter, *http.Request) - BulkDelete func(http.ResponseWriter, *http.Request) - Delete func(http.ResponseWriter, *http.Request) - Upload func(http.ResponseWriter, *http.Request) - TriggerScript func(http.ResponseWriter, *http.Request) + Report func(http.ResponseWriter, *http.Request) + List func(http.ResponseWriter, *http.Request) + ImportInit func(http.ResponseWriter, *http.Request) + ImportRun func(http.ResponseWriter, *http.Request) + ImportProgress func(http.ResponseWriter, *http.Request) + Export func(http.ResponseWriter, *http.Request) + Exec func(http.ResponseWriter, *http.Request) + Create func(http.ResponseWriter, *http.Request) + Read func(http.ResponseWriter, *http.Request) + Update func(http.ResponseWriter, *http.Request) + BulkDelete func(http.ResponseWriter, *http.Request) + Delete func(http.ResponseWriter, *http.Request) + Upload func(http.ResponseWriter, *http.Request) + TriggerScript func(http.ResponseWriter, *http.Request) + TriggerScriptOnList func(http.ResponseWriter, *http.Request) } func NewRecord(h RecordAPI) *Record { @@ -345,6 +347,26 @@ func NewRecord(h RecordAPI) *Record { resputil.JSON(w, value) } }, + TriggerScriptOnList: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewRecordTriggerScriptOnList() + if err := params.Fill(r); err != nil { + logger.LogParamError("Record.TriggerScriptOnList", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.TriggerScriptOnList(r.Context(), params) + if err != nil { + logger.LogControllerError("Record.TriggerScriptOnList", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("Record.TriggerScriptOnList", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, } } @@ -365,5 +387,6 @@ func (h Record) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http 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.TriggerScript) + r.Post("/namespace/{namespaceID}/module/{moduleID}/record/trigger", h.TriggerScriptOnList) }) } diff --git a/compose/rest/record.go b/compose/rest/record.go index 9da4dac19..ee8f27dd6 100644 --- a/compose/rest/record.go +++ b/compose/rest/record.go @@ -436,6 +436,27 @@ func (ctrl *Record) TriggerScript(ctx context.Context, r *request.RecordTriggerS return ctrl.makePayload(ctx, module, record, err) } +func (ctrl *Record) TriggerScriptOnList(ctx context.Context, r *request.RecordTriggerScriptOnList) (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 + //} + + // @todo this does not need to be under /record ... where then?!?! + err = corredor.Service().ExecIterator(ctx, r.Script) + + // Script can return modified record and we'll pass it on to the caller + return resputil.OK(), err +} + 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/record.go b/compose/rest/request/record.go index c75ad0d48..7c202834c 100644 --- a/compose/rest/request/record.go +++ b/compose/rest/request/record.go @@ -923,3 +923,62 @@ func (r *RecordTriggerScript) Fill(req *http.Request) (err error) { } var _ RequestFiller = NewRecordTriggerScript() + +// Record triggerScriptOnList request parameters +type RecordTriggerScriptOnList struct { + Script string + NamespaceID uint64 `json:",string"` + ModuleID uint64 `json:",string"` +} + +func NewRecordTriggerScriptOnList() *RecordTriggerScriptOnList { + return &RecordTriggerScriptOnList{} +} + +func (r RecordTriggerScriptOnList) Auditable() map[string]interface{} { + var out = map[string]interface{}{} + + out["script"] = r.Script + out["namespaceID"] = r.NamespaceID + out["moduleID"] = r.ModuleID + + return out +} + +func (r *RecordTriggerScriptOnList) 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 + } + r.NamespaceID = parseUInt64(chi.URLParam(req, "namespaceID")) + r.ModuleID = parseUInt64(chi.URLParam(req, "moduleID")) + + return err +} + +var _ RequestFiller = NewRecordTriggerScriptOnList() diff --git a/docs/compose/README.md b/docs/compose/README.md index 05b11da7d..9839b13ae 100644 --- a/docs/compose/README.md +++ b/docs/compose/README.md @@ -651,6 +651,7 @@ Compose pages | title | string | POST | Title | N/A | YES | | handle | string | POST | Handle | N/A | NO | | description | string | POST | Description | N/A | NO | +| weight | int | POST | Page tree weight | N/A | NO | | visible | bool | POST | Visible in navigation | N/A | NO | | blocks | sqlxTypes.JSONText | POST | Blocks JSON | N/A | NO | @@ -827,6 +828,7 @@ Compose records | `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 | +| `POST` | `/namespace/{namespaceID}/module/{moduleID}/record/trigger` | Fire compose:record trigger | ## Generates report from module records @@ -1069,6 +1071,22 @@ Compose records | script | string | POST | Script to execute | N/A | YES | | values | types.RecordValueSet | POST | Record values | N/A | YES | +## Fire compose:record trigger + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/namespace/{namespaceID}/module/{moduleID}/record/trigger` | HTTP/S | POST | | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | +| script | string | POST | Script to execute | N/A | YES | +| namespaceID | uint64 | PATH | Namespace ID | N/A | YES | +| moduleID | uint64 | PATH | Module ID | N/A | YES | + ---