diff --git a/federation/rest.yaml b/federation/rest.yaml index a41825677..92173d8dd 100644 --- a/federation/rest.yaml +++ b/federation/rest.yaml @@ -312,4 +312,54 @@ endpoints: title: Page cursor - type: string name: sort - title: Sort items \ No newline at end of file + title: Sort items + + - title: Sync data + description: Sync data + entrypoint: syncData + path: "/exposed" + authentication: [] + apis: + - name: readExposedAll + method: GET + title: List all record changes + path: "/records/" + parameters: + get: + - type: string + name: query + required: false + title: Search query + - type: uint + name: limit + title: Limit + - type: string + name: pageCursor + title: Page cursor + - type: string + name: sort + title: Sort items + - name: readExposed + method: GET + title: List all records per module + path: "/modules/{moduleID}/records/" + parameters: + path: + - type: uint64 + name: moduleID + required: true + title: Module ID + get: + - type: string + name: query + required: false + title: Search query + - type: uint + name: limit + title: Limit + - type: string + name: pageCursor + title: Page cursor + - type: string + name: sort + title: Sort items diff --git a/federation/rest/handlers/syncData.go b/federation/rest/handlers/syncData.go new file mode 100644 index 000000000..72d54eb18 --- /dev/null +++ b/federation/rest/handlers/syncData.go @@ -0,0 +1,86 @@ +package handlers + +// This file is auto-generated. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Definitions file that controls how this file is generated: +// + +import ( + "context" + "github.com/go-chi/chi" + "github.com/titpetric/factory/resputil" + "net/http" + + "github.com/cortezaproject/corteza-server/federation/rest/request" + "github.com/cortezaproject/corteza-server/pkg/logger" +) + +type ( + // Internal API interface + SyncDataAPI interface { + ReadExposedAll(context.Context, *request.SyncDataReadExposedAll) (interface{}, error) + ReadExposed(context.Context, *request.SyncDataReadExposed) (interface{}, error) + } + + // HTTP API interface + SyncData struct { + ReadExposedAll func(http.ResponseWriter, *http.Request) + ReadExposed func(http.ResponseWriter, *http.Request) + } +) + +func NewSyncData(h SyncDataAPI) *SyncData { + return &SyncData{ + ReadExposedAll: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewSyncDataReadExposedAll() + if err := params.Fill(r); err != nil { + logger.LogParamError("SyncData.ReadExposedAll", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.ReadExposedAll(r.Context(), params) + if err != nil { + logger.LogControllerError("SyncData.ReadExposedAll", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("SyncData.ReadExposedAll", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + ReadExposed: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewSyncDataReadExposed() + if err := params.Fill(r); err != nil { + logger.LogParamError("SyncData.ReadExposed", r, err) + resputil.JSON(w, err) + return + } + + value, err := h.ReadExposed(r.Context(), params) + if err != nil { + logger.LogControllerError("SyncData.ReadExposed", r, err, params.Auditable()) + resputil.JSON(w, err) + return + } + logger.LogControllerCall("SyncData.ReadExposed", r, params.Auditable()) + if !serveHTTP(value, w, r) { + resputil.JSON(w, value) + } + }, + } +} + +func (h SyncData) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { + r.Group(func(r chi.Router) { + r.Use(middlewares...) + r.Get("/exposed/records/", h.ReadExposedAll) + r.Get("/exposed/modules/{moduleID}/records/", h.ReadExposed) + }) +} diff --git a/federation/rest/request/syncData.go b/federation/rest/request/syncData.go new file mode 100644 index 000000000..1b71df1d1 --- /dev/null +++ b/federation/rest/request/syncData.go @@ -0,0 +1,260 @@ +package request + +// This file is auto-generated. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Definitions file that controls how this file is generated: +// + +import ( + "encoding/json" + "fmt" + "github.com/cortezaproject/corteza-server/pkg/payload" + "github.com/go-chi/chi" + "io" + "mime/multipart" + "net/http" + "strings" +) + +// dummy vars to prevent +// unused imports complain +var ( + _ = chi.URLParam + _ = multipart.ErrMessageTooLarge + _ = payload.ParseUint64s +) + +type ( + // Internal API interface + SyncDataReadExposedAll struct { + // Query GET parameter + // + // Search query + Query string + + // Limit GET parameter + // + // Limit + Limit uint + + // PageCursor GET parameter + // + // Page cursor + PageCursor string + + // Sort GET parameter + // + // Sort items + Sort string + } + + SyncDataReadExposed struct { + // ModuleID PATH parameter + // + // Module ID + ModuleID uint64 `json:",string"` + + // Query GET parameter + // + // Search query + Query string + + // Limit GET parameter + // + // Limit + Limit uint + + // PageCursor GET parameter + // + // Page cursor + PageCursor string + + // Sort GET parameter + // + // Sort items + Sort string + } +) + +// NewSyncDataReadExposedAll request +func NewSyncDataReadExposedAll() *SyncDataReadExposedAll { + return &SyncDataReadExposedAll{} +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposedAll) Auditable() map[string]interface{} { + return map[string]interface{}{ + "query": r.Query, + "limit": r.Limit, + "pageCursor": r.PageCursor, + "sort": r.Sort, + } +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposedAll) GetQuery() string { + return r.Query +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposedAll) GetLimit() uint { + return r.Limit +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposedAll) GetPageCursor() string { + return r.PageCursor +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposedAll) GetSort() string { + return r.Sort +} + +// Fill processes request and fills internal variables +func (r *SyncDataReadExposedAll) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return fmt.Errorf("error parsing http request body: %w", err) + } + } + + { + // GET params + tmp := req.URL.Query() + + if val, ok := tmp["query"]; ok && len(val) > 0 { + r.Query, err = val[0], nil + if err != nil { + return err + } + } + if val, ok := tmp["limit"]; ok && len(val) > 0 { + r.Limit, err = payload.ParseUint(val[0]), nil + if err != nil { + return err + } + } + if val, ok := tmp["pageCursor"]; ok && len(val) > 0 { + r.PageCursor, err = val[0], nil + if err != nil { + return err + } + } + if val, ok := tmp["sort"]; ok && len(val) > 0 { + r.Sort, err = val[0], nil + if err != nil { + return err + } + } + } + + return err +} + +// NewSyncDataReadExposed request +func NewSyncDataReadExposed() *SyncDataReadExposed { + return &SyncDataReadExposed{} +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposed) Auditable() map[string]interface{} { + return map[string]interface{}{ + "moduleID": r.ModuleID, + "query": r.Query, + "limit": r.Limit, + "pageCursor": r.PageCursor, + "sort": r.Sort, + } +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposed) GetModuleID() uint64 { + return r.ModuleID +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposed) GetQuery() string { + return r.Query +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposed) GetLimit() uint { + return r.Limit +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposed) GetPageCursor() string { + return r.PageCursor +} + +// Auditable returns all auditable/loggable parameters +func (r SyncDataReadExposed) GetSort() string { + return r.Sort +} + +// Fill processes request and fills internal variables +func (r *SyncDataReadExposed) Fill(req *http.Request) (err error) { + if strings.ToLower(req.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(req.Body).Decode(r) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return fmt.Errorf("error parsing http request body: %w", err) + } + } + + { + // GET params + tmp := req.URL.Query() + + if val, ok := tmp["query"]; ok && len(val) > 0 { + r.Query, err = val[0], nil + if err != nil { + return err + } + } + if val, ok := tmp["limit"]; ok && len(val) > 0 { + r.Limit, err = payload.ParseUint(val[0]), nil + if err != nil { + return err + } + } + if val, ok := tmp["pageCursor"]; ok && len(val) > 0 { + r.PageCursor, err = val[0], nil + if err != nil { + return err + } + } + if val, ok := tmp["sort"]; ok && len(val) > 0 { + r.Sort, err = val[0], nil + if err != nil { + return err + } + } + } + + { + var val string + // path params + + val = chi.URLParam(req, "moduleID") + r.ModuleID, err = payload.ParseUint64(val), nil + if err != nil { + return err + } + + } + + return err +} diff --git a/federation/rest/router.go b/federation/rest/router.go index 78e01a897..7eb124c84 100644 --- a/federation/rest/router.go +++ b/federation/rest/router.go @@ -14,6 +14,7 @@ func MountRoutes(r chi.Router) { // temporary because of acl handlers.NewManageStructure((ManageStructure{}.New())).MountRoutes(r) handlers.NewSyncStructure((SyncStructure{}.New())).MountRoutes(r) + handlers.NewSyncData((SyncData{}.New())).MountRoutes(r) }) // Protect all _private_ routes diff --git a/federation/rest/sync_data.go b/federation/rest/sync_data.go new file mode 100644 index 000000000..aa4e00eae --- /dev/null +++ b/federation/rest/sync_data.go @@ -0,0 +1,71 @@ +package rest + +import ( + "context" + + cs "github.com/cortezaproject/corteza-server/compose/service" + "github.com/cortezaproject/corteza-server/compose/types" + ct "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/federation/rest/request" + "github.com/cortezaproject/corteza-server/federation/service" + "github.com/davecgh/go-spew/spew" +) + +type ( + SyncData struct{} + + recordPayload struct { + *types.Record + + Records ct.RecordSet `json:"records,omitempty"` + + CanUpdateRecord bool `json:"canUpdateRecord"` + CanDeleteRecord bool `json:"canDeleteRecord"` + } + + recordSetPayload struct { + Filter *ct.RecordFilter `json:"filter,omitempty"` + Set []*recordPayload `json:"set"` + } +) + +func (SyncData) New() *SyncData { + return &SyncData{} +} + +func (ctrl SyncData) ReadExposedAll(ctx context.Context, r *request.SyncDataReadExposedAll) (interface{}, error) { + // /exposed/records/ + // fetch the node info here so we can use the node ID in the filtering + + return nil, nil +} + +func (ctrl SyncData) ReadExposed(ctx context.Context, r *request.SyncDataReadExposed) (interface{}, error) { + // /exposed/modules/{moduleID}/records/ + // fetch the node info here so we can use the node ID in the filtering + + var ( + err error + f = ct.RecordFilter{} + ) + + // use the fetched node + em, err := (service.ExposedModule()).FindByID(ctx, 276342359342989444, r.ModuleID) + + if err != nil { + return nil, err + } + + filter := ct.RecordFilter{ModuleID: em.ComposeModuleID} + + // find the compose module records + list, f, err := (cs.Record()).Find(filter) + + if err != nil { + return nil, err + } + + spew.Dump(list, f, err) + + return nil, nil +}