diff --git a/lib/js/src/api-clients/automation.ts b/lib/js/src/api-clients/automation.ts index f3c99d147..14394dcab 100644 --- a/lib/js/src/api-clients/automation.ts +++ b/lib/js/src/api-clients/automation.ts @@ -191,6 +191,7 @@ export default class Automation { paths, runAs, ownedBy, + updatedAt, } = (a as KV) || {} if (!workflowID) { throw Error('field workflowID is empty') @@ -220,6 +221,7 @@ export default class Automation { paths, runAs, ownedBy, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -491,6 +493,7 @@ export default class Automation { meta, constraints, ownedBy, + updatedAt, } = (a as KV) || {} if (!triggerID) { throw Error('field triggerID is empty') @@ -528,6 +531,7 @@ export default class Automation { meta, constraints, ownedBy, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } diff --git a/lib/js/src/api-clients/compose.ts b/lib/js/src/api-clients/compose.ts index ce68e85cc..ce5d6286f 100644 --- a/lib/js/src/api-clients/compose.ts +++ b/lib/js/src/api-clients/compose.ts @@ -666,6 +666,7 @@ export default class Compose { blocks, config, meta, + updatedAt, } = (a as KV) || {} if (!namespaceID) { throw Error('field namespaceID is empty') @@ -695,6 +696,7 @@ export default class Compose { blocks, config, meta, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -1207,6 +1209,7 @@ export default class Compose { blocks, labels, ownedBy, + updatedAt, } = (a as KV) || {} if (!namespaceID) { throw Error('field namespaceID is empty') @@ -1234,6 +1237,7 @@ export default class Compose { blocks, labels, ownedBy, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -2139,6 +2143,7 @@ export default class Compose { ownedBy, meta, records, + updatedAt, } = (a as KV) || {} if (!namespaceID) { throw Error('field namespaceID is empty') @@ -2161,6 +2166,7 @@ export default class Compose { ownedBy, meta, records, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } diff --git a/lib/js/src/api-clients/system.ts b/lib/js/src/api-clients/system.ts index 2f5012109..a7e843068 100644 --- a/lib/js/src/api-clients/system.ts +++ b/lib/js/src/api-clients/system.ts @@ -202,6 +202,7 @@ export default class System { expiresAt, security, labels, + updatedAt, } = (a as KV) || {} if (!clientID) { throw Error('field clientID is empty') @@ -225,6 +226,7 @@ export default class System { expiresAt, security, labels, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -586,6 +588,7 @@ export default class System { members, meta, labels, + updatedAt, } = (a as KV) || {} if (!roleID) { throw Error('field roleID is empty') @@ -603,6 +606,7 @@ export default class System { members, meta, labels, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -1054,6 +1058,7 @@ export default class System { handle, kind, labels, + updatedAt, } = (a as KV) || {} if (!userID) { throw Error('field userID is empty') @@ -1077,6 +1082,7 @@ export default class System { handle, kind, labels, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -1701,6 +1707,7 @@ export default class System { handle, level, meta, + updatedAt, } = (a as KV) || {} if (!sensitivityLevelID) { throw Error('field sensitivityLevelID is empty') @@ -1722,6 +1729,7 @@ export default class System { handle, level, meta, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -1883,6 +1891,7 @@ export default class System { type, meta, config, + updatedAt, } = (a as KV) || {} if (!connectionID) { throw Error('field connectionID is empty') @@ -1908,6 +1917,7 @@ export default class System { type, meta, config, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -2079,6 +2089,7 @@ export default class System { unify, config, labels, + updatedAt, } = (a as KV) || {} if (!applicationID) { throw Error('field applicationID is empty') @@ -2100,6 +2111,7 @@ export default class System { unify, config, labels, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -3018,6 +3030,7 @@ export default class System { template, ownerID, labels, + updatedAt, } = (a as KV) || {} if (!templateID) { throw Error('field templateID is empty') @@ -3038,6 +3051,7 @@ export default class System { template, ownerID, labels, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -3236,6 +3250,7 @@ export default class System { sources, blocks, labels, + updatedAt, } = (a as KV) || {} if (!reportID) { throw Error('field reportID is empty') @@ -3254,6 +3269,7 @@ export default class System { sources, blocks, labels, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -3622,6 +3638,7 @@ export default class System { queue, consumer, meta, + updatedAt, } = (a as KV) || {} if (!queueID) { throw Error('field queueID is empty') @@ -3643,6 +3660,7 @@ export default class System { queue, consumer, meta, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -3783,6 +3801,7 @@ export default class System { enabled, group, meta, + updatedAt, } = (a as KV) || {} if (!routeID) { throw Error('field routeID is empty') @@ -3803,6 +3822,7 @@ export default class System { enabled, group, meta, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -3969,6 +3989,7 @@ export default class System { ref, enabled, params, + updatedAt, } = (a as KV) || {} if (!filterID) { throw Error('field filterID is empty') @@ -3990,6 +4011,7 @@ export default class System { ref, enabled, params, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } @@ -4334,6 +4356,7 @@ export default class System { place, message, ownerID, + updatedAt, } = (a as KV) || {} if (!translationID) { throw Error('field translationID is empty') @@ -4352,6 +4375,7 @@ export default class System { place, message, ownerID, + updatedAt, } return this.api().request(cfg).then(result => stdResolve(result)) } diff --git a/server/automation/rest.yaml b/server/automation/rest.yaml index bcbff3e4e..73970b670 100644 --- a/server/automation/rest.yaml +++ b/server/automation/rest.yaml @@ -14,6 +14,7 @@ endpoints: - github.com/cortezaproject/corteza/server/pkg/expr - github.com/cortezaproject/corteza/server/automation/types - github.com/cortezaproject/corteza/server/pkg/label + - time apis: - name: list method: GET @@ -66,6 +67,7 @@ endpoints: - { name: paths, type: "types.WorkflowPathSet", title: "Workflow step paths definition", parser: "types.ParseWorkflowPathSet" } - { name: runAs, type: uint64, required: true, title: "Is workflow enabled" } - { name: ownedBy, type: uint64, required: true, title: "Owner of the workflow" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET title: Read workflow details @@ -112,6 +114,7 @@ endpoints: - github.com/cortezaproject/corteza/server/automation/types - github.com/cortezaproject/corteza/server/pkg/expr - github.com/cortezaproject/corteza/server/pkg/label + - time apis: - name: list method: GET @@ -163,6 +166,7 @@ endpoints: - { name: meta, type: "*types.TriggerMeta", title: "Trigger meta data", parser: "types.ParseTriggerMeta" } - { name: constraints, type: "types.TriggerConstraintSet", title: "Workflow steps definition", parser: "types.ParseTriggerConstraintSet" } - { name: ownedBy, type: uint64, required: true, title: "Owner of the trigger" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET title: Read trigger details diff --git a/server/automation/rest/request/trigger.go b/server/automation/rest/request/trigger.go index 1f44974ea..495213fd3 100644 --- a/server/automation/rest/request/trigger.go +++ b/server/automation/rest/request/trigger.go @@ -20,6 +20,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -200,6 +201,11 @@ type ( // // Owner of the trigger OwnedBy uint64 `json:",string"` + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } TriggerRead struct { @@ -698,6 +704,7 @@ func (r TriggerUpdate) Auditable() map[string]interface{} { "meta": r.Meta, "constraints": r.Constraints, "ownedBy": r.OwnedBy, + "updatedAt": r.UpdatedAt, } } @@ -756,6 +763,11 @@ func (r TriggerUpdate) GetOwnedBy() uint64 { return r.OwnedBy } +// Auditable returns all auditable/loggable parameters +func (r TriggerUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *TriggerUpdate) Fill(req *http.Request) (err error) { @@ -866,6 +878,13 @@ func (r *TriggerUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -965,6 +984,13 @@ func (r *TriggerUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/automation/rest/request/workflow.go b/server/automation/rest/request/workflow.go index 81514d03c..409dba8f4 100644 --- a/server/automation/rest/request/workflow.go +++ b/server/automation/rest/request/workflow.go @@ -20,6 +20,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -205,6 +206,11 @@ type ( // // Owner of the workflow OwnedBy uint64 `json:",string"` + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } WorkflowRead struct { @@ -766,6 +772,7 @@ func (r WorkflowUpdate) Auditable() map[string]interface{} { "paths": r.Paths, "runAs": r.RunAs, "ownedBy": r.OwnedBy, + "updatedAt": r.UpdatedAt, } } @@ -829,6 +836,11 @@ func (r WorkflowUpdate) GetOwnedBy() uint64 { return r.OwnedBy } +// Auditable returns all auditable/loggable parameters +func (r WorkflowUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *WorkflowUpdate) Fill(req *http.Request) (err error) { @@ -951,6 +963,13 @@ func (r *WorkflowUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -1062,6 +1081,13 @@ func (r *WorkflowUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/automation/rest/trigger.go b/server/automation/rest/trigger.go index e7b6114cf..c28a425a4 100644 --- a/server/automation/rest/trigger.go +++ b/server/automation/rest/trigger.go @@ -90,6 +90,7 @@ func (ctrl Trigger) Update(ctx context.Context, r *request.TriggerUpdate) (inter Labels: r.Labels, OwnedBy: r.OwnedBy, Meta: r.Meta, + UpdatedAt: r.UpdatedAt, } return ctrl.svc.Update(ctx, trigger) diff --git a/server/automation/rest/workflow.go b/server/automation/rest/workflow.go index 19c6daaaf..5b018e69f 100644 --- a/server/automation/rest/workflow.go +++ b/server/automation/rest/workflow.go @@ -3,6 +3,7 @@ package rest import ( "context" "fmt" + "github.com/cortezaproject/corteza/server/automation/rest/request" "github.com/cortezaproject/corteza/server/automation/service" "github.com/cortezaproject/corteza/server/automation/types" @@ -138,6 +139,7 @@ func (ctrl Workflow) Update(ctx context.Context, r *request.WorkflowUpdate) (int Paths: r.Paths, RunAs: r.RunAs, OwnedBy: r.OwnedBy, + UpdatedAt: r.UpdatedAt, } wf, err := ctrl.svc.Update(ctx, workflow) diff --git a/server/compose/rest.yaml b/server/compose/rest.yaml index 92314835e..f453133b5 100644 --- a/server/compose/rest.yaml +++ b/server/compose/rest.yaml @@ -257,6 +257,7 @@ endpoints: - github.com/cortezaproject/corteza/server/pkg/label - github.com/cortezaproject/corteza/server/pkg/str - github.com/cortezaproject/corteza/server/compose/types + - time parameters: path: - type: uint64 @@ -421,6 +422,7 @@ endpoints: required: false title: Meta parser: types.ParsePageMeta + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: reorder method: POST title: Reorder pages @@ -571,6 +573,7 @@ endpoints: - github.com/cortezaproject/corteza/server/pkg/locale - github.com/cortezaproject/corteza/server/compose/types - github.com/cortezaproject/corteza/server/pkg/label + - time parameters: path: - type: uint64 @@ -772,6 +775,7 @@ endpoints: name: ownedBy required: false title: OwnedBy + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: reorder method: POST title: Reorder page layouts @@ -999,6 +1003,7 @@ endpoints: authentication: [] imports: - github.com/cortezaproject/corteza/server/compose/types + - time parameters: path: - type: uint64 @@ -1155,6 +1160,7 @@ endpoints: - { name: ownedBy, type: "uint64", title: Record Owner } - { name: meta, type: "map[string]any", title: Record meta-data, parser: payload.ParseMeta } - { name: records, type: "types.RecordBulkSet", title: Records } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: patch method: PATCH title: Partially update record values diff --git a/server/compose/rest/page.go b/server/compose/rest/page.go index c90d32943..462556960 100644 --- a/server/compose/rest/page.go +++ b/server/compose/rest/page.go @@ -2,6 +2,7 @@ package rest import ( "context" + "github.com/cortezaproject/corteza/server/compose/rest/request" "github.com/cortezaproject/corteza/server/compose/service" "github.com/cortezaproject/corteza/server/compose/service/event" @@ -170,6 +171,7 @@ func (ctrl *Page) Update(ctx context.Context, r *request.PageUpdate) (interface{ Weight: r.Weight, Labels: r.Labels, Meta: r.Meta, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/compose/rest/page_layout.go b/server/compose/rest/page_layout.go index 34f9a0d5f..176479862 100644 --- a/server/compose/rest/page_layout.go +++ b/server/compose/rest/page_layout.go @@ -167,6 +167,7 @@ func (ctrl *PageLayout) Update(ctx context.Context, r *request.PageLayoutUpdate) Meta: r.Meta, Labels: r.Labels, OwnedBy: r.OwnedBy, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/compose/rest/record.go b/server/compose/rest/record.go index f247d8f80..d8b3e4d35 100644 --- a/server/compose/rest/record.go +++ b/server/compose/rest/record.go @@ -284,6 +284,7 @@ func (ctrl *Record) Update(ctx context.Context, r *request.RecordUpdate) (interf Values: r.Values, Meta: r.Meta, OwnedBy: r.OwnedBy, + UpdatedAt: r.UpdatedAt, } oo = append(oo, &types.RecordBulkOperation{ diff --git a/server/compose/rest/request/page.go b/server/compose/rest/request/page.go index 0e19c78f0..59c060721 100644 --- a/server/compose/rest/request/page.go +++ b/server/compose/rest/request/page.go @@ -22,6 +22,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -231,6 +232,11 @@ type ( // // Meta Meta types.PageMeta + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } PageReorder struct { @@ -911,6 +917,7 @@ func (r PageUpdate) Auditable() map[string]interface{} { "blocks": r.Blocks, "config": r.Config, "meta": r.Meta, + "updatedAt": r.UpdatedAt, } } @@ -979,6 +986,11 @@ func (r PageUpdate) GetMeta() types.PageMeta { return r.Meta } +// Auditable returns all auditable/loggable parameters +func (r PageUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *PageUpdate) Fill(req *http.Request) (err error) { @@ -1086,6 +1098,13 @@ func (r *PageUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -1182,6 +1201,13 @@ func (r *PageUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/compose/rest/request/pageLayout.go b/server/compose/rest/request/pageLayout.go index 5544fd844..dc0bdb93b 100644 --- a/server/compose/rest/request/pageLayout.go +++ b/server/compose/rest/request/pageLayout.go @@ -21,6 +21,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -275,6 +276,11 @@ type ( // // OwnedBy OwnedBy uint64 `json:",string"` + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } PageLayoutReorder struct { @@ -1035,6 +1041,7 @@ func (r PageLayoutUpdate) Auditable() map[string]interface{} { "blocks": r.Blocks, "labels": r.Labels, "ownedBy": r.OwnedBy, + "updatedAt": r.UpdatedAt, } } @@ -1098,6 +1105,11 @@ func (r PageLayoutUpdate) GetOwnedBy() uint64 { return r.OwnedBy } +// Auditable returns all auditable/loggable parameters +func (r PageLayoutUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *PageLayoutUpdate) Fill(req *http.Request) (err error) { @@ -1191,6 +1203,13 @@ func (r *PageLayoutUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -1273,6 +1292,13 @@ func (r *PageLayoutUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/compose/rest/request/record.go b/server/compose/rest/request/record.go index 06e8ea1ea..64fc58bf2 100644 --- a/server/compose/rest/request/record.go +++ b/server/compose/rest/request/record.go @@ -18,6 +18,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -317,6 +318,11 @@ type ( // // Records Records types.RecordBulkSet + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } RecordPatch struct { @@ -1469,6 +1475,7 @@ func (r RecordUpdate) Auditable() map[string]interface{} { "ownedBy": r.OwnedBy, "meta": r.Meta, "records": r.Records, + "updatedAt": r.UpdatedAt, } } @@ -1507,6 +1514,11 @@ func (r RecordUpdate) GetRecords() types.RecordBulkSet { return r.Records } +// Auditable returns all auditable/loggable parameters +func (r RecordUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *RecordUpdate) Fill(req *http.Request) (err error) { @@ -1547,6 +1559,12 @@ func (r *RecordUpdate) Fill(req *http.Request) (err error) { } } + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -1589,6 +1607,13 @@ func (r *RecordUpdate) Fill(req *http.Request) (err error) { // return err // } //} + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest.yaml b/server/system/rest.yaml index da0487421..25285eac0 100644 --- a/server/system/rest.yaml +++ b/server/system/rest.yaml @@ -99,6 +99,7 @@ endpoints: - { name: expiresAt, type: '*time.Time', title: Date and time from client is no logner valid } - { name: security, type: '*types.AuthClientSecurity', title: Security settings, allowed, denied, forced roles, parser: "types.ParseAuthClientSecurity" } - { name: labels, type: 'map[string]string', title: Labels, parser: label.ParseStrings } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET title: Read client details @@ -244,6 +245,7 @@ endpoints: imports: - github.com/cortezaproject/corteza/server/pkg/label - github.com/cortezaproject/corteza/server/system/types + - time apis: - name: list method: GET @@ -284,6 +286,7 @@ endpoints: - { type: "[]string", name: "members", required: false, title: "role member IDs" } - { type: "*types.RoleMeta", name: "meta", title: "Meta", parser: "types.ParseRoleMeta" } - { type: "map[string]string", name: "labels", title: "Labels", parser: "label.ParseStrings" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET title: Read role details and memberships @@ -445,6 +448,7 @@ endpoints: imports: - github.com/cortezaproject/corteza/server/pkg/label - github.com/cortezaproject/corteza/server/system/types + - time apis: - name: list method: GET @@ -569,6 +573,7 @@ endpoints: name: labels title: Labels parser: label.ParseStrings + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: partialUpdate method: PATCH title: Patch user (experimental) @@ -834,6 +839,7 @@ endpoints: - Session ID imports: - github.com/cortezaproject/corteza/server/system/types + - time apis: - name: list method: GET @@ -874,6 +880,7 @@ endpoints: - { name: "handle", type: "string", required: false } - { name: "level", type: "int", required: true } - { name: "meta", type: "types.DalSensitivityLevelMeta", required: true, parser: "types.ParseDalSensitivityLevelMeta" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET @@ -917,6 +924,7 @@ endpoints: - Session ID imports: - github.com/cortezaproject/corteza/server/system/types + - time apis: - name: list method: GET @@ -961,6 +969,7 @@ endpoints: - { name: type, type: "string", required: true } - { name: meta, type: "types.ConnectionMeta", required: true, parser: "types.ParseConnectionMeta" } - { name: config, type: "types.ConnectionConfig", required: true, parser: "types.ParseConnectionConfig" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET @@ -988,6 +997,7 @@ endpoints: imports: - github.com/cortezaproject/corteza/server/pkg/label - sqlxTypes github.com/jmoiron/sqlx/types + - time apis: - name: list method: GET @@ -1095,6 +1105,7 @@ endpoints: name: labels title: Labels parser: label.ParseStrings + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: upload path: "/upload" @@ -1533,6 +1544,7 @@ endpoints: imports: - github.com/cortezaproject/corteza/server/system/types - github.com/cortezaproject/corteza/server/pkg/label + - time authentication: - Client ID - SessionID @@ -1658,6 +1670,7 @@ endpoints: type: map[string]string title: Labels parser: label.ParseStrings + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: delete method: DELETE title: Delete template @@ -1718,6 +1731,7 @@ endpoints: - github.com/cortezaproject/corteza/server/pkg/label - github.com/cortezaproject/corteza/server/system/types - github.com/cortezaproject/corteza/server/system/reporting + - time apis: - name: list method: GET @@ -1782,6 +1796,7 @@ endpoints: - { name: sources, type: "types.ReportDataSourceSet", title: Report sources definition } - { name: blocks, type: "types.ReportBlockSet", title: Report blocks definition } - { name: labels, type: 'map[string]string', title: Labels, parser: label.ParseStrings } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET title: Read report details @@ -1948,6 +1963,7 @@ endpoints: path: "/queues" imports: - github.com/cortezaproject/corteza/server/system/types + - time apis: - name: list method: GET @@ -1988,6 +2004,7 @@ endpoints: - { type: string, name: queue, required: true, title: Name of queue } - { type: string, name: consumer, required: true, title: Queue consumer } - { type: "types.QueueMeta", name: meta, required: false, title: Meta data for queue, parser: "types.ParseQueueMeta" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: delete method: DELETE title: Messaging queue delete @@ -2010,6 +2027,7 @@ endpoints: imports: - github.com/cortezaproject/corteza/server/system/types - github.com/cortezaproject/corteza/server/pkg/label + - time apis: - name: list method: GET @@ -2049,6 +2067,7 @@ endpoints: - { name: enabled, type: bool, title: "Is route enabled" } - { name: group, type: uint64, title: "Route group" } - { name: meta, type: "types.ApigwRouteMeta", title: "Route meta", parser: "types.ParseApigwRouteMeta" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET title: Read route details @@ -2071,6 +2090,7 @@ endpoints: authentication: [] imports: - github.com/cortezaproject/corteza/server/system/types + - time apis: - name: list method: GET @@ -2109,6 +2129,7 @@ endpoints: - { name: ref, type: string, title: "Filter ref" } - { name: enabled, type: bool, title: "Is Filter enabled" } - { name: params, type: "types.ApigwFilterParams", title: "Filter parameters", parser: "types.ParseApigwfFilterParams" } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read method: GET title: Read filter details @@ -2181,6 +2202,8 @@ endpoints: - title: Locale entrypoint: locale path: "/locale" + imports: + - time apis: - name: list resource method: GET @@ -2223,6 +2246,7 @@ endpoints: - { name: place, type: int, title: place } - { name: message, type: string, title: Message } - { name: ownerID, type: uint64, title: OwnerID } + - { type: "*time.Time", name: updatedAt, required: false, title: Last update (or creation) date } - name: read resource method: GET diff --git a/server/system/rest/apigw_filter.go b/server/system/rest/apigw_filter.go index 72a662efb..0de67ad30 100644 --- a/server/system/rest/apigw_filter.go +++ b/server/system/rest/apigw_filter.go @@ -97,13 +97,14 @@ func (ctrl *ApigwFilter) Update(ctx context.Context, r *request.ApigwFilterUpdat var ( err error q = &types.ApigwFilter{ - ID: r.FilterID, - Route: r.RouteID, - Weight: r.Weight, - Kind: r.Kind, - Ref: r.Ref, - Enabled: r.Enabled, - Params: r.Params, + ID: r.FilterID, + Route: r.RouteID, + Weight: r.Weight, + Kind: r.Kind, + Ref: r.Ref, + Enabled: r.Enabled, + Params: r.Params, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/apigw_route.go b/server/system/rest/apigw_route.go index 323ae5d9e..ef4c6e9d8 100644 --- a/server/system/rest/apigw_route.go +++ b/server/system/rest/apigw_route.go @@ -107,12 +107,13 @@ func (ctrl *ApigwRoute) Update(ctx context.Context, r *request.ApigwRouteUpdate) var ( err error q = &types.ApigwRoute{ - ID: r.RouteID, - Endpoint: r.Endpoint, - Method: r.Method, - Group: r.Group, - Enabled: r.Enabled, - Meta: r.Meta, + ID: r.RouteID, + Endpoint: r.Endpoint, + Method: r.Method, + Group: r.Group, + Enabled: r.Enabled, + Meta: r.Meta, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/application.go b/server/system/rest/application.go index 336e29610..ba091530b 100644 --- a/server/system/rest/application.go +++ b/server/system/rest/application.go @@ -117,11 +117,12 @@ func (ctrl *Application) Update(ctx context.Context, r *request.ApplicationUpdat var ( err error app = &types.Application{ - ID: r.ApplicationID, - Name: r.Name, - Enabled: r.Enabled, - Weight: r.Weight, - Labels: r.Labels, + ID: r.ApplicationID, + Name: r.Name, + Enabled: r.Enabled, + Weight: r.Weight, + Labels: r.Labels, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/auth_client.go b/server/system/rest/auth_client.go index 1ed60c6d7..1e12ebbc2 100644 --- a/server/system/rest/auth_client.go +++ b/server/system/rest/auth_client.go @@ -122,6 +122,7 @@ func (ctrl *AuthClient) Update(ctx context.Context, r *request.AuthClientUpdate) ExpiresAt: r.ExpiresAt, Security: r.Security, Labels: r.Labels, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/dal_connection.go b/server/system/rest/dal_connection.go index 369acf951..f60b31126 100644 --- a/server/system/rest/dal_connection.go +++ b/server/system/rest/dal_connection.go @@ -117,11 +117,12 @@ func (ctrl DalConnection) Create(ctx context.Context, r *request.DalConnectionCr func (ctrl DalConnection) Update(ctx context.Context, r *request.DalConnectionUpdate) (interface{}, error) { connection := &types.DalConnection{ - ID: r.ConnectionID, - Handle: r.Handle, - Type: r.Type, - Meta: r.Meta, - Config: r.Config, + ID: r.ConnectionID, + Handle: r.Handle, + Type: r.Type, + Meta: r.Meta, + Config: r.Config, + UpdatedAt: r.UpdatedAt, } res, err := ctrl.svc.Update(ctx, connection) diff --git a/server/system/rest/queues.go b/server/system/rest/queues.go index 19d29224b..780752dd7 100644 --- a/server/system/rest/queues.go +++ b/server/system/rest/queues.go @@ -101,10 +101,11 @@ func (ctrl *Queue) Update(ctx context.Context, r *request.QueuesUpdate) (interfa var ( err error q = &types.Queue{ - ID: r.QueueID, - Consumer: r.Consumer, - Queue: r.Queue, - Meta: r.Meta, + ID: r.QueueID, + Consumer: r.Consumer, + Queue: r.Queue, + Meta: r.Meta, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/report.go b/server/system/rest/report.go index 43c4b84c0..52b13848f 100644 --- a/server/system/rest/report.go +++ b/server/system/rest/report.go @@ -117,6 +117,7 @@ func (ctrl *Report) Update(ctx context.Context, r *request.ReportUpdate) (interf Sources: r.Sources, Blocks: r.Blocks, Labels: r.Labels, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/request/apigwFilter.go b/server/system/rest/request/apigwFilter.go index e607474ba..6844a01f4 100644 --- a/server/system/rest/request/apigwFilter.go +++ b/server/system/rest/request/apigwFilter.go @@ -18,6 +18,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -133,6 +134,11 @@ type ( // // Filter parameters Params types.ApigwFilterParams + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } ApigwFilterRead struct { @@ -445,13 +451,14 @@ func NewApigwFilterUpdate() *ApigwFilterUpdate { // Auditable returns all auditable/loggable parameters func (r ApigwFilterUpdate) Auditable() map[string]interface{} { return map[string]interface{}{ - "filterID": r.FilterID, - "routeID": r.RouteID, - "weight": r.Weight, - "kind": r.Kind, - "ref": r.Ref, - "enabled": r.Enabled, - "params": r.Params, + "filterID": r.FilterID, + "routeID": r.RouteID, + "weight": r.Weight, + "kind": r.Kind, + "ref": r.Ref, + "enabled": r.Enabled, + "params": r.Params, + "updatedAt": r.UpdatedAt, } } @@ -490,6 +497,11 @@ func (r ApigwFilterUpdate) GetParams() types.ApigwFilterParams { return r.Params } +// Auditable returns all auditable/loggable parameters +func (r ApigwFilterUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *ApigwFilterUpdate) Fill(req *http.Request) (err error) { @@ -557,6 +569,13 @@ func (r *ApigwFilterUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -613,6 +632,13 @@ func (r *ApigwFilterUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/apigwRoute.go b/server/system/rest/request/apigwRoute.go index f72013c10..6f170830d 100644 --- a/server/system/rest/request/apigwRoute.go +++ b/server/system/rest/request/apigwRoute.go @@ -19,6 +19,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -139,6 +140,11 @@ type ( // // Route meta Meta types.ApigwRouteMeta + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } ApigwRouteRead struct { @@ -467,12 +473,13 @@ func NewApigwRouteUpdate() *ApigwRouteUpdate { // Auditable returns all auditable/loggable parameters func (r ApigwRouteUpdate) Auditable() map[string]interface{} { return map[string]interface{}{ - "routeID": r.RouteID, - "endpoint": r.Endpoint, - "method": r.Method, - "enabled": r.Enabled, - "group": r.Group, - "meta": r.Meta, + "routeID": r.RouteID, + "endpoint": r.Endpoint, + "method": r.Method, + "enabled": r.Enabled, + "group": r.Group, + "meta": r.Meta, + "updatedAt": r.UpdatedAt, } } @@ -506,6 +513,11 @@ func (r ApigwRouteUpdate) GetMeta() types.ApigwRouteMeta { return r.Meta } +// Auditable returns all auditable/loggable parameters +func (r ApigwRouteUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *ApigwRouteUpdate) Fill(req *http.Request) (err error) { @@ -566,6 +578,13 @@ func (r *ApigwRouteUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -615,6 +634,13 @@ func (r *ApigwRouteUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/application.go b/server/system/rest/request/application.go index 1a4e53bf9..26c4c82c6 100644 --- a/server/system/rest/request/application.go +++ b/server/system/rest/request/application.go @@ -19,6 +19,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -154,6 +155,11 @@ type ( // // Labels Labels map[string]string + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } ApplicationUpload struct { @@ -591,6 +597,7 @@ func (r ApplicationUpdate) Auditable() map[string]interface{} { "unify": r.Unify, "config": r.Config, "labels": r.Labels, + "updatedAt": r.UpdatedAt, } } @@ -629,6 +636,11 @@ func (r ApplicationUpdate) GetLabels() map[string]string { return r.Labels } +// Auditable returns all auditable/loggable parameters +func (r ApplicationUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *ApplicationUpdate) Fill(req *http.Request) (err error) { @@ -696,6 +708,13 @@ func (r *ApplicationUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -752,6 +771,13 @@ func (r *ApplicationUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/authClient.go b/server/system/rest/request/authClient.go index 22d2981af..83717bd98 100644 --- a/server/system/rest/request/authClient.go +++ b/server/system/rest/request/authClient.go @@ -190,6 +190,11 @@ type ( // // Labels Labels map[string]string + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } AuthClientRead struct { @@ -655,6 +660,7 @@ func (r AuthClientUpdate) Auditable() map[string]interface{} { "expiresAt": r.ExpiresAt, "security": r.Security, "labels": r.Labels, + "updatedAt": r.UpdatedAt, } } @@ -718,6 +724,11 @@ func (r AuthClientUpdate) GetLabels() map[string]string { return r.Labels } +// Auditable returns all auditable/loggable parameters +func (r AuthClientUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *AuthClientUpdate) Fill(req *http.Request) (err error) { @@ -830,6 +841,13 @@ func (r *AuthClientUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -931,6 +949,13 @@ func (r *AuthClientUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/dalConnection.go b/server/system/rest/request/dalConnection.go index 95a3139aa..dd5124b6f 100644 --- a/server/system/rest/request/dalConnection.go +++ b/server/system/rest/request/dalConnection.go @@ -18,6 +18,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -108,6 +109,11 @@ type ( // // Config types.ConnectionConfig + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } DalConnectionRead struct { @@ -378,6 +384,7 @@ func (r DalConnectionUpdate) Auditable() map[string]interface{} { "type": r.Type, "meta": r.Meta, "config": r.Config, + "updatedAt": r.UpdatedAt, } } @@ -406,6 +413,11 @@ func (r DalConnectionUpdate) GetConfig() types.ConnectionConfig { return r.Config } +// Auditable returns all auditable/loggable parameters +func (r DalConnectionUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *DalConnectionUpdate) Fill(req *http.Request) (err error) { @@ -464,6 +476,13 @@ func (r *DalConnectionUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -511,6 +530,13 @@ func (r *DalConnectionUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/dalSensitivityLevel.go b/server/system/rest/request/dalSensitivityLevel.go index 57f5174e4..65010c7b1 100644 --- a/server/system/rest/request/dalSensitivityLevel.go +++ b/server/system/rest/request/dalSensitivityLevel.go @@ -18,6 +18,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -88,6 +89,11 @@ type ( // // Meta types.DalSensitivityLevelMeta + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } DalSensitivityLevelRead struct { @@ -303,6 +309,7 @@ func (r DalSensitivityLevelUpdate) Auditable() map[string]interface{} { "handle": r.Handle, "level": r.Level, "meta": r.Meta, + "updatedAt": r.UpdatedAt, } } @@ -326,6 +333,11 @@ func (r DalSensitivityLevelUpdate) GetMeta() types.DalSensitivityLevelMeta { return r.Meta } +// Auditable returns all auditable/loggable parameters +func (r DalSensitivityLevelUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *DalSensitivityLevelUpdate) Fill(req *http.Request) (err error) { @@ -372,6 +384,13 @@ func (r *DalSensitivityLevelUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -407,6 +426,13 @@ func (r *DalSensitivityLevelUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/locale.go b/server/system/rest/request/locale.go index 1dc615b1d..442c52045 100644 --- a/server/system/rest/request/locale.go +++ b/server/system/rest/request/locale.go @@ -17,6 +17,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -142,6 +143,11 @@ type ( // // OwnerID OwnerID uint64 `json:",string"` + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } LocaleReadResource struct { @@ -480,6 +486,7 @@ func (r LocaleUpdateResource) Auditable() map[string]interface{} { "place": r.Place, "message": r.Message, "ownerID": r.OwnerID, + "updatedAt": r.UpdatedAt, } } @@ -518,6 +525,11 @@ func (r LocaleUpdateResource) GetOwnerID() uint64 { return r.OwnerID } +// Auditable returns all auditable/loggable parameters +func (r LocaleUpdateResource) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *LocaleUpdateResource) Fill(req *http.Request) (err error) { @@ -580,6 +592,13 @@ func (r *LocaleUpdateResource) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -631,6 +650,13 @@ func (r *LocaleUpdateResource) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/queues.go b/server/system/rest/request/queues.go index 7a6e934d7..b4ccc9ce1 100644 --- a/server/system/rest/request/queues.go +++ b/server/system/rest/request/queues.go @@ -18,6 +18,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -110,6 +111,11 @@ type ( // // Meta data for queue Meta types.QueueMeta + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } QueuesDelete struct { @@ -380,10 +386,11 @@ func NewQueuesUpdate() *QueuesUpdate { // Auditable returns all auditable/loggable parameters func (r QueuesUpdate) Auditable() map[string]interface{} { return map[string]interface{}{ - "queueID": r.QueueID, - "queue": r.Queue, - "consumer": r.Consumer, - "meta": r.Meta, + "queueID": r.QueueID, + "queue": r.Queue, + "consumer": r.Consumer, + "meta": r.Meta, + "updatedAt": r.UpdatedAt, } } @@ -407,6 +414,11 @@ func (r QueuesUpdate) GetMeta() types.QueueMeta { return r.Meta } +// Auditable returns all auditable/loggable parameters +func (r QueuesUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *QueuesUpdate) Fill(req *http.Request) (err error) { @@ -453,6 +465,13 @@ func (r *QueuesUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -488,6 +507,13 @@ func (r *QueuesUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/report.go b/server/system/rest/request/report.go index 67d459551..296d16548 100644 --- a/server/system/rest/request/report.go +++ b/server/system/rest/request/report.go @@ -20,6 +20,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -145,6 +146,11 @@ type ( // // Labels Labels map[string]string + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } ReportRead struct { @@ -501,6 +507,7 @@ func (r ReportUpdate) Auditable() map[string]interface{} { "sources": r.Sources, "blocks": r.Blocks, "labels": r.Labels, + "updatedAt": r.UpdatedAt, } } @@ -539,6 +546,11 @@ func (r ReportUpdate) GetLabels() map[string]string { return r.Labels } +// Auditable returns all auditable/loggable parameters +func (r ReportUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *ReportUpdate) Fill(req *http.Request) (err error) { @@ -590,6 +602,13 @@ func (r *ReportUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -651,6 +670,13 @@ func (r *ReportUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/role.go b/server/system/rest/request/role.go index 3d0c909ad..7772f0088 100644 --- a/server/system/rest/request/role.go +++ b/server/system/rest/request/role.go @@ -19,6 +19,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -139,6 +140,11 @@ type ( // // Labels Labels map[string]string + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } RoleRead struct { @@ -563,12 +569,13 @@ func NewRoleUpdate() *RoleUpdate { // Auditable returns all auditable/loggable parameters func (r RoleUpdate) Auditable() map[string]interface{} { return map[string]interface{}{ - "roleID": r.RoleID, - "name": r.Name, - "handle": r.Handle, - "members": r.Members, - "meta": r.Meta, - "labels": r.Labels, + "roleID": r.RoleID, + "name": r.Name, + "handle": r.Handle, + "members": r.Members, + "meta": r.Meta, + "labels": r.Labels, + "updatedAt": r.UpdatedAt, } } @@ -602,6 +609,11 @@ func (r RoleUpdate) GetLabels() map[string]string { return r.Labels } +// Auditable returns all auditable/loggable parameters +func (r RoleUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *RoleUpdate) Fill(req *http.Request) (err error) { @@ -660,6 +672,13 @@ func (r *RoleUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -714,6 +733,13 @@ func (r *RoleUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/template.go b/server/system/rest/request/template.go index a7c17037d..36ad73db4 100644 --- a/server/system/rest/request/template.go +++ b/server/system/rest/request/template.go @@ -19,6 +19,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -186,6 +187,11 @@ type ( // // Labels Labels map[string]string + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } TemplateDelete struct { @@ -670,6 +676,7 @@ func (r TemplateUpdate) Auditable() map[string]interface{} { "template": r.Template, "ownerID": r.OwnerID, "labels": r.Labels, + "updatedAt": r.UpdatedAt, } } @@ -718,6 +725,11 @@ func (r TemplateUpdate) GetLabels() map[string]string { return r.Labels } +// Auditable returns all auditable/loggable parameters +func (r TemplateUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *TemplateUpdate) Fill(req *http.Request) (err error) { @@ -804,6 +816,13 @@ func (r *TemplateUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -879,6 +898,13 @@ func (r *TemplateUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/request/user.go b/server/system/rest/request/user.go index c28d858b3..7d8375db6 100644 --- a/server/system/rest/request/user.go +++ b/server/system/rest/request/user.go @@ -19,6 +19,7 @@ import ( "mime/multipart" "net/http" "strings" + "time" ) // dummy vars to prevent @@ -174,6 +175,11 @@ type ( // // Labels Labels map[string]string + + // UpdatedAt POST parameter + // + // Last update (or creation) date + UpdatedAt *time.Time } UserPartialUpdate struct { @@ -768,12 +774,13 @@ func NewUserUpdate() *UserUpdate { // Auditable returns all auditable/loggable parameters func (r UserUpdate) Auditable() map[string]interface{} { return map[string]interface{}{ - "userID": r.UserID, - "email": r.Email, - "name": r.Name, - "handle": r.Handle, - "kind": r.Kind, - "labels": r.Labels, + "userID": r.UserID, + "email": r.Email, + "name": r.Name, + "handle": r.Handle, + "kind": r.Kind, + "labels": r.Labels, + "updatedAt": r.UpdatedAt, } } @@ -807,6 +814,11 @@ func (r UserUpdate) GetLabels() map[string]string { return r.Labels } +// Auditable returns all auditable/loggable parameters +func (r UserUpdate) GetUpdatedAt() *time.Time { + return r.UpdatedAt +} + // Fill processes request and fills internal variables func (r *UserUpdate) Fill(req *http.Request) (err error) { @@ -867,6 +879,13 @@ func (r *UserUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.MultipartForm.Value["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } } @@ -916,6 +935,13 @@ func (r *UserUpdate) Fill(req *http.Request) (err error) { return err } } + + if val, ok := req.Form["updatedAt"]; ok && len(val) > 0 { + r.UpdatedAt, err = payload.ParseISODatePtrWithErr(val[0]) + if err != nil { + return err + } + } } { diff --git a/server/system/rest/role.go b/server/system/rest/role.go index dd62a2617..649d84898 100644 --- a/server/system/rest/role.go +++ b/server/system/rest/role.go @@ -2,6 +2,7 @@ package rest import ( "context" + "github.com/cortezaproject/corteza/server/pkg/api" "github.com/cortezaproject/corteza/server/pkg/auth" "github.com/cortezaproject/corteza/server/pkg/corredor" @@ -115,11 +116,12 @@ func (ctrl Role) Update(ctx context.Context, r *request.RoleUpdate) (interface{} var ( err error role = &types.Role{ - ID: r.RoleID, - Name: r.Name, - Handle: r.Handle, - Labels: r.Labels, - Meta: r.Meta, + ID: r.RoleID, + Name: r.Name, + Handle: r.Handle, + Labels: r.Labels, + Meta: r.Meta, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/sensitivity_level.go b/server/system/rest/sensitivity_level.go index 270f792ff..2e7890328 100644 --- a/server/system/rest/sensitivity_level.go +++ b/server/system/rest/sensitivity_level.go @@ -77,10 +77,11 @@ func (ctrl SensitivityLevel) Create(ctx context.Context, r *request.DalSensitivi func (ctrl SensitivityLevel) Update(ctx context.Context, r *request.DalSensitivityLevelUpdate) (interface{}, error) { sensitivityLevel := &types.DalSensitivityLevel{ - ID: r.SensitivityLevelID, - Handle: r.Handle, - Level: r.Level, - Meta: r.Meta, + ID: r.SensitivityLevelID, + Handle: r.Handle, + Level: r.Level, + Meta: r.Meta, + UpdatedAt: r.UpdatedAt, } return ctrl.svc.Update(ctx, sensitivityLevel) diff --git a/server/system/rest/template.go b/server/system/rest/template.go index a6bfabb11..d89842263 100644 --- a/server/system/rest/template.go +++ b/server/system/rest/template.go @@ -114,14 +114,15 @@ func (ctrl *Template) Update(ctx context.Context, r *request.TemplateUpdate) (in var ( err error app = &types.Template{ - ID: r.TemplateID, - Handle: r.Handle, - Language: r.Language, - Type: types.DocumentType(r.Type), - Partial: r.Partial, - Meta: r.Meta, - Template: r.Template, - OwnerID: r.OwnerID, + ID: r.TemplateID, + Handle: r.Handle, + Language: r.Language, + Type: types.DocumentType(r.Type), + Partial: r.Partial, + Meta: r.Meta, + Template: r.Template, + OwnerID: r.OwnerID, + UpdatedAt: r.UpdatedAt, } ) diff --git a/server/system/rest/user.go b/server/system/rest/user.go index 9b64660d6..9c1521fce 100644 --- a/server/system/rest/user.go +++ b/server/system/rest/user.go @@ -147,12 +147,13 @@ func (ctrl User) Create(ctx context.Context, r *request.UserCreate) (interface{} func (ctrl User) Update(ctx context.Context, r *request.UserUpdate) (interface{}, error) { user := &types.User{ - ID: r.UserID, - Email: r.Email, - Name: r.Name, - Handle: r.Handle, - Kind: r.Kind, - Labels: r.Labels, + ID: r.UserID, + Email: r.Email, + Name: r.Name, + Handle: r.Handle, + Kind: r.Kind, + Labels: r.Labels, + UpdatedAt: r.UpdatedAt, } res, err := ctrl.user.Update(ctx, user) diff --git a/server/system/service/apigw_filter.go b/server/system/service/apigw_filter.go index e23d04d03..7a68d9606 100644 --- a/server/system/service/apigw_filter.go +++ b/server/system/service/apigw_filter.go @@ -156,6 +156,11 @@ func (svc *apigwFilter) Update(ctx context.Context, upd *types.ApigwFilter) (q * return ApigwRouteErrNotAllowedToUpdate() } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, qq.UpdatedAt, qq.CreatedAt) { + return ApigwFilterErrStaleData() + } + if qq, e = store.LookupApigwFilterByID(ctx, svc.store, upd.ID); e == nil && qq == nil { return ApigwFilterErrNotFound(qProps) } diff --git a/server/system/service/apigw_filter_actions.gen.go b/server/system/service/apigw_filter_actions.gen.go index 18fb192f2..28160fade 100644 --- a/server/system/service/apigw_filter_actions.gen.go +++ b/server/system/service/apigw_filter_actions.gen.go @@ -435,6 +435,40 @@ func ApigwFilterErrInvalidRoute(mm ...*apigwFilterActionProps) *errors.Error { return e } +// ApigwFilterErrStaleData returns "system:filter.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func ApigwFilterErrStaleData(mm ...*apigwFilterActionProps) *errors.Error { + var p = &apigwFilterActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:filter"), + + errors.Meta(apigwFilterPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "apigw-filter.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // ApigwFilterErrAsyncRouteTooManyProcessers returns "system:filter.asyncRouteTooManyProcessers" as *errors.Error // // diff --git a/server/system/service/apigw_filter_actions.yaml b/server/system/service/apigw_filter_actions.yaml index d62912ba6..bfdfaf375 100644 --- a/server/system/service/apigw_filter_actions.yaml +++ b/server/system/service/apigw_filter_actions.yaml @@ -54,6 +54,10 @@ errors: message: "invalid route" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: asyncRouteTooManyProcessers message: "processer already exists for this async route" log: "failed to add {{filter}}; too many processers, async route" diff --git a/server/system/service/apigw_route.go b/server/system/service/apigw_route.go index 3a2fba9c5..25159a025 100644 --- a/server/system/service/apigw_route.go +++ b/server/system/service/apigw_route.go @@ -2,6 +2,7 @@ package service import ( "context" + "github.com/cortezaproject/corteza/server/pkg/actionlog" "github.com/cortezaproject/corteza/server/pkg/apigw" a "github.com/cortezaproject/corteza/server/pkg/auth" @@ -117,6 +118,11 @@ func (svc *apigwRoute) Update(ctx context.Context, upd *types.ApigwRoute) (res * return ApigwRouteErrNotAllowedToUpdate(qProps) } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, res.UpdatedAt, res.CreatedAt) { + return ApigwRouteErrStaleData() + } + // copy (potentially) updated files from the payload res.Meta = upd.Meta res.Method = upd.Method diff --git a/server/system/service/apigw_route_actions.gen.go b/server/system/service/apigw_route_actions.gen.go index 02de07ae8..2bc9cc5a4 100644 --- a/server/system/service/apigw_route_actions.gen.go +++ b/server/system/service/apigw_route_actions.gen.go @@ -487,6 +487,40 @@ func ApigwRouteErrInvalidEndpoint(mm ...*apigwRouteActionProps) *errors.Error { return e } +// ApigwRouteErrStaleData returns "system:apigw-route.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func ApigwRouteErrStaleData(mm ...*apigwRouteActionProps) *errors.Error { + var p = &apigwRouteActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:apigw-route"), + + errors.Meta(apigwRoutePropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "apigw-route.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // ApigwRouteErrExistsEndpoint returns "system:apigw-route.existsEndpoint" as *errors.Error // // diff --git a/server/system/service/apigw_route_actions.yaml b/server/system/service/apigw_route_actions.yaml index 49a8781bc..42a6caa81 100644 --- a/server/system/service/apigw_route_actions.yaml +++ b/server/system/service/apigw_route_actions.yaml @@ -60,6 +60,10 @@ errors: message: "invalid endpoint" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: existsEndpoint message: "route with this endpoint already exists" severity: warning diff --git a/server/system/service/application.go b/server/system/service/application.go index 52acf2a80..2a7444d85 100644 --- a/server/system/service/application.go +++ b/server/system/service/application.go @@ -2,6 +2,7 @@ package service import ( "context" + "github.com/cortezaproject/corteza/server/pkg/errors" "github.com/cortezaproject/corteza/server/pkg/actionlog" @@ -203,6 +204,11 @@ func (svc *application) Update(ctx context.Context, upd *types.Application) (app return ApplicationErrNotAllowedToUpdate() } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, app.UpdatedAt, app.CreatedAt) { + return ApplicationErrStaleData() + } + if err = svc.eventbus.WaitFor(ctx, event.ApplicationBeforeUpdate(upd, app)); err != nil { return } diff --git a/server/system/service/application_actions.gen.go b/server/system/service/application_actions.gen.go index ebe4fc0e7..525e18e0a 100644 --- a/server/system/service/application_actions.gen.go +++ b/server/system/service/application_actions.gen.go @@ -526,6 +526,40 @@ func ApplicationErrInvalidID(mm ...*applicationActionProps) *errors.Error { return e } +// ApplicationErrStaleData returns "system:application.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func ApplicationErrStaleData(mm ...*applicationActionProps) *errors.Error { + var p = &applicationActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:application"), + + errors.Meta(applicationPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "application.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // ApplicationErrNotAllowedToRead returns "system:application.notAllowedToRead" as *errors.Error // // diff --git a/server/system/service/application_actions.yaml b/server/system/service/application_actions.yaml index 380f08859..bacfbc394 100644 --- a/server/system/service/application_actions.yaml +++ b/server/system/service/application_actions.yaml @@ -65,6 +65,10 @@ errors: message: "invalid ID" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: notAllowedToRead message: "not allowed to read this application" log: "failed to read {{application.name}}; insufficient permissions" diff --git a/server/system/service/attachment_actions.gen.go b/server/system/service/attachment_actions.gen.go index 4b9080f5d..18592e780 100644 --- a/server/system/service/attachment_actions.gen.go +++ b/server/system/service/attachment_actions.gen.go @@ -57,6 +57,7 @@ var ( // setSize updates attachmentActionProps's size // // This function is auto-generated. +// func (p *attachmentActionProps) setSize(size int64) *attachmentActionProps { p.size = size return p @@ -65,6 +66,7 @@ func (p *attachmentActionProps) setSize(size int64) *attachmentActionProps { // setName updates attachmentActionProps's name // // This function is auto-generated. +// func (p *attachmentActionProps) setName(name string) *attachmentActionProps { p.name = name return p @@ -73,6 +75,7 @@ func (p *attachmentActionProps) setName(name string) *attachmentActionProps { // setMimetype updates attachmentActionProps's mimetype // // This function is auto-generated. +// func (p *attachmentActionProps) setMimetype(mimetype string) *attachmentActionProps { p.mimetype = mimetype return p @@ -81,6 +84,7 @@ func (p *attachmentActionProps) setMimetype(mimetype string) *attachmentActionPr // setUrl updates attachmentActionProps's url // // This function is auto-generated. +// func (p *attachmentActionProps) setUrl(url string) *attachmentActionProps { p.url = url return p @@ -89,6 +93,7 @@ func (p *attachmentActionProps) setUrl(url string) *attachmentActionProps { // setAttachment updates attachmentActionProps's attachment // // This function is auto-generated. +// func (p *attachmentActionProps) setAttachment(attachment *types.Attachment) *attachmentActionProps { p.attachment = attachment return p @@ -97,6 +102,7 @@ func (p *attachmentActionProps) setAttachment(attachment *types.Attachment) *att // setFilter updates attachmentActionProps's filter // // This function is auto-generated. +// func (p *attachmentActionProps) setFilter(filter *types.AttachmentFilter) *attachmentActionProps { p.filter = filter return p @@ -105,6 +111,7 @@ func (p *attachmentActionProps) setFilter(filter *types.AttachmentFilter) *attac // Serialize converts attachmentActionProps to actionlog.Meta // // This function is auto-generated. +// func (p attachmentActionProps) Serialize() actionlog.Meta { var ( m = make(actionlog.Meta) @@ -135,6 +142,7 @@ func (p attachmentActionProps) Serialize() actionlog.Meta { // tr translates string and replaces meta value placeholder with values // // This function is auto-generated. +// func (p attachmentActionProps) Format(in string, err error) string { var ( pairs = []string{"{{err}}"} @@ -209,6 +217,7 @@ func (p attachmentActionProps) Format(in string, err error) string { // String returns loggable description as string // // This function is auto-generated. +// func (a *attachmentAction) String() string { var props = &attachmentActionProps{} @@ -236,6 +245,7 @@ func (e *attachmentAction) ToAction() *actionlog.Action { // AttachmentActionSearch returns "system:attachment.search" action // // This function is auto-generated. +// func AttachmentActionSearch(props ...*attachmentActionProps) *attachmentAction { a := &attachmentAction{ timestamp: time.Now(), @@ -255,6 +265,7 @@ func AttachmentActionSearch(props ...*attachmentActionProps) *attachmentAction { // AttachmentActionLookup returns "system:attachment.lookup" action // // This function is auto-generated. +// func AttachmentActionLookup(props ...*attachmentActionProps) *attachmentAction { a := &attachmentAction{ timestamp: time.Now(), @@ -274,6 +285,7 @@ func AttachmentActionLookup(props ...*attachmentActionProps) *attachmentAction { // AttachmentActionCreate returns "system:attachment.create" action // // This function is auto-generated. +// func AttachmentActionCreate(props ...*attachmentActionProps) *attachmentAction { a := &attachmentAction{ timestamp: time.Now(), @@ -293,6 +305,7 @@ func AttachmentActionCreate(props ...*attachmentActionProps) *attachmentAction { // AttachmentActionDelete returns "system:attachment.delete" action // // This function is auto-generated. +// func AttachmentActionDelete(props ...*attachmentActionProps) *attachmentAction { a := &attachmentAction{ timestamp: time.Now(), @@ -315,7 +328,9 @@ func AttachmentActionDelete(props ...*attachmentActionProps) *attachmentAction { // AttachmentErrGeneric returns "system:attachment.generic" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrGeneric(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -349,7 +364,9 @@ func AttachmentErrGeneric(mm ...*attachmentActionProps) *errors.Error { // AttachmentErrNotFound returns "system:attachment.notFound" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrNotFound(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -381,7 +398,9 @@ func AttachmentErrNotFound(mm ...*attachmentActionProps) *errors.Error { // AttachmentErrInvalidID returns "system:attachment.invalidID" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrInvalidID(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -413,7 +432,9 @@ func AttachmentErrInvalidID(mm ...*attachmentActionProps) *errors.Error { // AttachmentErrNotAllowedToListAttachments returns "system:attachment.notAllowedToListAttachments" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrNotAllowedToListAttachments(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -447,7 +468,9 @@ func AttachmentErrNotAllowedToListAttachments(mm ...*attachmentActionProps) *err // AttachmentErrNotAllowedToCreate returns "system:attachment.notAllowedToCreate" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrNotAllowedToCreate(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -481,7 +504,9 @@ func AttachmentErrNotAllowedToCreate(mm ...*attachmentActionProps) *errors.Error // AttachmentErrNotAllowedToCreateEmptyAttachment returns "system:attachment.notAllowedToCreateEmptyAttachment" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrNotAllowedToCreateEmptyAttachment(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -515,7 +540,9 @@ func AttachmentErrNotAllowedToCreateEmptyAttachment(mm ...*attachmentActionProps // AttachmentErrFailedToExtractMimeType returns "system:attachment.failedToExtractMimeType" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrFailedToExtractMimeType(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -547,7 +574,9 @@ func AttachmentErrFailedToExtractMimeType(mm ...*attachmentActionProps) *errors. // AttachmentErrFailedToStoreFile returns "system:attachment.failedToStoreFile" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrFailedToStoreFile(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -579,7 +608,9 @@ func AttachmentErrFailedToStoreFile(mm ...*attachmentActionProps) *errors.Error // AttachmentErrFailedToProcessImage returns "system:attachment.failedToProcessImage" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrFailedToProcessImage(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -611,7 +642,9 @@ func AttachmentErrFailedToProcessImage(mm ...*attachmentActionProps) *errors.Err // AttachmentErrInvalidAvatarFileType returns "system:attachment.invalidAvatarFileType" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrInvalidAvatarFileType(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -643,7 +676,9 @@ func AttachmentErrInvalidAvatarFileType(mm ...*attachmentActionProps) *errors.Er // AttachmentErrInvalidAvatarFileSize returns "system:attachment.invalidAvatarFileSize" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrInvalidAvatarFileSize(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -675,7 +710,9 @@ func AttachmentErrInvalidAvatarFileSize(mm ...*attachmentActionProps) *errors.Er // AttachmentErrInvalidAvatarGenerateFontFile returns "system:attachment.invalidAvatarGenerateFontFile" as *errors.Error // +// // This function is auto-generated. +// func AttachmentErrInvalidAvatarGenerateFontFile(mm ...*attachmentActionProps) *errors.Error { var p = &attachmentActionProps{} if len(mm) > 0 { @@ -713,6 +750,7 @@ func AttachmentErrInvalidAvatarGenerateFontFile(mm ...*attachmentActionProps) *e // It will wrap unrecognized/internal errors with generic errors. // // This function is auto-generated. +// func (svc attachment) recordAction(ctx context.Context, props *attachmentActionProps, actionFn func(...*attachmentActionProps) *attachmentAction, err error) error { if svc.actionlog == nil || actionFn == nil { // action log disabled or no action fn passed, return error as-is diff --git a/server/system/service/auth_actions.gen.go b/server/system/service/auth_actions.gen.go index 1ce58d94e..6ba71bcc1 100644 --- a/server/system/service/auth_actions.gen.go +++ b/server/system/service/auth_actions.gen.go @@ -56,6 +56,7 @@ var ( // setEmail updates authActionProps's email // // This function is auto-generated. +// func (p *authActionProps) setEmail(email string) *authActionProps { p.email = email return p @@ -64,6 +65,7 @@ func (p *authActionProps) setEmail(email string) *authActionProps { // setProvider updates authActionProps's provider // // This function is auto-generated. +// func (p *authActionProps) setProvider(provider string) *authActionProps { p.provider = provider return p @@ -72,6 +74,7 @@ func (p *authActionProps) setProvider(provider string) *authActionProps { // setCredentials updates authActionProps's credentials // // This function is auto-generated. +// func (p *authActionProps) setCredentials(credentials *types.Credential) *authActionProps { p.credentials = credentials return p @@ -80,6 +83,7 @@ func (p *authActionProps) setCredentials(credentials *types.Credential) *authAct // setRole updates authActionProps's role // // This function is auto-generated. +// func (p *authActionProps) setRole(role *types.Role) *authActionProps { p.role = role return p @@ -88,6 +92,7 @@ func (p *authActionProps) setRole(role *types.Role) *authActionProps { // setUser updates authActionProps's user // // This function is auto-generated. +// func (p *authActionProps) setUser(user *types.User) *authActionProps { p.user = user return p @@ -96,6 +101,7 @@ func (p *authActionProps) setUser(user *types.User) *authActionProps { // Serialize converts authActionProps to actionlog.Meta // // This function is auto-generated. +// func (p authActionProps) Serialize() actionlog.Meta { var ( m = make(actionlog.Meta) @@ -128,6 +134,7 @@ func (p authActionProps) Serialize() actionlog.Meta { // tr translates string and replaces meta value placeholder with values // // This function is auto-generated. +// func (p authActionProps) Format(in string, err error) string { var ( pairs = []string{"{{err}}"} @@ -214,6 +221,7 @@ func (p authActionProps) Format(in string, err error) string { // String returns loggable description as string // // This function is auto-generated. +// func (a *authAction) String() string { var props = &authActionProps{} @@ -241,6 +249,7 @@ func (e *authAction) ToAction() *actionlog.Action { // AuthActionAuthenticate returns "system:auth.authenticate" action // // This function is auto-generated. +// func AuthActionAuthenticate(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -260,6 +269,7 @@ func AuthActionAuthenticate(props ...*authActionProps) *authAction { // AuthActionIssueToken returns "system:auth.issueToken" action // // This function is auto-generated. +// func AuthActionIssueToken(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -279,6 +289,7 @@ func AuthActionIssueToken(props ...*authActionProps) *authAction { // AuthActionValidateToken returns "system:auth.validateToken" action // // This function is auto-generated. +// func AuthActionValidateToken(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -298,6 +309,7 @@ func AuthActionValidateToken(props ...*authActionProps) *authAction { // AuthActionChangePassword returns "system:auth.changePassword" action // // This function is auto-generated. +// func AuthActionChangePassword(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -317,6 +329,7 @@ func AuthActionChangePassword(props ...*authActionProps) *authAction { // AuthActionInternalSignup returns "system:auth.internalSignup" action // // This function is auto-generated. +// func AuthActionInternalSignup(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -336,6 +349,7 @@ func AuthActionInternalSignup(props ...*authActionProps) *authAction { // AuthActionConfirmEmail returns "system:auth.confirmEmail" action // // This function is auto-generated. +// func AuthActionConfirmEmail(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -355,6 +369,7 @@ func AuthActionConfirmEmail(props ...*authActionProps) *authAction { // AuthActionExternalSignup returns "system:auth.externalSignup" action // // This function is auto-generated. +// func AuthActionExternalSignup(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -374,6 +389,7 @@ func AuthActionExternalSignup(props ...*authActionProps) *authAction { // AuthActionSendEmailConfirmationToken returns "system:auth.sendEmailConfirmationToken" action // // This function is auto-generated. +// func AuthActionSendEmailConfirmationToken(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -393,6 +409,7 @@ func AuthActionSendEmailConfirmationToken(props ...*authActionProps) *authAction // AuthActionSendPasswordResetToken returns "system:auth.sendPasswordResetToken" action // // This function is auto-generated. +// func AuthActionSendPasswordResetToken(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -412,6 +429,7 @@ func AuthActionSendPasswordResetToken(props ...*authActionProps) *authAction { // AuthActionExchangePasswordResetToken returns "system:auth.exchangePasswordResetToken" action // // This function is auto-generated. +// func AuthActionExchangePasswordResetToken(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -431,6 +449,7 @@ func AuthActionExchangePasswordResetToken(props ...*authActionProps) *authAction // AuthActionGeneratePasswordCreateToken returns "system:auth.generatePasswordCreateToken" action // // This function is auto-generated. +// func AuthActionGeneratePasswordCreateToken(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -450,6 +469,7 @@ func AuthActionGeneratePasswordCreateToken(props ...*authActionProps) *authActio // AuthActionAutoPromote returns "system:auth.autoPromote" action // // This function is auto-generated. +// func AuthActionAutoPromote(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -469,6 +489,7 @@ func AuthActionAutoPromote(props ...*authActionProps) *authAction { // AuthActionUpdateCredentials returns "system:auth.updateCredentials" action // // This function is auto-generated. +// func AuthActionUpdateCredentials(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -488,6 +509,7 @@ func AuthActionUpdateCredentials(props ...*authActionProps) *authAction { // AuthActionCreateCredentials returns "system:auth.createCredentials" action // // This function is auto-generated. +// func AuthActionCreateCredentials(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -507,6 +529,7 @@ func AuthActionCreateCredentials(props ...*authActionProps) *authAction { // AuthActionImpersonate returns "system:auth.impersonate" action // // This function is auto-generated. +// func AuthActionImpersonate(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -526,6 +549,7 @@ func AuthActionImpersonate(props ...*authActionProps) *authAction { // AuthActionTotpConfigure returns "system:auth.totpConfigure" action // // This function is auto-generated. +// func AuthActionTotpConfigure(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -545,6 +569,7 @@ func AuthActionTotpConfigure(props ...*authActionProps) *authAction { // AuthActionTotpRemove returns "system:auth.totpRemove" action // // This function is auto-generated. +// func AuthActionTotpRemove(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -564,6 +589,7 @@ func AuthActionTotpRemove(props ...*authActionProps) *authAction { // AuthActionTotpValidate returns "system:auth.totpValidate" action // // This function is auto-generated. +// func AuthActionTotpValidate(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -583,6 +609,7 @@ func AuthActionTotpValidate(props ...*authActionProps) *authAction { // AuthActionEmailOtpVerify returns "system:auth.emailOtpVerify" action // // This function is auto-generated. +// func AuthActionEmailOtpVerify(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -602,6 +629,7 @@ func AuthActionEmailOtpVerify(props ...*authActionProps) *authAction { // AuthActionAccessTokensRemoved returns "system:auth.accessTokensRemoved" action // // This function is auto-generated. +// func AuthActionAccessTokensRemoved(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -621,6 +649,7 @@ func AuthActionAccessTokensRemoved(props ...*authActionProps) *authAction { // AuthActionSendInviteEMail returns "system:auth.sendInviteEMail" action // // This function is auto-generated. +// func AuthActionSendInviteEMail(props ...*authActionProps) *authAction { a := &authAction{ timestamp: time.Now(), @@ -643,7 +672,9 @@ func AuthActionSendInviteEMail(props ...*authActionProps) *authAction { // AuthErrGeneric returns "system:auth.generic" as *errors.Error // +// // This function is auto-generated. +// func AuthErrGeneric(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -677,7 +708,9 @@ func AuthErrGeneric(mm ...*authActionProps) *errors.Error { // AuthErrInvalidCredentials returns "system:auth.invalidCredentials" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInvalidCredentials(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -711,7 +744,9 @@ func AuthErrInvalidCredentials(mm ...*authActionProps) *errors.Error { // AuthErrInvalidEmailFormat returns "system:auth.invalidEmailFormat" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInvalidEmailFormat(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -743,7 +778,9 @@ func AuthErrInvalidEmailFormat(mm ...*authActionProps) *errors.Error { // AuthErrInvalidHandle returns "system:auth.invalidHandle" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInvalidHandle(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -778,6 +815,7 @@ func AuthErrInvalidHandle(mm ...*authActionProps) *errors.Error { // Note: This error will be wrapped with safe (system:auth.invalidCredentials) error! // // This function is auto-generated. +// func AuthErrFailedForUnknownUser(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -817,6 +855,7 @@ func AuthErrFailedForUnknownUser(mm ...*authActionProps) *errors.Error { // Note: This error will be wrapped with safe (system:auth.invalidCredentials) error! // // This function is auto-generated. +// func AuthErrFailedForDeletedUser(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -856,6 +895,7 @@ func AuthErrFailedForDeletedUser(mm ...*authActionProps) *errors.Error { // Note: This error will be wrapped with safe (system:auth.invalidCredentials) error! // // This function is auto-generated. +// func AuthErrFailedForSuspendedUser(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -895,6 +935,7 @@ func AuthErrFailedForSuspendedUser(mm ...*authActionProps) *errors.Error { // Note: This error will be wrapped with safe (system:auth.invalidCredentials) error! // // This function is auto-generated. +// func AuthErrFailedForSystemUser(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -931,7 +972,9 @@ func AuthErrFailedForSystemUser(mm ...*authActionProps) *errors.Error { // AuthErrFailedUnconfirmedEmail returns "system:auth.failedUnconfirmedEmail" as *errors.Error // +// // This function is auto-generated. +// func AuthErrFailedUnconfirmedEmail(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -965,7 +1008,9 @@ func AuthErrFailedUnconfirmedEmail(mm ...*authActionProps) *errors.Error { // AuthErrInternalLoginDisabledByConfig returns "system:auth.internalLoginDisabledByConfig" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInternalLoginDisabledByConfig(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -997,7 +1042,9 @@ func AuthErrInternalLoginDisabledByConfig(mm ...*authActionProps) *errors.Error // AuthErrInternalSignupDisabledByConfig returns "system:auth.internalSignupDisabledByConfig" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInternalSignupDisabledByConfig(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1029,7 +1076,9 @@ func AuthErrInternalSignupDisabledByConfig(mm ...*authActionProps) *errors.Error // AuthErrPasswordChangeFailedForUnknownUser returns "system:auth.passwordChangeFailedForUnknownUser" as *errors.Error // +// // This function is auto-generated. +// func AuthErrPasswordChangeFailedForUnknownUser(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1061,7 +1110,9 @@ func AuthErrPasswordChangeFailedForUnknownUser(mm ...*authActionProps) *errors.E // AuthErrPasswordResetFailedOldPasswordCheckFailed returns "system:auth.passwordResetFailedOldPasswordCheckFailed" as *errors.Error // +// // This function is auto-generated. +// func AuthErrPasswordResetFailedOldPasswordCheckFailed(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1093,7 +1144,9 @@ func AuthErrPasswordResetFailedOldPasswordCheckFailed(mm ...*authActionProps) *e // AuthErrPasswordSetFailedReusedPasswordCheckFailed returns "system:auth.passwordSetFailedReusedPasswordCheckFailed" as *errors.Error // +// // This function is auto-generated. +// func AuthErrPasswordSetFailedReusedPasswordCheckFailed(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1125,7 +1178,9 @@ func AuthErrPasswordSetFailedReusedPasswordCheckFailed(mm ...*authActionProps) * // AuthErrPasswordCreateFailedForUnknownUser returns "system:auth.passwordCreateFailedForUnknownUser" as *errors.Error // +// // This function is auto-generated. +// func AuthErrPasswordCreateFailedForUnknownUser(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1157,7 +1212,9 @@ func AuthErrPasswordCreateFailedForUnknownUser(mm ...*authActionProps) *errors.E // AuthErrPasswordResetDisabledByConfig returns "system:auth.passwordResetDisabledByConfig" as *errors.Error // +// // This function is auto-generated. +// func AuthErrPasswordResetDisabledByConfig(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1189,7 +1246,9 @@ func AuthErrPasswordResetDisabledByConfig(mm ...*authActionProps) *errors.Error // AuthErrPasswordCreateDisabledByConfig returns "system:auth.passwordCreateDisabledByConfig" as *errors.Error // +// // This function is auto-generated. +// func AuthErrPasswordCreateDisabledByConfig(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1221,7 +1280,9 @@ func AuthErrPasswordCreateDisabledByConfig(mm ...*authActionProps) *errors.Error // AuthErrPasswordNotSecure returns "system:auth.passwordNotSecure" as *errors.Error // +// // This function is auto-generated. +// func AuthErrPasswordNotSecure(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1253,7 +1314,9 @@ func AuthErrPasswordNotSecure(mm ...*authActionProps) *errors.Error { // AuthErrExternalDisabledByConfig returns "system:auth.externalDisabledByConfig" as *errors.Error // +// // This function is auto-generated. +// func AuthErrExternalDisabledByConfig(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1287,7 +1350,9 @@ func AuthErrExternalDisabledByConfig(mm ...*authActionProps) *errors.Error { // AuthErrProfileWithoutValidEmail returns "system:auth.profileWithoutValidEmail" as *errors.Error // +// // This function is auto-generated. +// func AuthErrProfileWithoutValidEmail(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1321,7 +1386,9 @@ func AuthErrProfileWithoutValidEmail(mm ...*authActionProps) *errors.Error { // AuthErrCredentialsLinkedToInvalidUser returns "system:auth.credentialsLinkedToInvalidUser" as *errors.Error // +// // This function is auto-generated. +// func AuthErrCredentialsLinkedToInvalidUser(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1353,7 +1420,9 @@ func AuthErrCredentialsLinkedToInvalidUser(mm ...*authActionProps) *errors.Error // AuthErrInvalidToken returns "system:auth.invalidToken" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInvalidToken(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1385,7 +1454,9 @@ func AuthErrInvalidToken(mm ...*authActionProps) *errors.Error { // AuthErrNotAllowedToImpersonate returns "system:auth.notAllowedToImpersonate" as *errors.Error // +// // This function is auto-generated. +// func AuthErrNotAllowedToImpersonate(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1417,7 +1488,9 @@ func AuthErrNotAllowedToImpersonate(mm ...*authActionProps) *errors.Error { // AuthErrNotAllowedToRemoveTOTP returns "system:auth.notAllowedToRemoveTOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrNotAllowedToRemoveTOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1449,7 +1522,9 @@ func AuthErrNotAllowedToRemoveTOTP(mm ...*authActionProps) *errors.Error { // AuthErrUnconfiguredTOTP returns "system:auth.unconfiguredTOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrUnconfiguredTOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1481,7 +1556,9 @@ func AuthErrUnconfiguredTOTP(mm ...*authActionProps) *errors.Error { // AuthErrNotAllowedToConfigureTOTP returns "system:auth.notAllowedToConfigureTOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrNotAllowedToConfigureTOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1513,7 +1590,9 @@ func AuthErrNotAllowedToConfigureTOTP(mm ...*authActionProps) *errors.Error { // AuthErrEnforcedMFAWithTOTP returns "system:auth.enforcedMFAWithTOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrEnforcedMFAWithTOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1545,7 +1624,9 @@ func AuthErrEnforcedMFAWithTOTP(mm ...*authActionProps) *errors.Error { // AuthErrInvalidTOTP returns "system:auth.invalidTOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInvalidTOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1577,7 +1658,9 @@ func AuthErrInvalidTOTP(mm ...*authActionProps) *errors.Error { // AuthErrDisabledMFAWithTOTP returns "system:auth.disabledMFAWithTOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrDisabledMFAWithTOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1609,7 +1692,9 @@ func AuthErrDisabledMFAWithTOTP(mm ...*authActionProps) *errors.Error { // AuthErrDisabledMFAWithEmailOTP returns "system:auth.disabledMFAWithEmailOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrDisabledMFAWithEmailOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1641,7 +1726,9 @@ func AuthErrDisabledMFAWithEmailOTP(mm ...*authActionProps) *errors.Error { // AuthErrEnforcedMFAWithEmailOTP returns "system:auth.enforcedMFAWithEmailOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrEnforcedMFAWithEmailOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1673,7 +1760,9 @@ func AuthErrEnforcedMFAWithEmailOTP(mm ...*authActionProps) *errors.Error { // AuthErrInvalidEmailOTP returns "system:auth.invalidEmailOTP" as *errors.Error // +// // This function is auto-generated. +// func AuthErrInvalidEmailOTP(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1705,7 +1794,9 @@ func AuthErrInvalidEmailOTP(mm ...*authActionProps) *errors.Error { // AuthErrRateLimitExceeded returns "system:auth.rateLimitExceeded" as *errors.Error // +// // This function is auto-generated. +// func AuthErrRateLimitExceeded(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1739,7 +1830,9 @@ func AuthErrRateLimitExceeded(mm ...*authActionProps) *errors.Error { // AuthErrMaxUserLimitReached returns "system:auth.maxUserLimitReached" as *errors.Error // +// // This function is auto-generated. +// func AuthErrMaxUserLimitReached(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1771,7 +1864,9 @@ func AuthErrMaxUserLimitReached(mm ...*authActionProps) *errors.Error { // AuthErrDisabledSendUserInviteEmail returns "system:auth.disabledSendUserInviteEmail" as *errors.Error // +// // This function is auto-generated. +// func AuthErrDisabledSendUserInviteEmail(mm ...*authActionProps) *errors.Error { var p = &authActionProps{} if len(mm) > 0 { @@ -1809,6 +1904,7 @@ func AuthErrDisabledSendUserInviteEmail(mm ...*authActionProps) *errors.Error { // It will wrap unrecognized/internal errors with generic errors. // // This function is auto-generated. +// func (svc auth) recordAction(ctx context.Context, props *authActionProps, actionFn func(...*authActionProps) *authAction, err error) error { if svc.actionlog == nil || actionFn == nil { // action log disabled or no action fn passed, return error as-is diff --git a/server/system/service/auth_client.go b/server/system/service/auth_client.go index c1033127b..c4b013672 100644 --- a/server/system/service/auth_client.go +++ b/server/system/service/auth_client.go @@ -278,6 +278,11 @@ func (svc *authClient) Update(ctx context.Context, upd *types.AuthClient) (res * return AuthClientErrNotAllowedToUpdate() } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, res.UpdatedAt, res.CreatedAt) { + return AuthClientErrStaleData() + } + // Firstly validate default clients before the automation occurs if err = defaultClientValidator(res, upd); err != nil { return err diff --git a/server/system/service/auth_client_actions.gen.go b/server/system/service/auth_client_actions.gen.go index f0c27ef19..83b2c8810 100644 --- a/server/system/service/auth_client_actions.gen.go +++ b/server/system/service/auth_client_actions.gen.go @@ -503,6 +503,40 @@ func AuthClientErrInvalidID(mm ...*authClientActionProps) *errors.Error { return e } +// AuthClientErrStaleData returns "system:auth-client.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func AuthClientErrStaleData(mm ...*authClientActionProps) *errors.Error { + var p = &authClientActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:auth-client"), + + errors.Meta(authClientPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "auth-client.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // AuthClientErrMissingName returns "system:auth-client.missingName" as *errors.Error // // diff --git a/server/system/service/auth_client_actions.yaml b/server/system/service/auth_client_actions.yaml index e38cde416..4ab0cb3bc 100644 --- a/server/system/service/auth_client_actions.yaml +++ b/server/system/service/auth_client_actions.yaml @@ -61,6 +61,10 @@ errors: message: "invalid ID" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: missingName message: "missing name" diff --git a/server/system/service/dal_connection.go b/server/system/service/dal_connection.go index 2d2795a18..07b37ea0d 100644 --- a/server/system/service/dal_connection.go +++ b/server/system/service/dal_connection.go @@ -138,6 +138,11 @@ func (svc *dalConnection) Update(ctx context.Context, upd *types.DalConnection) return DalConnectionErrNotAllowedToUpdate(cProps) } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, old.UpdatedAt, old.CreatedAt) { + return DalConnectionErrStaleData() + } + upd.UpdatedAt = now() upd.CreatedAt = old.CreatedAt upd.UpdatedBy = a.GetIdentityFromContext(ctx).Identity() diff --git a/server/system/service/dal_connection_actions.gen.go b/server/system/service/dal_connection_actions.gen.go index ce87cdd9d..1227477fc 100644 --- a/server/system/service/dal_connection_actions.gen.go +++ b/server/system/service/dal_connection_actions.gen.go @@ -521,6 +521,40 @@ func DalConnectionErrInvalidEndpoint(mm ...*dalConnectionActionProps) *errors.Er return e } +// DalConnectionErrStaleData returns "system:dal-connection.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func DalConnectionErrStaleData(mm ...*dalConnectionActionProps) *errors.Error { + var p = &dalConnectionActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:dal-connection"), + + errors.Meta(dalConnectionPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "dal-connection.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // DalConnectionErrExistsEndpoint returns "system:dal-connection.existsEndpoint" as *errors.Error // // diff --git a/server/system/service/dal_connection_actions.yaml b/server/system/service/dal_connection_actions.yaml index 67e621b75..4f5f9d60a 100644 --- a/server/system/service/dal_connection_actions.yaml +++ b/server/system/service/dal_connection_actions.yaml @@ -63,6 +63,10 @@ errors: message: "invalid DSN" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: existsEndpoint message: "connection with this DSN already exists" severity: warning diff --git a/server/system/service/dal_sensitivity_level.go b/server/system/service/dal_sensitivity_level.go index 17ffed6de..7ea152645 100644 --- a/server/system/service/dal_sensitivity_level.go +++ b/server/system/service/dal_sensitivity_level.go @@ -122,6 +122,11 @@ func (svc *dalSensitivityLevel) Update(ctx context.Context, upd *types.DalSensit return DalSensitivityLevelErrNotAllowedToManage(qProps) } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, qq.UpdatedAt, qq.CreatedAt) { + return DalSensitivityLevelErrStaleData() + } + upd.UpdatedAt = now() upd.CreatedAt = qq.CreatedAt upd.UpdatedBy = a.GetIdentityFromContext(ctx).Identity() diff --git a/server/system/service/dal_sensitivity_level_actions.gen.go b/server/system/service/dal_sensitivity_level_actions.gen.go index 317443550..967693bc5 100644 --- a/server/system/service/dal_sensitivity_level_actions.gen.go +++ b/server/system/service/dal_sensitivity_level_actions.gen.go @@ -521,6 +521,40 @@ func DalSensitivityLevelErrInvalidEndpoint(mm ...*dalSensitivityLevelActionProps return e } +// DalSensitivityLevelErrStaleData returns "system:dal-sensitivity-level.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func DalSensitivityLevelErrStaleData(mm ...*dalSensitivityLevelActionProps) *errors.Error { + var p = &dalSensitivityLevelActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:dal-sensitivity-level"), + + errors.Meta(dalSensitivityLevelPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "dal-sensitivity-level.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // DalSensitivityLevelErrExistsEndpoint returns "system:dal-sensitivity-level.existsEndpoint" as *errors.Error // // diff --git a/server/system/service/dal_sensitivity_level_actions.yaml b/server/system/service/dal_sensitivity_level_actions.yaml index 42d8bda8b..c21595fb9 100644 --- a/server/system/service/dal_sensitivity_level_actions.yaml +++ b/server/system/service/dal_sensitivity_level_actions.yaml @@ -63,6 +63,10 @@ errors: message: "invalid DSN" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: existsEndpoint message: "sensitivityLevel with this DSN already exists" severity: warning diff --git a/server/system/service/data_privacy_request_actions.gen.go b/server/system/service/data_privacy_request_actions.gen.go index a0f5a6c16..bd388b340 100644 --- a/server/system/service/data_privacy_request_actions.gen.go +++ b/server/system/service/data_privacy_request_actions.gen.go @@ -508,6 +508,40 @@ func DataPrivacyErrInvalidStatus(mm ...*dataPrivacyActionProps) *errors.Error { return e } +// DataPrivacyErrStaleData returns "system:data-privacy-request.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func DataPrivacyErrStaleData(mm ...*dataPrivacyActionProps) *errors.Error { + var p = &dataPrivacyActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:data-privacy-request"), + + errors.Meta(dataPrivacyPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "data-privacy.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // DataPrivacyErrNotAllowedToRead returns "system:data-privacy-request.notAllowedToRead" as *errors.Error // // diff --git a/server/system/service/data_privacy_request_actions.yaml b/server/system/service/data_privacy_request_actions.yaml index ecf3b2cfe..cacf60ede 100644 --- a/server/system/service/data_privacy_request_actions.yaml +++ b/server/system/service/data_privacy_request_actions.yaml @@ -62,6 +62,10 @@ errors: message: "invalid Status" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: notAllowedToRead message: "not allowed to read this data privacy request" log: "failed to read data privacy request; insufficient permissions" diff --git a/server/system/service/queue.go b/server/system/service/queue.go index b82186a18..776497925 100644 --- a/server/system/service/queue.go +++ b/server/system/service/queue.go @@ -2,6 +2,7 @@ package service import ( "context" + "github.com/cortezaproject/corteza/server/pkg/errors" "github.com/cortezaproject/corteza/server/pkg/actionlog" @@ -166,6 +167,11 @@ func (svc *queue) Update(ctx context.Context, upd *types.Queue) (q *types.Queue, return QueueErrNotFound(qProps) } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, qq.UpdatedAt, qq.CreatedAt) { + return QueueErrStaleData() + } + if qq, e := store.LookupQueueByQueue(ctx, svc.store, upd.Queue); e == nil && qq != nil && qq.ID != upd.ID { return QueueErrAlreadyExists(qProps) } diff --git a/server/system/service/queue_actions.gen.go b/server/system/service/queue_actions.gen.go index 60b43ae74..93110314c 100644 --- a/server/system/service/queue_actions.gen.go +++ b/server/system/service/queue_actions.gen.go @@ -493,6 +493,40 @@ func QueueErrInvalidConsumer(mm ...*queueActionProps) *errors.Error { return e } +// QueueErrStaleData returns "system:queue.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func QueueErrStaleData(mm ...*queueActionProps) *errors.Error { + var p = &queueActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:queue"), + + errors.Meta(queuePropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "queue.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // QueueErrAlreadyExists returns "system:queue.alreadyExists" as *errors.Error // // diff --git a/server/system/service/queue_actions.yaml b/server/system/service/queue_actions.yaml index 850f03572..c98263689 100644 --- a/server/system/service/queue_actions.yaml +++ b/server/system/service/queue_actions.yaml @@ -60,6 +60,10 @@ errors: message: "invalid consumer" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: alreadyExists message: "queue by that name already exists" severity: warning diff --git a/server/system/service/report.go b/server/system/service/report.go index 5a49d1be8..46a07b67d 100644 --- a/server/system/service/report.go +++ b/server/system/service/report.go @@ -195,6 +195,11 @@ func (svc *report) Update(ctx context.Context, upd *types.Report) (report *types return ReportErrNotAllowedToUpdate() } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, report.UpdatedAt, report.CreatedAt) { + return ReportErrStaleData() + } + // if err = svc.eventbus.WaitFor(ctx, event.ReportBeforeUpdate(upd, report)); err != nil { // return // } diff --git a/server/system/service/report_actions.gen.go b/server/system/service/report_actions.gen.go index 3119547da..29bc9ac58 100644 --- a/server/system/service/report_actions.gen.go +++ b/server/system/service/report_actions.gen.go @@ -483,6 +483,40 @@ func ReportErrInvalidID(mm ...*reportActionProps) *errors.Error { return e } +// ReportErrStaleData returns "system:report.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func ReportErrStaleData(mm ...*reportActionProps) *errors.Error { + var p = &reportActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:report"), + + errors.Meta(reportPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "report.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // ReportErrNotAllowedToRead returns "system:report.notAllowedToRead" as *errors.Error // // diff --git a/server/system/service/report_actions.yaml b/server/system/service/report_actions.yaml index b9511733b..a46596f3f 100644 --- a/server/system/service/report_actions.yaml +++ b/server/system/service/report_actions.yaml @@ -59,6 +59,10 @@ errors: message: "invalid ID" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: notAllowedToRead message: "not allowed to read this report" log: "failed to read {{report}}; insufficient permissions" diff --git a/server/system/service/resource_translation_actions.gen.go b/server/system/service/resource_translation_actions.gen.go index d9156d965..a17ea0584 100644 --- a/server/system/service/resource_translation_actions.gen.go +++ b/server/system/service/resource_translation_actions.gen.go @@ -493,6 +493,40 @@ func ResourceTranslationErrInvalidID(mm ...*resourceTranslationActionProps) *err return e } +// ResourceTranslationErrStaleData returns "system:resource-translation.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func ResourceTranslationErrStaleData(mm ...*resourceTranslationActionProps) *errors.Error { + var p = &resourceTranslationActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:resource-translation"), + + errors.Meta(resourceTranslationPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "resource-translation.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // ResourceTranslationErrNotAllowedToRead returns "system:resource-translation.notAllowedToRead" as *errors.Error // // diff --git a/server/system/service/resource_translation_actions.yaml b/server/system/service/resource_translation_actions.yaml index a89affdcd..2c25d3737 100644 --- a/server/system/service/resource_translation_actions.yaml +++ b/server/system/service/resource_translation_actions.yaml @@ -56,6 +56,10 @@ errors: message: "invalid ID" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: notAllowedToRead message: "not allowed to read this resource translation" log: "failed to read {{resourceTranslation}}; insufficient permissions" diff --git a/server/system/service/role.go b/server/system/service/role.go index 633e7460e..b0313cdc7 100644 --- a/server/system/service/role.go +++ b/server/system/service/role.go @@ -369,6 +369,11 @@ func (svc role) Update(ctx context.Context, upd *types.Role) (r *types.Role, err return RoleErrNotAllowedToUpdate() } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, r.UpdatedAt, r.CreatedAt) { + return RoleErrStaleData() + } + if svc.IsSystem(r) { // prevent system role updates // we need this here because of the clumsy way diff --git a/server/system/service/role_actions.gen.go b/server/system/service/role_actions.gen.go index 0770d0128..5a2b776e6 100644 --- a/server/system/service/role_actions.gen.go +++ b/server/system/service/role_actions.gen.go @@ -737,6 +737,40 @@ func RoleErrInvalidHandle(mm ...*roleActionProps) *errors.Error { return e } +// RoleErrStaleData returns "system:role.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func RoleErrStaleData(mm ...*roleActionProps) *errors.Error { + var p = &roleActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:role"), + + errors.Meta(rolePropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "role.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // RoleErrNotAllowedToRead returns "system:role.notAllowedToRead" as *errors.Error // // diff --git a/server/system/service/role_actions.yaml b/server/system/service/role_actions.yaml index 2c00db846..ea7b3c3fb 100644 --- a/server/system/service/role_actions.yaml +++ b/server/system/service/role_actions.yaml @@ -88,6 +88,10 @@ errors: message: "invalid handle" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: notAllowedToRead message: "not allowed to read this role" log: "failed to read {{role.handle}}; insufficient permissions" diff --git a/server/system/service/template.go b/server/system/service/template.go index 497edbe37..8fe021ca1 100644 --- a/server/system/service/template.go +++ b/server/system/service/template.go @@ -252,6 +252,11 @@ func (svc template) Update(ctx context.Context, upd *types.Template) (tpl *types return TemplateErrNotAllowedToUpdate() } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, tpl.UpdatedAt, tpl.CreatedAt) { + return TemplateErrStaleData() + } + // @todo corredor? tpl.Handle = upd.Handle diff --git a/server/system/service/template_actions.gen.go b/server/system/service/template_actions.gen.go index 03b479603..48ea54f11 100644 --- a/server/system/service/template_actions.gen.go +++ b/server/system/service/template_actions.gen.go @@ -501,6 +501,40 @@ func TemplateErrInvalidID(mm ...*templateActionProps) *errors.Error { return e } +// TemplateErrStaleData returns "system:template.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func TemplateErrStaleData(mm ...*templateActionProps) *errors.Error { + var p = &templateActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:template"), + + errors.Meta(templatePropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "template.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // TemplateErrInvalidHandle returns "system:template.invalidHandle" as *errors.Error // // diff --git a/server/system/service/template_actions.yaml b/server/system/service/template_actions.yaml index fb6457410..290e2af55 100644 --- a/server/system/service/template_actions.yaml +++ b/server/system/service/template_actions.yaml @@ -59,6 +59,10 @@ errors: message: "invalid ID" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: invalidHandle message: "invalid handle" severity: warning diff --git a/server/system/service/user.go b/server/system/service/user.go index 4cdaad33d..7f5e9afb6 100644 --- a/server/system/service/user.go +++ b/server/system/service/user.go @@ -2,6 +2,15 @@ package service import ( "context" + "io" + "mime/multipart" + "net/mail" + "regexp" + "strconv" + "strings" + "time" + "unicode" + "github.com/cortezaproject/corteza/server/pkg/actionlog" internalAuth "github.com/cortezaproject/corteza/server/pkg/auth" "github.com/cortezaproject/corteza/server/pkg/errors" @@ -12,14 +21,6 @@ import ( "github.com/cortezaproject/corteza/server/store" "github.com/cortezaproject/corteza/server/system/service/event" "github.com/cortezaproject/corteza/server/system/types" - "io" - "mime/multipart" - "net/mail" - "regexp" - "strconv" - "strings" - "time" - "unicode" ) const ( @@ -447,6 +448,11 @@ func (svc user) Update(ctx context.Context, upd *types.User) (u *types.User, err } } + // Test if stale (update has an older version of data) + if isStale(upd.UpdatedAt, u.UpdatedAt, u.CreatedAt) { + return UserErrStaleData() + } + // Assign changed values u.Email = upd.Email u.Username = upd.Username diff --git a/server/system/service/user_actions.gen.go b/server/system/service/user_actions.gen.go index c3a524d86..e4332fb7b 100644 --- a/server/system/service/user_actions.gen.go +++ b/server/system/service/user_actions.gen.go @@ -793,6 +793,40 @@ func UserErrInvalidEmail(mm ...*userActionProps) *errors.Error { return e } +// UserErrStaleData returns "system:user.staleData" as *errors.Error +// +// +// This function is auto-generated. +// +func UserErrStaleData(mm ...*userActionProps) *errors.Error { + var p = &userActionProps{} + if len(mm) > 0 { + p = mm[0] + } + + var e = errors.New( + errors.KindInternal, + + p.Format("stale data", nil), + + errors.Meta("type", "staleData"), + errors.Meta("resource", "system:user"), + + errors.Meta(userPropsMetaKey{}, p), + + // translation namespace & key + errors.Meta(locale.ErrorMetaNamespace{}, "system"), + errors.Meta(locale.ErrorMetaKey{}, "user.errors.staleData"), + + errors.StackSkip(1), + ) + + if len(mm) > 0 { + } + + return e +} + // UserErrNotAllowedToRead returns "system:user.notAllowedToRead" as *errors.Error // // diff --git a/server/system/service/user_actions.yaml b/server/system/service/user_actions.yaml index 19db999af..46b20a38a 100644 --- a/server/system/service/user_actions.yaml +++ b/server/system/service/user_actions.yaml @@ -94,6 +94,10 @@ errors: message: "invalid email" severity: warning + - error: staleData + message: "stale data" + severity: warning + - error: notAllowedToRead message: "not allowed to read this user" log: "failed to read {{user.handle}}; insufficient permissions"