From d117ce5027fca99d748bbe6d2c0a9eac2658f29f Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Tue, 8 Aug 2023 02:29:14 +0200 Subject: [PATCH] Add public page for campsite type, and function to edit them Had to export and move PublicPage struct to template because i can not import app from campsites/types: app already imports campsite for the http handler, and it, in turn, imports the types package for its own http handler; an import loop. Also had to replace PublicPage.MustRender with a Setup function because the page passed down to html/template was the PublicPage struct, not whatever struct embeds it. I was thinking more of Java inheritance here rather than struct embedding. --- deploy/edit_campsite_type.sql | 25 ++++++ pkg/app/admin.go | 4 +- pkg/app/public.go | 55 ++++-------- pkg/campsite/{http.go => admin.go} | 13 +-- pkg/campsite/public.go | 39 +++++++++ pkg/campsite/{type.go => types/admin.go} | 57 +++++++++++-- pkg/campsite/types/public.go | 68 +++++++++++++++ pkg/template/page.go | 85 +++++++++++++++++++ po/ca.po | 45 ++++++---- po/es.po | 45 ++++++---- revert/edit_campsite_type.sql | 7 ++ sqitch.plan | 1 + test/edit_campsite_type.sql | 59 +++++++++++++ verify/edit_campsite_type.sql | 7 ++ .../admin/campsite/type/index.gohtml | 4 +- web/templates/admin/campsite/type/new.gohtml | 33 +++++-- web/templates/public/campsite/type.gohtml | 14 +++ web/templates/public/layout.gohtml | 17 ++++ 18 files changed, 490 insertions(+), 88 deletions(-) create mode 100644 deploy/edit_campsite_type.sql rename pkg/campsite/{http.go => admin.go} (64%) create mode 100644 pkg/campsite/public.go rename pkg/campsite/{type.go => types/admin.go} (67%) create mode 100644 pkg/campsite/types/public.go create mode 100644 pkg/template/page.go create mode 100644 revert/edit_campsite_type.sql create mode 100644 test/edit_campsite_type.sql create mode 100644 verify/edit_campsite_type.sql create mode 100644 web/templates/public/campsite/type.gohtml diff --git a/deploy/edit_campsite_type.sql b/deploy/edit_campsite_type.sql new file mode 100644 index 0000000..b0bfe86 --- /dev/null +++ b/deploy/edit_campsite_type.sql @@ -0,0 +1,25 @@ +-- Deploy camper:edit_campsite_type to pg +-- requires: roles +-- requires: schema_camper +-- requires: campsite_type +-- requires: company + +begin; + +set search_path to camper, public; + +create or replace function edit_campsite_type(slug uuid, name text, description text) returns uuid as +$$ + update campsite_type + set name = edit_campsite_type.name + , description = xmlparse(content edit_campsite_type.description) + where slug = edit_campsite_type.slug + returning slug; +$$ +language sql +; + +revoke execute on function edit_campsite_type(uuid, text, text) from public; +grant execute on function edit_campsite_type(uuid, text, text) to admin; + +commit; diff --git a/pkg/app/admin.go b/pkg/app/admin.go index ca1eaf8..a80b92a 100644 --- a/pkg/app/admin.go +++ b/pkg/app/admin.go @@ -16,12 +16,12 @@ import ( ) type adminHandler struct { - campsite *campsite.Handler + campsite *campsite.AdminHandler } func newAdminHandler() *adminHandler { return &adminHandler{ - campsite: campsite.NewHandler(), + campsite: campsite.NewAdminHandler(), } } diff --git a/pkg/app/public.go b/pkg/app/public.go index 2d672b8..b17fc51 100644 --- a/pkg/app/public.go +++ b/pkg/app/public.go @@ -6,19 +6,23 @@ package app import ( + "net/http" + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/campsite" "dev.tandem.ws/tandem/camper/pkg/database" httplib "dev.tandem.ws/tandem/camper/pkg/http" "dev.tandem.ws/tandem/camper/pkg/template" - "fmt" - "net/http" - "sort" ) -type publicHandler struct{} +type publicHandler struct { + campsite *campsite.PublicHandler +} func newPublicHandler() *publicHandler { - return &publicHandler{} + return &publicHandler{ + campsite: campsite.NewPublicHandler(), + } } func (h *publicHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.Handler { @@ -28,7 +32,9 @@ func (h *publicHandler) Handler(user *auth.User, company *auth.Company, conn *da switch head { case "": page := newHomePage() - page.MustRender(w, r, user, company) + page.MustRender(w, r, user, company, conn) + case "campsites": + h.campsite.Handler(user, company, conn).ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -36,41 +42,14 @@ func (h *publicHandler) Handler(user *auth.User, company *auth.Company, conn *da } type homePage struct { - *PublicPage + *template.PublicPage } func newHomePage() *homePage { - return &homePage{newPublicPage("home.gohtml")} + return &homePage{template.NewPublicPage()} } -type PublicPage struct { - template string - LocalizedAlternates []*LocalizedAlternate -} - -func newPublicPage(template string) *PublicPage { - return &PublicPage{ - template: template, - } -} - -func (p *PublicPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { - schema := httplib.Protocol(r) - authority := httplib.Host(r) - _, path := httplib.ShiftPath(r.RequestURI) - for _, l := range company.Locales { - p.LocalizedAlternates = append(p.LocalizedAlternates, &LocalizedAlternate{ - Lang: l.Language.String(), - Endonym: l.Endonym, - HRef: fmt.Sprintf("%s://%s/%s%s", schema, authority, l.Language, path), - }) - } - sort.Slice(p.LocalizedAlternates, func(i, j int) bool { return p.LocalizedAlternates[i].Lang < p.LocalizedAlternates[j].Lang }) - template.MustRenderPublic(w, r, user, company, p.template, p) -} - -type LocalizedAlternate struct { - Lang string - HRef string - Endonym string +func (p *homePage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + p.Setup(r, user, company, conn) + template.MustRenderPublic(w, r, user, company, "home.gohtml", p) } diff --git a/pkg/campsite/http.go b/pkg/campsite/admin.go similarity index 64% rename from pkg/campsite/http.go rename to pkg/campsite/admin.go index dce90b6..151e50c 100644 --- a/pkg/campsite/http.go +++ b/pkg/campsite/admin.go @@ -9,21 +9,22 @@ import ( "net/http" "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/campsite/types" "dev.tandem.ws/tandem/camper/pkg/database" httplib "dev.tandem.ws/tandem/camper/pkg/http" ) -type Handler struct { - types *typeHandler +type AdminHandler struct { + types *types.AdminHandler } -func NewHandler() *Handler { - return &Handler{ - types: &typeHandler{}, +func NewAdminHandler() *AdminHandler { + return &AdminHandler{ + types: &types.AdminHandler{}, } } -func (h *Handler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.HandlerFunc { +func (h *AdminHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var head string head, r.URL.Path = httplib.ShiftPath(r.URL.Path) diff --git a/pkg/campsite/public.go b/pkg/campsite/public.go new file mode 100644 index 0000000..9bb4bf0 --- /dev/null +++ b/pkg/campsite/public.go @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2023 jordi fita mas + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package campsite + +import ( + "net/http" + + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/campsite/types" + "dev.tandem.ws/tandem/camper/pkg/database" + httplib "dev.tandem.ws/tandem/camper/pkg/http" +) + +type PublicHandler struct { + types *types.PublicHandler +} + +func NewPublicHandler() *PublicHandler { + return &PublicHandler{ + types: &types.PublicHandler{}, + } +} + +func (h *PublicHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var head string + head, r.URL.Path = httplib.ShiftPath(r.URL.Path) + + switch head { + case "types": + h.types.Handler(user, company, conn).ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} diff --git a/pkg/campsite/type.go b/pkg/campsite/types/admin.go similarity index 67% rename from pkg/campsite/type.go rename to pkg/campsite/types/admin.go index ef0e8ac..28c0661 100644 --- a/pkg/campsite/type.go +++ b/pkg/campsite/types/admin.go @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -package campsite +package types import ( "context" @@ -15,12 +15,13 @@ import ( httplib "dev.tandem.ws/tandem/camper/pkg/http" "dev.tandem.ws/tandem/camper/pkg/locale" "dev.tandem.ws/tandem/camper/pkg/template" + "dev.tandem.ws/tandem/camper/pkg/uuid" ) -type typeHandler struct { +type AdminHandler struct { } -func (h *typeHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.Handler { +func (h *AdminHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var head string head, r.URL.Path = httplib.ShiftPath(r.URL.Path) @@ -44,7 +45,26 @@ func (h *typeHandler) Handler(user *auth.User, company *auth.Company, conn *data httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPost) } default: - http.NotFound(w, r) + if !uuid.Valid(head) { + http.NotFound(w, r) + return + } + f := newTypeForm() + if err := f.FillFromDatabase(r.Context(), conn, head); err != nil { + if database.ErrorIsNotFound(err) { + http.NotFound(w, r) + return + } + panic(err) + } + switch r.Method { + case http.MethodGet: + f.MustRender(w, r, user, company) + case http.MethodPut: + editType(w, r, user, company, conn, f) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet, http.MethodPut) + } } }) } @@ -110,10 +130,31 @@ func addType(w http.ResponseWriter, r *http.Request, user *auth.User, company *a return } conn.MustExec(r.Context(), "select add_campsite_type($1, $2, $3)", company.ID, f.Name, f.Description) - httplib.Redirect(w, r, "/campsites/types", http.StatusSeeOther) + httplib.Redirect(w, r, "/admin/campsites/types", http.StatusSeeOther) +} + +func editType(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *typeForm) { + if err := f.Parse(r); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if err := user.VerifyCSRFToken(r); err != nil { + http.Error(w, err.Error(), http.StatusForbidden) + return + } + if !f.Valid(user.Locale) { + if !httplib.IsHTMxRequest(r) { + w.WriteHeader(http.StatusUnprocessableEntity) + } + f.MustRender(w, r, user, company) + return + } + conn.MustExec(r.Context(), "select edit_campsite_type($1, $2, $3)", f.Slug, f.Name, f.Description) + httplib.Redirect(w, r, "/admin/campsites/types", http.StatusSeeOther) } type typeForm struct { + Slug string Name *form.Input Description *form.Input } @@ -129,6 +170,12 @@ func newTypeForm() *typeForm { } } +func (f *typeForm) FillFromDatabase(ctx context.Context, conn *database.Conn, slug string) error { + f.Slug = slug + row := conn.QueryRow(ctx, "select name, description from campsite_type where slug = $1", slug) + return row.Scan(&f.Name.Val, &f.Description.Val) +} + func (f *typeForm) Parse(r *http.Request) error { if err := r.ParseForm(); err != nil { return err diff --git a/pkg/campsite/types/public.go b/pkg/campsite/types/public.go new file mode 100644 index 0000000..caa266b --- /dev/null +++ b/pkg/campsite/types/public.go @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2023 jordi fita mas + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package types + +import ( + "context" + gotemplate "html/template" + "net/http" + + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/database" + httplib "dev.tandem.ws/tandem/camper/pkg/http" + "dev.tandem.ws/tandem/camper/pkg/template" + "dev.tandem.ws/tandem/camper/pkg/uuid" +) + +type PublicHandler struct { +} + +func (h *PublicHandler) Handler(user *auth.User, company *auth.Company, conn *database.Conn) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var head string + head, r.URL.Path = httplib.ShiftPath(r.URL.Path) + + switch r.Method { + case http.MethodGet: + if !uuid.Valid(head) { + http.NotFound(w, r) + return + } + page, err := newPublicPage(r.Context(), conn, head) + if database.ErrorIsNotFound(err) { + http.NotFound(w, r) + } else if err != nil { + panic(err) + } + page.MustRender(w, r, user, company, conn) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet) + } + }) +} + +type publicPage struct { + *template.PublicPage + Name string + Description gotemplate.HTML +} + +func newPublicPage(ctx context.Context, conn *database.Conn, slug string) (*publicPage, error) { + page := &publicPage{ + PublicPage: template.NewPublicPage(), + } + row := conn.QueryRow(ctx, "select name, description::text from campsite_type where slug = $1", slug) + if err := row.Scan(&page.Name, &page.Description); err != nil { + return nil, err + } + + return page, nil +} + +func (p *publicPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + p.Setup(r, user, company, conn) + template.MustRenderPublic(w, r, user, company, "campsite/type.gohtml", p) +} diff --git a/pkg/template/page.go b/pkg/template/page.go new file mode 100644 index 0000000..e3cfdad --- /dev/null +++ b/pkg/template/page.go @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: 2023 jordi fita mas + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package template + +import ( + "context" + "fmt" + "net/http" + "sort" + + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/database" + httplib "dev.tandem.ws/tandem/camper/pkg/http" + "dev.tandem.ws/tandem/camper/pkg/locale" +) + +type PublicPage struct { + LocalizedAlternates []*LocalizedAlternate + Menu *siteMenu +} + +func NewPublicPage() *PublicPage { + return &PublicPage{} +} + +func (p *PublicPage) Setup(r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + schema := httplib.Protocol(r) + authority := httplib.Host(r) + _, path := httplib.ShiftPath(r.RequestURI) + for _, l := range company.Locales { + p.LocalizedAlternates = append(p.LocalizedAlternates, &LocalizedAlternate{ + Lang: l.Language.String(), + Endonym: l.Endonym, + HRef: fmt.Sprintf("%s://%s/%s%s", schema, authority, l.Language, path), + }) + } + sort.Slice(p.LocalizedAlternates, func(i, j int) bool { return p.LocalizedAlternates[i].Lang < p.LocalizedAlternates[j].Lang }) + + p.Menu = &siteMenu{ + CampsiteTypes: mustCollectMenuItems(r.Context(), conn, user.Locale, "select name, '/campsites/types/' || slug from campsite_type where company_id = $1", company.ID), + } +} + +type LocalizedAlternate struct { + Lang string + HRef string + Endonym string +} + +type siteMenu struct { + CampsiteTypes []*menuItem +} + +type menuItem struct { + Label string + HRef string +} + +func mustCollectMenuItems(ctx context.Context, conn *database.Conn, loc *locale.Locale, sql string, args ...interface{}) []*menuItem { + rows, err := conn.Query(ctx, sql, args...) + if err != nil { + panic(err) + } + defer rows.Close() + + localePath := "/" + loc.Language.String() + var items []*menuItem + for rows.Next() { + item := &menuItem{} + err = rows.Scan(&item.Label, &item.HRef) + if err != nil { + panic(err) + } + item.HRef = localePath + item.HRef + items = append(items, item) + } + if rows.Err() != nil { + panic(rows.Err()) + } + + return items +} diff --git a/po/ca.po b/po/ca.po index 6f6f23a..b67c1e2 100644 --- a/po/ca.po +++ b/po/ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2023-08-05 03:23+0200\n" +"POT-Creation-Date: 2023-08-08 02:43+0200\n" "PO-Revision-Date: 2023-07-22 23:45+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -23,32 +23,47 @@ msgctxt "title" msgid "Home" msgstr "Inici" -#: web/templates/public/layout.gohtml:10 web/templates/public/layout.gohtml:17 +#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:21 msgid "Campsite Montagut" msgstr "Càmping Montagut" -#: web/templates/public/layout.gohtml:16 web/templates/admin/layout.gohtml:18 +#: web/templates/public/layout.gohtml:20 web/templates/admin/layout.gohtml:18 msgid "Skip to main content" msgstr "Salta al contingut principal" -#: web/templates/admin/campsite/type/new.gohtml:14 -#: web/templates/admin/campsite/type/new.gohtml:20 +#: web/templates/public/layout.gohtml:38 +msgid "Singular Lodges" +msgstr "Allotjaments singulars" + +#: web/templates/admin/campsite/type/new.gohtml:16 +#: web/templates/admin/campsite/type/new.gohtml:33 +msgctxt "title" +msgid "Edit Campsite Type" +msgstr "Edició del tipus d’allotjament" + +#: web/templates/admin/campsite/type/new.gohtml:18 +#: web/templates/admin/campsite/type/new.gohtml:35 msgctxt "title" msgid "New Campsite Type" msgstr "Nou tipus d’allotjament" -#: web/templates/admin/campsite/type/new.gohtml:25 +#: web/templates/admin/campsite/type/new.gohtml:42 #: web/templates/admin/profile.gohtml:26 msgctxt "input" msgid "Name" msgstr "Nom" -#: web/templates/admin/campsite/type/new.gohtml:33 +#: web/templates/admin/campsite/type/new.gohtml:50 msgctxt "input" msgid "Description" msgstr "Descripció" -#: web/templates/admin/campsite/type/new.gohtml:40 +#: web/templates/admin/campsite/type/new.gohtml:59 +msgctxt "action" +msgid "Update" +msgstr "Actualitza" + +#: web/templates/admin/campsite/type/new.gohtml:61 msgctxt "action" msgid "Add" msgstr "Afegeix" @@ -140,11 +155,11 @@ msgctxt "action" msgid "Logout" msgstr "Surt" -#: pkg/app/login.go:56 pkg/app/user.go:245 +#: pkg/app/login.go:56 pkg/app/user.go:246 msgid "Email can not be empty." msgstr "No podeu deixar el correu en blanc." -#: pkg/app/login.go:57 pkg/app/user.go:246 +#: pkg/app/login.go:57 pkg/app/user.go:247 msgid "This email is not valid. It should be like name@domain.com." msgstr "Aquest correu-e no és vàlid. Hauria de ser similar a nom@domini.com." @@ -156,24 +171,24 @@ msgstr "No podeu deixar la contrasenya en blanc." msgid "Invalid user or password." msgstr "Nom d’usuari o contrasenya incorrectes." -#: pkg/app/user.go:196 +#: pkg/app/user.go:197 msgctxt "language option" msgid "Automatic" msgstr "Automàtic" -#: pkg/app/user.go:248 pkg/campsite/type.go:143 +#: pkg/app/user.go:249 pkg/campsite/types/admin.go:190 msgid "Name can not be empty." msgstr "No podeu deixar el nom en blanc." -#: pkg/app/user.go:249 +#: pkg/app/user.go:250 msgid "Confirmation does not match password." msgstr "La confirmació no es correspon amb la contrasenya." -#: pkg/app/user.go:250 +#: pkg/app/user.go:251 msgid "Selected language is not valid." msgstr "L’idioma escollit no és vàlid." -#: pkg/app/user.go:252 +#: pkg/app/user.go:253 msgid "File must be a valid PNG or JPEG image." msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida." diff --git a/po/es.po b/po/es.po index 4ac992e..510854d 100644 --- a/po/es.po +++ b/po/es.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2023-08-05 03:23+0200\n" +"POT-Creation-Date: 2023-08-08 02:43+0200\n" "PO-Revision-Date: 2023-07-22 23:46+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -23,32 +23,47 @@ msgctxt "title" msgid "Home" msgstr "Inicio" -#: web/templates/public/layout.gohtml:10 web/templates/public/layout.gohtml:17 +#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:21 msgid "Campsite Montagut" msgstr "Camping Montagut" -#: web/templates/public/layout.gohtml:16 web/templates/admin/layout.gohtml:18 +#: web/templates/public/layout.gohtml:20 web/templates/admin/layout.gohtml:18 msgid "Skip to main content" msgstr "Saltar al contenido principal" -#: web/templates/admin/campsite/type/new.gohtml:14 -#: web/templates/admin/campsite/type/new.gohtml:20 +#: web/templates/public/layout.gohtml:38 +msgid "Singular Lodges" +msgstr "Alojamientos singulares" + +#: web/templates/admin/campsite/type/new.gohtml:16 +#: web/templates/admin/campsite/type/new.gohtml:33 +msgctxt "title" +msgid "Edit Campsite Type" +msgstr "Edición del tipo de alojamientos" + +#: web/templates/admin/campsite/type/new.gohtml:18 +#: web/templates/admin/campsite/type/new.gohtml:35 msgctxt "title" msgid "New Campsite Type" msgstr "Nuevo tipo de alojamiento" -#: web/templates/admin/campsite/type/new.gohtml:25 +#: web/templates/admin/campsite/type/new.gohtml:42 #: web/templates/admin/profile.gohtml:26 msgctxt "input" msgid "Name" msgstr "Nombre" -#: web/templates/admin/campsite/type/new.gohtml:33 +#: web/templates/admin/campsite/type/new.gohtml:50 msgctxt "input" msgid "Description" msgstr "Descripción" -#: web/templates/admin/campsite/type/new.gohtml:40 +#: web/templates/admin/campsite/type/new.gohtml:59 +msgctxt "action" +msgid "Update" +msgstr "Actualitzar" + +#: web/templates/admin/campsite/type/new.gohtml:61 msgctxt "action" msgid "Add" msgstr "Añadir" @@ -140,11 +155,11 @@ msgctxt "action" msgid "Logout" msgstr "Salir" -#: pkg/app/login.go:56 pkg/app/user.go:245 +#: pkg/app/login.go:56 pkg/app/user.go:246 msgid "Email can not be empty." msgstr "No podéis dejar el correo-e en blanco." -#: pkg/app/login.go:57 pkg/app/user.go:246 +#: pkg/app/login.go:57 pkg/app/user.go:247 msgid "This email is not valid. It should be like name@domain.com." msgstr "Este correo-e no es válido. Tiene que ser parecido a nombre@dominio.com." @@ -156,24 +171,24 @@ msgstr "No podéis dejar la contraseña en blanco." msgid "Invalid user or password." msgstr "Usuario o contraseña incorrectos." -#: pkg/app/user.go:196 +#: pkg/app/user.go:197 msgctxt "language option" msgid "Automatic" msgstr "Automático" -#: pkg/app/user.go:248 pkg/campsite/type.go:143 +#: pkg/app/user.go:249 pkg/campsite/types/admin.go:190 msgid "Name can not be empty." msgstr "No podéis dejar el nombre en blanco." -#: pkg/app/user.go:249 +#: pkg/app/user.go:250 msgid "Confirmation does not match password." msgstr "La confirmación no se corresponde con la contraseña." -#: pkg/app/user.go:250 +#: pkg/app/user.go:251 msgid "Selected language is not valid." msgstr "El idioma escogido no es válido." -#: pkg/app/user.go:252 +#: pkg/app/user.go:253 msgid "File must be a valid PNG or JPEG image." msgstr "El archivo tiene que ser una imagen PNG o JPEG válida." diff --git a/revert/edit_campsite_type.sql b/revert/edit_campsite_type.sql new file mode 100644 index 0000000..4aa8ab0 --- /dev/null +++ b/revert/edit_campsite_type.sql @@ -0,0 +1,7 @@ +-- Revert camper:edit_campsite_type from pg + +begin; + +drop function if exists camper.edit_campsite_type(uuid, text, text); + +commit; diff --git a/sqitch.plan b/sqitch.plan index 3ac9433..c932fb2 100644 --- a/sqitch.plan +++ b/sqitch.plan @@ -41,3 +41,4 @@ policies_company [company user_profile] 2023-08-07T20:04:26Z jordi fita mas # Add function to change the current user’s password campsite_type [roles schema_camper company user_profile] 2023-07-31T11:20:29Z jordi fita mas # Add relation of campsite type add_campsite_type [roles schema_camper campsite_type company] 2023-08-04T16:14:48Z jordi fita mas # Add function to create campsite types +edit_campsite_type [roles schema_camper campsite_type company] 2023-08-07T22:21:34Z jordi fita mas # Add function to edit campsite types diff --git a/test/edit_campsite_type.sql b/test/edit_campsite_type.sql new file mode 100644 index 0000000..7f7346a --- /dev/null +++ b/test/edit_campsite_type.sql @@ -0,0 +1,59 @@ +-- Test edit_campsite_type +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +set search_path to camper, public; + +select plan(12); + +select has_function('camper', 'edit_campsite_type', array ['uuid', 'text', 'text']); +select function_lang_is('camper', 'edit_campsite_type', array ['uuid', 'text', 'text'], 'sql'); +select function_returns('camper', 'edit_campsite_type', array ['uuid', 'text', 'text'], 'uuid'); +select isnt_definer('camper', 'edit_campsite_type', array ['uuid', 'text', 'text']); +select volatility_is('camper', 'edit_campsite_type', array ['uuid', 'text', 'text'], 'volatile'); +select function_privs_are('camper', 'edit_campsite_type', array ['uuid', 'text', 'text'], 'guest', array[]::text[]); +select function_privs_are('camper', 'edit_campsite_type', array ['uuid', 'text', 'text'], 'employee', array[]::text[]); +select function_privs_are('camper', 'edit_campsite_type', array ['uuid', 'text', 'text'], 'admin', array['EXECUTE']); +select function_privs_are('camper', 'edit_campsite_type', array ['uuid', 'text', 'text'], 'authenticator', array[]::text[]); + +set client_min_messages to warning; +truncate campsite_type cascade; +truncate company cascade; +reset client_min_messages; + + +insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_lang_tag) +values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 'ca') +; + +insert into campsite_type (company_id, slug, name, description) +values (1, '87452b88-b48f-48d3-bb6c-0296de64164e', 'Type A', '

A

') + , (1, '9b6370f7-f941-46f2-bc6e-de455675bd0a', 'Type B', '

B

') +; + +select lives_ok( + $$ select edit_campsite_type('87452b88-b48f-48d3-bb6c-0296de64164e', 'Type 1', '

1

') $$, + 'Should be ablo to edit the first type' +); + +select lives_ok( + $$ select edit_campsite_type('9b6370f7-f941-46f2-bc6e-de455675bd0a', 'Type 2', '

2

') $$, + 'Should be ablo to edit the second type' +); + +select bag_eq( + $$ select slug::text, name, description::text from campsite_type $$, + $$ values ('87452b88-b48f-48d3-bb6c-0296de64164e', 'Type 1', '

1

') + , ('9b6370f7-f941-46f2-bc6e-de455675bd0a', 'Type 2', '

2

') + $$, + 'Should have updated all campsite types.' +); + + +select * +from finish(); + +rollback; diff --git a/verify/edit_campsite_type.sql b/verify/edit_campsite_type.sql new file mode 100644 index 0000000..28d51c6 --- /dev/null +++ b/verify/edit_campsite_type.sql @@ -0,0 +1,7 @@ +-- Verify camper:edit_campsite_type on pg + +begin; + +select has_function_privilege('camper.edit_campsite_type(uuid, text, text)', 'execute'); + +rollback; diff --git a/web/templates/admin/campsite/type/index.gohtml b/web/templates/admin/campsite/type/index.gohtml index c703b53..15bea87 100644 --- a/web/templates/admin/campsite/type/index.gohtml +++ b/web/templates/admin/campsite/type/index.gohtml @@ -7,7 +7,7 @@ {{- end }} {{ define "content" -}} - {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite.typeIndex*/ -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.typeIndex*/ -}} {{( pgettext "Add Type" "action" )}}

{{( pgettext "Campsite Types" "title" )}}

{{ if .Types -}} @@ -20,7 +20,7 @@ {{ range .Types -}} - {{ .Name }} + {{ .Name }} {{- end }} diff --git a/web/templates/admin/campsite/type/new.gohtml b/web/templates/admin/campsite/type/new.gohtml index 68c67bd..2f2f34c 100644 --- a/web/templates/admin/campsite/type/new.gohtml +++ b/web/templates/admin/campsite/type/new.gohtml @@ -11,13 +11,30 @@ {{- end }} {{ define "title" -}} - {{( pgettext "New Campsite Type" "title" )}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.typeForm*/ -}} + {{ if .Slug}} + {{( pgettext "Edit Campsite Type" "title" )}} + {{ else }} + {{( pgettext "New Campsite Type" "title" )}} + {{ end }} {{- end }} {{ define "content" -}} - {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite.typeForm*/ -}} -
-

{{( pgettext "New Campsite Type" "title" )}}

+ {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.typeForm*/ -}} + +

+ {{ if .Slug }} + {{( pgettext "Edit Campsite Type" "title" )}} + {{ else }} + {{( pgettext "New Campsite Type" "title" )}} + {{ end }} +

{{ CSRFInput }}
{{ with .Name -}} @@ -37,7 +54,13 @@ {{- end }}
- +
{{- end }} diff --git a/web/templates/public/campsite/type.gohtml b/web/templates/public/campsite/type.gohtml new file mode 100644 index 0000000..7a0cbd8 --- /dev/null +++ b/web/templates/public/campsite/type.gohtml @@ -0,0 +1,14 @@ + +{{ define "title" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.publicPage*/ -}} + {{ .Name }} +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/campsite/types.publicPage*/ -}} +

{{ .Name }}

+ {{ .Description }} +{{- end }} diff --git a/web/templates/public/layout.gohtml b/web/templates/public/layout.gohtml index ec98d54..a263c31 100644 --- a/web/templates/public/layout.gohtml +++ b/web/templates/public/layout.gohtml @@ -29,6 +29,23 @@ {{- end }} + {{ with .Menu -}} + + {{- end }}
{{- template "content" . }}