From 6bd82c3e9d95da9d131ca9e523a45d8317da428a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Wed, 5 May 2021 11:18:19 +0200 Subject: [PATCH] Add endpoint to fetch available render drivers --- system/renderer/generic_html.go | 35 ++++++++++++++++++++++++---- system/renderer/generic_text.go | 35 ++++++++++++++++++++++++---- system/renderer/gotenbergPDF.go | 30 ++++++++++++++++++++++-- system/renderer/renderer.go | 8 +++++++ system/renderer/types.go | 8 +++++++ system/rest.yaml | 4 ++++ system/rest/handlers/template.go | 33 +++++++++++++++++++++------ system/rest/request/template.go | 19 ++++++++++++++++ system/rest/template.go | 39 ++++++++++++++++++++++++++------ system/service/template.go | 6 +++++ 10 files changed, 193 insertions(+), 24 deletions(-) diff --git a/system/renderer/generic_html.go b/system/renderer/generic_html.go index 45811a8c4..277e5d14e 100644 --- a/system/renderer/generic_html.go +++ b/system/renderer/generic_html.go @@ -9,20 +9,47 @@ import ( ) type ( - genericHTML struct{} + genericHTML struct { + def DriverDefinition + } genericHTMLDriver struct{} ) func newGenericHTML() driverFactory { - return &genericHTML{} + return &genericHTML{ + def: DriverDefinition{ + Name: "genericHTML", + InputTypes: []types.DocumentType{ + types.DocumentTypePlain, + types.DocumentTypeHTML, + }, + OutputTypes: []types.DocumentType{ + types.DocumentTypeHTML, + }, + }, + } +} + +func (d *genericHTML) Define() DriverDefinition { + return d.def } func (d *genericHTML) CanRender(t types.DocumentType) bool { - return t == types.DocumentTypeHTML || t == types.DocumentTypePlain + for _, i := range d.def.InputTypes { + if i == t { + return true + } + } + return false } func (d *genericHTML) CanProduce(t types.DocumentType) bool { - return t == types.DocumentTypeHTML + for _, o := range d.def.OutputTypes { + if o == t { + return true + } + } + return false } func (d *genericHTML) Driver() driver { diff --git a/system/renderer/generic_text.go b/system/renderer/generic_text.go index 204d1edfc..ba4b8aa36 100644 --- a/system/renderer/generic_text.go +++ b/system/renderer/generic_text.go @@ -10,7 +10,9 @@ import ( ) type ( - genericText struct{} + genericText struct { + def DriverDefinition + } genericTextDriver struct{} ) @@ -19,15 +21,40 @@ var ( ) func newGenericText() driverFactory { - return &genericText{} + return &genericText{ + def: DriverDefinition{ + Name: "genericText", + InputTypes: []types.DocumentType{ + types.DocumentTypePlain, + types.DocumentTypeHTML, + }, + OutputTypes: []types.DocumentType{ + types.DocumentTypePlain, + }, + }, + } +} + +func (d *genericText) Define() DriverDefinition { + return d.def } func (d *genericText) CanRender(t types.DocumentType) bool { - return t == types.DocumentTypePlain || t == types.DocumentTypeHTML + for _, i := range d.def.InputTypes { + if i == t { + return true + } + } + return false } func (d *genericText) CanProduce(t types.DocumentType) bool { - return t == types.DocumentTypePlain + for _, o := range d.def.OutputTypes { + if o == t { + return true + } + } + return false } func (d *genericText) Driver() driver { diff --git a/system/renderer/gotenbergPDF.go b/system/renderer/gotenbergPDF.go index 3c86d9d0b..afe21e7ca 100644 --- a/system/renderer/gotenbergPDF.go +++ b/system/renderer/gotenbergPDF.go @@ -15,6 +15,7 @@ import ( type ( gotenbergPDF struct { url string + def DriverDefinition } gotenbergPDFDriver struct { url string @@ -25,15 +26,40 @@ type ( func newGotenbergPDF(url string) driverFactory { return &gotenbergPDF{ url: url, + + def: DriverDefinition{ + Name: "gotenbergPDF", + InputTypes: []types.DocumentType{ + types.DocumentTypePlain, + types.DocumentTypeHTML, + }, + OutputTypes: []types.DocumentType{ + types.DocumentTypePDF, + }, + }, } } +func (d *gotenbergPDF) Define() DriverDefinition { + return d.def +} + func (d *gotenbergPDF) CanRender(t types.DocumentType) bool { - return t == types.DocumentTypeHTML || t == types.DocumentTypePlain + for _, i := range d.def.InputTypes { + if i == t { + return true + } + } + return false } func (d *gotenbergPDF) CanProduce(t types.DocumentType) bool { - return t == types.DocumentTypePDF + for _, o := range d.def.OutputTypes { + if o == t { + return true + } + } + return false } func (d *gotenbergPDF) Driver() driver { diff --git a/system/renderer/renderer.go b/system/renderer/renderer.go index abfac3b09..84cf5cddd 100644 --- a/system/renderer/renderer.go +++ b/system/renderer/renderer.go @@ -47,3 +47,11 @@ func (r *renderer) Render(ctx context.Context, pl *RendererPayload) (io.ReadSeek return nil, errors.New("rendering failed: driver not found") } + +func (r *renderer) Drivers() []DriverDefinition { + dd := make([]DriverDefinition, len(r.factories)) + for i, f := range r.factories { + dd[i] = f.Define() + } + return dd +} diff --git a/system/renderer/types.go b/system/renderer/types.go index a97e8f4b7..a669ea168 100644 --- a/system/renderer/types.go +++ b/system/renderer/types.go @@ -39,7 +39,15 @@ type ( Name string } + DriverDefinition struct { + Name string `json:"name"` + InputTypes []types.DocumentType `json:"inputTypes"` + OutputTypes []types.DocumentType `json:"outputTypes"` + } + driverFactory interface { + Define() DriverDefinition + CanRender(t types.DocumentType) bool CanProduce(t types.DocumentType) bool Driver() driver diff --git a/system/rest.yaml b/system/rest.yaml index cb39116c9..72f99a7bf 100644 --- a/system/rest.yaml +++ b/system/rest.yaml @@ -1343,6 +1343,10 @@ endpoints: type: uint64 required: true title: Template ID + - name: renderDrivers + method: GET + title: Render drivers + path: "/render/drivers" - name: render method: POST title: Render template diff --git a/system/rest/handlers/template.go b/system/rest/handlers/template.go index f69ed934b..4e49f76fb 100644 --- a/system/rest/handlers/template.go +++ b/system/rest/handlers/template.go @@ -25,18 +25,20 @@ type ( Update(context.Context, *request.TemplateUpdate) (interface{}, error) Delete(context.Context, *request.TemplateDelete) (interface{}, error) Undelete(context.Context, *request.TemplateUndelete) (interface{}, error) + RenderDrivers(context.Context, *request.TemplateRenderDrivers) (interface{}, error) Render(context.Context, *request.TemplateRender) (interface{}, error) } // HTTP API interface Template struct { - List func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) - Read func(http.ResponseWriter, *http.Request) - Update func(http.ResponseWriter, *http.Request) - Delete func(http.ResponseWriter, *http.Request) - Undelete func(http.ResponseWriter, *http.Request) - Render func(http.ResponseWriter, *http.Request) + List func(http.ResponseWriter, *http.Request) + Create func(http.ResponseWriter, *http.Request) + Read func(http.ResponseWriter, *http.Request) + Update func(http.ResponseWriter, *http.Request) + Delete func(http.ResponseWriter, *http.Request) + Undelete func(http.ResponseWriter, *http.Request) + RenderDrivers func(http.ResponseWriter, *http.Request) + Render func(http.ResponseWriter, *http.Request) } ) @@ -138,6 +140,22 @@ func NewTemplate(h TemplateAPI) *Template { api.Send(w, r, value) }, + RenderDrivers: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewTemplateRenderDrivers() + if err := params.Fill(r); err != nil { + api.Send(w, r, err) + return + } + + value, err := h.RenderDrivers(r.Context(), params) + if err != nil { + api.Send(w, r, err) + return + } + + api.Send(w, r, value) + }, Render: func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() params := request.NewTemplateRender() @@ -166,6 +184,7 @@ func (h Template) MountRoutes(r chi.Router, middlewares ...func(http.Handler) ht r.Put("/template/{templateID}", h.Update) r.Delete("/template/{templateID}", h.Delete) r.Post("/template/{templateID}/undelete", h.Undelete) + r.Get("/template/render/drivers", h.RenderDrivers) r.Post("/template/{templateID}/render/{filename}.{ext}", h.Render) }) } diff --git a/system/rest/request/template.go b/system/rest/request/template.go index fb6c644fc..f11792825 100644 --- a/system/rest/request/template.go +++ b/system/rest/request/template.go @@ -192,6 +192,9 @@ type ( TemplateID uint64 `json:",string"` } + TemplateRenderDrivers struct { + } + TemplateRender struct { // TemplateID PATH parameter // @@ -779,6 +782,22 @@ func (r *TemplateUndelete) Fill(req *http.Request) (err error) { return err } +// NewTemplateRenderDrivers request +func NewTemplateRenderDrivers() *TemplateRenderDrivers { + return &TemplateRenderDrivers{} +} + +// Auditable returns all auditable/loggable parameters +func (r TemplateRenderDrivers) Auditable() map[string]interface{} { + return map[string]interface{}{} +} + +// Fill processes request and fills internal variables +func (r *TemplateRenderDrivers) Fill(req *http.Request) (err error) { + + return err +} + // NewTemplateRender request func NewTemplateRender() *TemplateRender { return &TemplateRender{} diff --git a/system/rest/template.go b/system/rest/template.go index 492b532be..2dd3b1c96 100644 --- a/system/rest/template.go +++ b/system/rest/template.go @@ -11,6 +11,7 @@ import ( "github.com/cortezaproject/corteza-server/pkg/api" "github.com/cortezaproject/corteza-server/pkg/filter" + "github.com/cortezaproject/corteza-server/system/renderer" "github.com/cortezaproject/corteza-server/system/rest/request" "github.com/cortezaproject/corteza-server/system/service" "github.com/cortezaproject/corteza-server/system/types" @@ -38,6 +39,14 @@ type ( CanDeleteTemplate bool `json:"canDeleteTemplate"` } + driverSetPayload struct { + Set []*driverPayload `json:"set"` + } + + driverPayload struct { + renderer.DriverDefinition + } + templateAccessController interface { CanGrant(context.Context) bool CanCreateTemplate(context.Context) bool @@ -56,7 +65,7 @@ func (Template) New() *Template { func (ctrl *Template) Read(ctx context.Context, r *request.TemplateRead) (interface{}, error) { tpl, err := ctrl.renderer.FindByID(ctx, r.TemplateID) - return ctrl.makePayload(ctx, tpl, err) + return ctrl.makeTemplatePayload(ctx, tpl, err) } func (ctrl *Template) List(ctx context.Context, r *request.TemplateList) (interface{}, error) { @@ -80,7 +89,7 @@ func (ctrl *Template) List(ctx context.Context, r *request.TemplateList) (interf } set, filter, err := ctrl.renderer.Search(ctx, f) - return ctrl.makeFilterPayload(ctx, set, filter, err) + return ctrl.makeFilterTemplatePayload(ctx, set, filter, err) } func (ctrl *Template) Create(ctx context.Context, r *request.TemplateCreate) (interface{}, error) { @@ -98,7 +107,7 @@ func (ctrl *Template) Create(ctx context.Context, r *request.TemplateCreate) (in ) app, err = ctrl.renderer.Create(ctx, app) - return ctrl.makePayload(ctx, app, err) + return ctrl.makeTemplatePayload(ctx, app, err) } func (ctrl *Template) Update(ctx context.Context, r *request.TemplateUpdate) (interface{}, error) { @@ -117,7 +126,7 @@ func (ctrl *Template) Update(ctx context.Context, r *request.TemplateUpdate) (in ) app, err = ctrl.renderer.Update(ctx, app) - return ctrl.makePayload(ctx, app, err) + return ctrl.makeTemplatePayload(ctx, app, err) } func (ctrl *Template) Delete(ctx context.Context, r *request.TemplateDelete) (interface{}, error) { @@ -128,6 +137,10 @@ func (ctrl *Template) Undelete(ctx context.Context, r *request.TemplateUndelete) return api.OK(), ctrl.renderer.UndeleteByID(ctx, r.TemplateID) } +func (ctrl *Template) RenderDrivers(ctx context.Context, r *request.TemplateRenderDrivers) (interface{}, error) { + return ctrl.makeSetRenderDriverPayload(ctx, ctrl.renderer.Drivers()), nil +} + func (ctrl *Template) Render(ctx context.Context, r *request.TemplateRender) (interface{}, error) { vars := make(map[string]interface{}) err := json.Unmarshal(r.Variables, &vars) @@ -151,7 +164,7 @@ func (ctrl *Template) Render(ctx context.Context, r *request.TemplateRender) (in // Utilities -func (ctrl Template) makeFilterPayload(ctx context.Context, nn types.TemplateSet, f types.TemplateFilter, err error) (*templateSetPayload, error) { +func (ctrl Template) makeFilterTemplatePayload(ctx context.Context, nn types.TemplateSet, f types.TemplateFilter, err error) (*templateSetPayload, error) { if err != nil { return nil, err } @@ -159,13 +172,13 @@ func (ctrl Template) makeFilterPayload(ctx context.Context, nn types.TemplateSet msp := &templateSetPayload{Filter: f, Set: make([]*templatePayload, len(nn))} for i := range nn { - msp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil) + msp.Set[i], _ = ctrl.makeTemplatePayload(ctx, nn[i], nil) } return msp, nil } -func (ctrl Template) makePayload(ctx context.Context, tpl *types.Template, err error) (*templatePayload, error) { +func (ctrl Template) makeTemplatePayload(ctx context.Context, tpl *types.Template, err error) (*templatePayload, error) { if err != nil || tpl == nil { return nil, err } @@ -181,6 +194,18 @@ func (ctrl Template) makePayload(ctx context.Context, tpl *types.Template, err e return pl, nil } +func (ctrl Template) makeSetRenderDriverPayload(ctx context.Context, nn []renderer.DriverDefinition) *driverSetPayload { + msp := &driverSetPayload{Set: make([]*driverPayload, len(nn))} + + for i := range nn { + msp.Set[i] = &driverPayload{ + DriverDefinition: nn[i], + } + } + + return msp +} + func (ctrl *Template) serve(doc io.ReadSeeker, ct string, r *request.TemplateRender, err error) (interface{}, error) { if err != nil { return nil, err diff --git a/system/service/template.go b/system/service/template.go index 1919e3f25..b3e9e40e7 100644 --- a/system/service/template.go +++ b/system/service/template.go @@ -36,6 +36,7 @@ type ( rendererService interface { Render(ctx context.Context, p *renderer.RendererPayload) (io.ReadSeeker, error) + Drivers() []renderer.DriverDefinition } TemplateService interface { @@ -50,6 +51,7 @@ type ( DeleteByID(ctx context.Context, ID uint64) error UndeleteByID(ctx context.Context, ID uint64) error + Drivers() []renderer.DriverDefinition Render(ctx context.Context, templateID uint64, dstType string, variables map[string]interface{}, options map[string]string) (io.ReadSeeker, error) } ) @@ -330,6 +332,10 @@ func (svc template) UndeleteByID(ctx context.Context, ID uint64) (err error) { return svc.recordAction(ctx, tplProps, TemplateActionUndelete, err) } +func (svc template) Drivers() []renderer.DriverDefinition { + return svc.renderer.Drivers() +} + func (svc template) Render(ctx context.Context, templateID uint64, dstType string, variables map[string]interface{}, options map[string]string) (document io.ReadSeeker, err error) { var ( tplProps = &templateActionProps{}