package system import ( "context" "fmt" "io" "net/http" "testing" "time" "github.com/cortezaproject/corteza/server/pkg/id" "github.com/cortezaproject/corteza/server/store" "github.com/cortezaproject/corteza/server/system/service" "github.com/cortezaproject/corteza/server/system/types" "github.com/cortezaproject/corteza/server/tests/helpers" jsonpath "github.com/steinfletcher/apitest-jsonpath" ) func (h helper) repoMakeTemplate(ss ...string) *types.Template { var res = &types.Template{ ID: id.Next(), CreatedAt: time.Now(), } if len(ss) > 0 { res.Handle = ss[0] } else { res.Handle = "n_" + rs() } if len(ss) > 1 { res.Template = ss[1] } if len(ss) > 2 { res.Type = types.DocumentType(ss[2]) } h.a.NoError(store.CreateTemplate(context.Background(), service.DefaultStore, res)) return res } func (h helper) lookupTemplateByID(ID uint64) *types.Template { res, err := store.LookupTemplateByID(context.Background(), service.DefaultStore, ID) h.noError(err) return res } func TestTemplateRead(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.AllowMe(h, types.TemplateRbacResource(0), "read") u := h.repoMakeTemplate() h.apiInit(). Get(fmt.Sprintf("/template/%d", u.ID)). Header("Accept", "application/json"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). Assert(jsonpath.Equal(`$.response.handle`, u.Handle)). Assert(jsonpath.Equal(`$.response.templateID`, fmt.Sprintf("%d", u.ID))). End() } func TestTemplateList(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.AllowMe(h, types.TemplateRbacResource(0), "read") h.repoMakeTemplate(rs()) h.repoMakeTemplate(rs()) h.apiInit(). Get("/template/"). Header("Accept", "application/json"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). Assert(jsonpath.Len(`$.response.set`, 2)). End() } func TestTemplateList_filterForbidden(t *testing.T) { h := newHelper(t) h.clearTemplates() // @todo this can be a problematic test because it leaves // behind templates that are not denied this context // db purge might be needed h.repoMakeTemplate("template") f := h.repoMakeTemplate() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.DenyMe(h, f.RbacResource(), "read") h.apiInit(). Get("/template/"). Header("Accept", "application/json"). Query("handle", f.Handle). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). Assert(jsonpath.NotPresent(fmt.Sprintf(`$.response.set[? @.handle=="%s"]`, f.Handle))). End() } func TestTemplateCreateForbidden(t *testing.T) { h := newHelper(t) h.clearTemplates() h.apiInit(). Post("/template/"). Header("Accept", "application/json"). FormData("meta", fmt.Sprintf(`{"short": "%s"}`, rs())). FormData("handle", "a"+rs()). Expect(t). Status(http.StatusOK). Assert(helpers.AssertError("template.errors.notAllowedToCreate")). End() } func TestTemplateCreate(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "template.create") h.apiInit(). Post("/template/"). Header("Accept", "application/json"). FormData("meta", fmt.Sprintf(`{"short": "%s"}`, rs())). FormData("handle", "handle_"+rs()). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() } func TestTemplateUpdateForbidden(t *testing.T) { h := newHelper(t) h.clearTemplates() u := h.repoMakeTemplate() h.apiInit(). Put(fmt.Sprintf("/template/%d", u.ID)). Header("Accept", "application/json"). FormData("meta", fmt.Sprintf(`{"short": "%s"}`, rs())). FormData("handle", "handle_"+rs()). Expect(t). Status(http.StatusOK). Assert(helpers.AssertError("template.errors.notAllowedToUpdate")). End() } func TestTemplateUpdate(t *testing.T) { h := newHelper(t) h.clearTemplates() res := h.repoMakeTemplate() helpers.AllowMe(h, types.TemplateRbacResource(0), "update") newHandle := "updated-" + rs() h.apiInit(). Put(fmt.Sprintf("/template/%d", res.ID)). Header("Accept", "application/json"). FormData("meta", fmt.Sprintf(`{"short": "%s"}`, rs())). FormData("handle", newHandle). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() res = h.lookupTemplateByID(res.ID) h.a.NotNil(res) h.a.Equal(newHandle, res.Handle) } func TestTemplateDeleteForbidden(t *testing.T) { h := newHelper(t) h.clearTemplates() u := h.repoMakeTemplate() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") h.apiInit(). Delete(fmt.Sprintf("/template/%d", u.ID)). Header("Accept", "application/json"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertError("template.errors.notAllowedToDelete")). End() } func TestTemplateDelete(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.TemplateRbacResource(0), "delete") res := h.repoMakeTemplate() h.apiInit(). Delete(fmt.Sprintf("/template/%d", res.ID)). Header("Accept", "application/json"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() res = h.lookupTemplateByID(res.ID) h.a.NotNil(res) h.a.NotNil(res.DeletedAt) } func TestTemplateUndelete(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.TemplateRbacResource(0), "delete") res := h.repoMakeTemplate() h.apiInit(). Post(fmt.Sprintf("/template/%d/undelete", res.ID)). Header("Accept", "application/json"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() res = h.lookupTemplateByID(res.ID) h.a.NotNil(res) h.a.Nil(res.DeletedAt) } func TestTemplateRenderForbidden(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.AllowMe(h, types.TemplateRbacResource(0), "read") helpers.DenyMe(h, types.TemplateRbacResource(0), "render") res := h.repoMakeTemplate("rendering", "Hello, {{.interpolate}}", "text/plain") h.apiInit(). Post(fmt.Sprintf("/template/%d/render/testing.txt", res.ID)). JSON(`{"variables": {"interpolate": "world!"}}`). Header("Accept", "application/json"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertError("template.errors.notAllowedToRender")). End() } func TestTemplateRenderDriverUndefined(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.AllowMe(h, types.TemplateRbacResource(0), "read") helpers.AllowMe(h, types.TemplateRbacResource(0), "render") res := h.repoMakeTemplate("rendering", "Hello, {{.interpolate}}", "text/notexisting") h.apiInit(). Post(fmt.Sprintf("/template/%d/render/testing.txt", res.ID)). JSON(`{"variables": {"interpolate": "world!"}}`). Header("Accept", "application/json"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertError("rendering failed: driver not found")). End() } func TestTemplateRenderPlain(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.AllowMe(h, types.TemplateRbacResource(0), "read") helpers.AllowMe(h, types.TemplateRbacResource(0), "render") res := h.repoMakeTemplate("rendering", "Hello, {{.interpolate}}", "text/plain") h.apiInit(). Post(fmt.Sprintf("/template/%d/render/testing.txt", res.ID)). Header("Accept", "application/json"). JSON(`{"variables": {"interpolate": "world!"}}`). Expect(t). Status(http.StatusOK). Assert(helpers.AssertBody("Hello, world!")). End() } func TestTemplateRenderHTML(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.AllowMe(h, types.TemplateRbacResource(0), "read") helpers.AllowMe(h, types.TemplateRbacResource(0), "render") res := h.repoMakeTemplate("rendering", "

Hello, {{.interpolate}}

", "text/html") h.apiInit(). Post(fmt.Sprintf("/template/%d/render/testing.html", res.ID)). Header("Accept", "application/json"). JSON(`{"variables": {"interpolate": "world!"}}`). Expect(t). Status(http.StatusOK). Assert(helpers.AssertBody("

Hello, world!

")). End() } func TestTemplateRenderAuxTemplates(t *testing.T) { h := newHelper(t) h.clearTemplates() helpers.AllowMe(h, types.ComponentRbacResource(), "templates.search") helpers.AllowMe(h, types.TemplateRbacResource(0), "read") helpers.AllowMe(h, types.TemplateRbacResource(0), "render") var ( ctx = h.secCtx() header = h.repoMakeTemplate("header-tpl", "
from meta
", "text/html") altHeader = h.repoMakeTemplate("alt-header-tpl", "
from argument
", "text/html") footer = h.repoMakeTemplate("footer-tpl", "", "text/html") body = h.repoMakeTemplate("body-tpl", "

Hello

", "text/html") ) body.Meta.HeaderTemplateID = header.ID h.a.NoError(store.UpdateTemplate(ctx, service.DefaultStore, body)) read := func(aux types.TemplateRenderAux) string { doc, err := service.DefaultRenderer.Render(ctx, body.ID, "text/html", nil, nil, aux) h.a.NoError(err) out, err := io.ReadAll(doc) h.a.NoError(err) return string(out) } // no overrides, header comes from the template's own meta out := read(types.TemplateRenderAux{}) h.a.Contains(out, "from meta") h.a.NotContains(out, "from argument") h.a.NotContains(out, "bye") // header overridden, footer added out = read(types.TemplateRenderAux{HeaderTemplateID: altHeader.ID, FooterTemplateID: footer.ID}) h.a.Contains(out, "from argument") h.a.NotContains(out, "from meta") h.a.Contains(out, "bye") h.a.Contains(out, "

Hello

") }