Add record procedure exec capabilities

This will allow us to perform bulk operations on record & record-values
This commit is contained in:
Denis Arh
2019-09-13 11:29:01 +02:00
parent 05dfa30500
commit dc99bc2cb8
14 changed files with 565 additions and 53 deletions
+23
View File
@@ -35,6 +35,7 @@ type RecordAPI interface {
ImportRun(context.Context, *request.RecordImportRun) (interface{}, error)
ImportProgress(context.Context, *request.RecordImportProgress) (interface{}, error)
Export(context.Context, *request.RecordExport) (interface{}, error)
Exec(context.Context, *request.RecordExec) (interface{}, error)
Create(context.Context, *request.RecordCreate) (interface{}, error)
Read(context.Context, *request.RecordRead) (interface{}, error)
Update(context.Context, *request.RecordUpdate) (interface{}, error)
@@ -50,6 +51,7 @@ type Record struct {
ImportRun func(http.ResponseWriter, *http.Request)
ImportProgress func(http.ResponseWriter, *http.Request)
Export func(http.ResponseWriter, *http.Request)
Exec func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Update func(http.ResponseWriter, *http.Request)
@@ -179,6 +181,26 @@ func NewRecord(h RecordAPI) *Record {
resputil.JSON(w, value)
}
},
Exec: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewRecordExec()
if err := params.Fill(r); err != nil {
logger.LogParamError("Record.Exec", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Exec(r.Context(), params)
if err != nil {
logger.LogControllerError("Record.Exec", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("Record.Exec", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Create: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewRecordCreate()
@@ -291,6 +313,7 @@ func (h Record) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http
r.Patch("/namespace/{namespaceID}/module/{moduleID}/record/import/{sessionID}", h.ImportRun)
r.Get("/namespace/{namespaceID}/module/{moduleID}/record/import/{sessionID}", h.ImportProgress)
r.Get("/namespace/{namespaceID}/module/{moduleID}/record/export{filename}.{ext}", h.Export)
r.Post("/namespace/{namespaceID}/module/{moduleID}/record/exec/{procedure}", h.Exec)
r.Post("/namespace/{namespaceID}/module/{moduleID}/record/", h.Create)
r.Get("/namespace/{namespaceID}/module/{moduleID}/record/{recordID}", h.Read)
r.Post("/namespace/{namespaceID}/module/{moduleID}/record/{recordID}", h.Update)
+22
View File
@@ -347,6 +347,28 @@ func (ctrl *Record) Export(ctx context.Context, r *request.RecordExport) (interf
}, nil
}
func (ctrl Record) Exec(ctx context.Context, r *request.RecordExec) (interface{}, error) {
aa := request.ProcedureArgs(r.Args)
switch r.Procedure {
case "organize":
return resputil.OK(), ctrl.record.With(ctx).Organize(
r.NamespaceID,
r.ModuleID,
aa.GetUint64("recordID"),
aa.Get("sortingField"),
aa.Get("sortingValue"),
aa.Get("sortingFilter"),
aa.Get("valueField"),
aa.Get("value"),
)
default:
return nil, errors.New("unknown procedure")
}
return nil, nil
}
func (ctrl Record) makePayload(ctx context.Context, m *types.Module, r *types.Record, err error) (*recordPayload, error) {
if err != nil || r == nil {
return nil, err
+59
View File
@@ -435,6 +435,65 @@ func (r *RecordExport) Fill(req *http.Request) (err error) {
var _ RequestFiller = NewRecordExport()
// Record exec request parameters
type RecordExec struct {
Procedure string
NamespaceID uint64 `json:",string"`
ModuleID uint64 `json:",string"`
Args []ProcedureArg
}
func NewRecordExec() *RecordExec {
return &RecordExec{}
}
func (r RecordExec) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["procedure"] = r.Procedure
out["namespaceID"] = r.NamespaceID
out["moduleID"] = r.ModuleID
out["args"] = r.Args
return out
}
func (r *RecordExec) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
r.Procedure = chi.URLParam(req, "procedure")
r.NamespaceID = parseUInt64(chi.URLParam(req, "namespaceID"))
r.ModuleID = parseUInt64(chi.URLParam(req, "moduleID"))
return err
}
var _ RequestFiller = NewRecordExec()
// Record create request parameters
type RecordCreate struct {
Values types.RecordValueSet
+25
View File
@@ -12,6 +12,15 @@ import (
"github.com/pkg/errors"
)
type (
ProcedureArgs []ProcedureArg
ProcedureArg struct {
Name string `json:"name"`
Value string `json:"value"`
}
)
var truthy = regexp.MustCompile(`^\s*(t(rue)?|y(es)?|1)\s*$`)
func parseJSONTextWithErr(s string) (types.JSONText, error) {
@@ -97,3 +106,19 @@ func is(s string, matches ...string) bool {
}
return false
}
func (args ProcedureArgs) GetUint64(name string) uint64 {
u, _ := strconv.ParseUint(args.Get(name), 10, 64)
return u
}
func (args ProcedureArgs) Get(name string) string {
name = strings.ToLower(name)
for _, arg := range args {
if strings.ToLower(arg.Name) == name {
return arg.Value
}
}
return ""
}