From c9a6df658f64844faff9fcf6ad0fccdc9b3ab724 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Thu, 21 Dec 2023 17:33:01 +0100 Subject: [PATCH] Add position to campsite type features --- deploy/campsite_type_feature.sql | 3 +- deploy/order_campsite_type_features.sql | 24 +++++ pkg/campsite/types/feature.go | 43 ++++++++- pkg/campsite/types/public.go | 1 + pkg/database/funcs.go | 5 + po/ca.po | 63 ++++++------- po/es.po | 63 ++++++------- po/fr.po | 63 ++++++------- revert/order_campsite_type_features.sql | 7 ++ sqitch.plan | 1 + test/campsite_type_feature.sql | 8 +- test/order_campsite_type_features.sql | 91 +++++++++++++++++++ verify/campsite_type_feature.sql | 1 + verify/order_campsite_type_features.sql | 7 ++ .../admin/campsite/feature/index.gohtml | 58 +++++++----- 15 files changed, 318 insertions(+), 120 deletions(-) create mode 100644 deploy/order_campsite_type_features.sql create mode 100644 revert/order_campsite_type_features.sql create mode 100644 test/order_campsite_type_features.sql create mode 100644 verify/order_campsite_type_features.sql diff --git a/deploy/campsite_type_feature.sql b/deploy/campsite_type_feature.sql index b7c11f7..4ea5960 100644 --- a/deploy/campsite_type_feature.sql +++ b/deploy/campsite_type_feature.sql @@ -13,7 +13,8 @@ create table campsite_type_feature ( campsite_type_feature_id integer generated by default as identity primary key, campsite_type_id integer not null references campsite_type, icon_name text not null references icon, - name text not null constraint name_not_empty check(length(trim(name)) > 0) + name text not null constraint name_not_empty check(length(trim(name)) > 0), + position integer not null default 2147483647 ); grant select on campsite_type_feature to guest; diff --git a/deploy/order_campsite_type_features.sql b/deploy/order_campsite_type_features.sql new file mode 100644 index 0000000..4bb0d56 --- /dev/null +++ b/deploy/order_campsite_type_features.sql @@ -0,0 +1,24 @@ +-- Deploy camper:order_campsite_type_features to pg +-- requires: schema_camper +-- requires: roles +-- requires: campsite_type_feature + +begin; + +set search_path to camper, public; + +create or replace function order_campsite_type_features(positions integer[]) returns void as +$$ + update campsite_type_feature + set position = cast(temp.position as integer) + from unnest(positions) with ordinality as temp(feature_id, position) + where campsite_type_feature_id = temp.feature_id + ; +$$ + language sql +; + +revoke execute on function order_campsite_type_features(integer[]) from public; +grant execute on function order_campsite_type_features(integer[]) to admin; + +commit; diff --git a/pkg/campsite/types/feature.go b/pkg/campsite/types/feature.go index 2818e83..8be62a0 100644 --- a/pkg/campsite/types/feature.go +++ b/pkg/campsite/types/feature.go @@ -43,6 +43,13 @@ func (h *AdminHandler) featuresHandler(user *auth.User, company *auth.Company, c default: httplib.MethodNotAllowed(w, r, http.MethodGet) } + case "order": + switch r.Method { + case http.MethodPost: + orderFeatures(w, r, user, company, conn, typeSlug) + default: + httplib.MethodNotAllowed(w, r, http.MethodPost) + } default: id, err := strconv.Atoi(head) if err != nil { @@ -113,7 +120,8 @@ func serveFeatureIndex(w http.ResponseWriter, r *http.Request, user *auth.User, func collectFeatureEntries(ctx context.Context, conn *database.Conn, typeSlug string) ([]*featureEntry, error) { rows, err := conn.Query(ctx, ` - select '/admin/campsites/types/' || campsite_type.slug || '/features/' || campsite_type_feature_id + select campsite_type_feature_id + , '/admin/campsites/types/' || campsite_type.slug || '/features/' || campsite_type_feature_id , feature.icon_name , feature.name , array_agg((lang_tag, endonym, not exists (select 1 from campsite_type_feature_i18n as i18n where i18n.campsite_type_feature_id = feature.campsite_type_feature_id and i18n.lang_tag = language.lang_tag)) order by endonym) @@ -127,7 +135,8 @@ func collectFeatureEntries(ctx context.Context, conn *database.Conn, typeSlug st group by campsite_type_feature_id , campsite_type.slug , feature.name - order by name + , feature.position + order by feature.position, feature.name `, pgx.QueryResultFormats{pgx.BinaryFormatCode}, typeSlug) if err != nil { return nil, err @@ -138,7 +147,7 @@ func collectFeatureEntries(ctx context.Context, conn *database.Conn, typeSlug st for rows.Next() { feature := &featureEntry{} var translations database.RecordArray - if err = rows.Scan(&feature.URL, &feature.Icon, &feature.Name, &translations); err != nil { + if err = rows.Scan(&feature.ID, &feature.URL, &feature.Icon, &feature.Name, &translations); err != nil { return nil, err } for _, el := range translations.Elements { @@ -155,6 +164,7 @@ func collectFeatureEntries(ctx context.Context, conn *database.Conn, typeSlug st } type featureEntry struct { + ID int URL string Icon string Name string @@ -249,3 +259,30 @@ func (f *featureForm) Valid(l *locale.Locale) bool { func (f *featureForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { template.MustRenderAdmin(w, r, user, company, "campsite/feature/form.gohtml", f) } + +func orderFeatures(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, typeSlug string) { + if err := r.ParseForm(); 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 + } + input := r.PostForm["feature_id"] + if len(input) > 0 { + var ids []int + for _, s := range input { + if id, err := strconv.Atoi(s); err == nil { + ids = append(ids, id) + } else { + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + } + if err := conn.OrderCampsiteTypeFeatures(r.Context(), ids); err != nil { + panic(err) + } + } + serveFeatureIndex(w, r, user, company, conn, typeSlug) +} diff --git a/pkg/campsite/types/public.go b/pkg/campsite/types/public.go index 2f84bdd..f5c73e6 100644 --- a/pkg/campsite/types/public.go +++ b/pkg/campsite/types/public.go @@ -182,6 +182,7 @@ func collectFeatures(ctx context.Context, conn *database.Conn, language language join campsite_type using (campsite_type_id) left join campsite_type_feature_i18n as i18n on feature.campsite_type_feature_id = i18n.campsite_type_feature_id and i18n.lang_tag = $1 where campsite_type.slug = $2 + order by feature.position `, language, slug) if err != nil { return nil, err diff --git a/pkg/database/funcs.go b/pkg/database/funcs.go index d2ef2dd..da1788b 100644 --- a/pkg/database/funcs.go +++ b/pkg/database/funcs.go @@ -74,6 +74,11 @@ func (c *Conn) TranslateCampsiteTypeFeature(ctx context.Context, id int, langTag return err } +func (c *Conn) OrderCampsiteTypeFeatures(ctx context.Context, ids []int) error { + _, err := c.Exec(ctx, "select order_campsite_type_features($1)", ids) + return err +} + func (c *Conn) SetupRedsys(ctx context.Context, companyID int, merchantCode string, terminalNumber int, environment string, integration string, encryptKey string) error { var encryptKeyParam interface{} if encryptKey != "" { diff --git a/po/ca.po b/po/ca.po index e0c5faf..4fd22b7 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-12-20 19:48+0100\n" +"POT-Creation-Date: 2023-12-21 17:32+0100\n" "PO-Revision-Date: 2023-07-22 23:45+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -43,7 +43,7 @@ msgstr "Ha fallat el pagament" #: web/templates/public/services.gohtml:6 #: web/templates/public/services.gohtml:15 -#: web/templates/public/layout.gohtml:44 web/templates/public/layout.gohtml:71 +#: web/templates/public/layout.gohtml:52 web/templates/public/layout.gohtml:79 #: web/templates/admin/services/index.gohtml:66 msgctxt "title" msgid "Services" @@ -53,8 +53,8 @@ msgstr "Serveis" msgid "The campsite offers many different services." msgstr "El càmping disposa de diversos serveis." -#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:30 -#: web/templates/public/layout.gohtml:69 +#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:37 +#: web/templates/public/layout.gohtml:77 msgctxt "title" msgid "Home" msgstr "Inici" @@ -72,34 +72,34 @@ msgstr "Reserva" msgid "Our services" msgstr "Els nostres serveis" -#: web/templates/public/home.gohtml:34 +#: web/templates/public/home.gohtml:33 +msgid "Come and enjoy!" +msgstr "Vine a gaudir!" + +#: web/templates/public/home.gohtml:35 #: web/templates/public/surroundings.gohtml:6 #: web/templates/public/surroundings.gohtml:10 -#: web/templates/public/layout.gohtml:45 web/templates/public/layout.gohtml:72 +#: web/templates/public/layout.gohtml:53 web/templates/public/layout.gohtml:80 msgctxt "title" msgid "Surroundings" msgstr "L’entorn" -#: web/templates/public/home.gohtml:37 +#: web/templates/public/home.gohtml:38 msgid "Located in Alta Garrotxa, between the Pyrenees and the Costa Brava." msgstr "Situats a l’Alta Garrotxa, entre els Pirineus i la Costa Brava." -#: web/templates/public/home.gohtml:38 +#: web/templates/public/home.gohtml:39 msgid "Nearby there are the gorges of Sadernes, volcanoes, La Fageda d’en Jordà, the Jewish quarter of Besalú, the basaltic cliff of Castellfollit de la Roca… much to see and much to do." msgstr "A prop teniu els gorgs de Sadernes, volcans, La Fageda d’en Jordà, el call jueu de Besalú, la cinglera basàltica de Castellfollit de la Roca… molt per veure i molt per fer." -#: web/templates/public/home.gohtml:39 +#: web/templates/public/home.gohtml:40 msgid "Less than an hour from Girona, one from La Bisbal d’Empordà, and two from Barcelona." msgstr "A menys d’una hora de Girona, a una de La Bisbal d’Empordà i a dues de Barcelona." -#: web/templates/public/home.gohtml:40 +#: web/templates/public/home.gohtml:41 msgid "Discover the surroundings" msgstr "Descobreix l’entorn" -#: web/templates/public/home.gohtml:54 -msgid "Come and enjoy!" -msgstr "Vine a gaudir!" - #: web/templates/public/campsite/type.gohtml:41 msgctxt "input" msgid "Check-in Date" @@ -263,18 +263,19 @@ msgstr "Hi ha diversos punts on poder anar amb caiac, des de trams del riu Ter c #: web/templates/public/campground.gohtml:6 #: web/templates/public/campground.gohtml:11 -#: web/templates/public/layout.gohtml:31 web/templates/public/layout.gohtml:70 +#: web/templates/public/layout.gohtml:38 web/templates/public/layout.gohtml:78 msgctxt "title" msgid "Campground" msgstr "El càmping" #: web/templates/public/contact.gohtml:6 web/templates/public/contact.gohtml:18 -#: web/templates/public/layout.gohtml:46 web/templates/public/layout.gohtml:73 +#: web/templates/public/layout.gohtml:54 web/templates/public/layout.gohtml:81 msgctxt "title" msgid "Contact" msgstr "Contacte" #: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 +#: web/templates/public/layout.gohtml:51 msgctxt "title" msgid "Booking" msgstr "Reserva" @@ -362,8 +363,8 @@ msgctxt "input" msgid "I have read and I accept the reservation conditions" msgstr "He llegit i accepto les condicions de reserves" -#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:25 -#: web/templates/public/layout.gohtml:102 +#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:32 +#: web/templates/public/layout.gohtml:110 msgid "Campsite Montagut" msgstr "Càmping Montagut" @@ -371,7 +372,7 @@ msgstr "Càmping Montagut" msgid "Skip to main content" msgstr "Salta al contingut principal" -#: web/templates/public/layout.gohtml:35 web/templates/public/layout.gohtml:80 +#: web/templates/public/layout.gohtml:42 web/templates/public/layout.gohtml:88 #: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/layout.gohtml:44 web/templates/admin/layout.gohtml:75 @@ -379,12 +380,12 @@ msgctxt "title" msgid "Campsites" msgstr "Allotjaments" -#: web/templates/public/layout.gohtml:67 +#: web/templates/public/layout.gohtml:75 msgctxt "title" msgid "Sections" msgstr "Apartats" -#: web/templates/public/layout.gohtml:99 +#: web/templates/public/layout.gohtml:107 msgid "RTC #%s" msgstr "Núm. RTC %s" @@ -525,7 +526,7 @@ msgctxt "action" msgid "Add Feature" msgstr "Afegeix característica" -#: web/templates/admin/campsite/feature/index.gohtml:17 +#: web/templates/admin/campsite/feature/index.gohtml:26 #: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/season/index.gohtml:26 @@ -533,7 +534,7 @@ msgctxt "header" msgid "Name" msgstr "Nom" -#: web/templates/admin/campsite/feature/index.gohtml:18 +#: web/templates/admin/campsite/feature/index.gohtml:27 #: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/campsite/option/index.gohtml:26 #: web/templates/admin/campsite/type/index.gohtml:26 @@ -545,7 +546,7 @@ msgctxt "header" msgid "Translations" msgstr "Traduccions" -#: web/templates/admin/campsite/feature/index.gohtml:39 +#: web/templates/admin/campsite/feature/index.gohtml:53 msgid "No campsite type features added yet." msgstr "No s’ha afegit cap característica al tipus d’allotjament encara." @@ -1203,21 +1204,21 @@ msgctxt "title" msgid "Upload Media" msgstr "Pujada de mèdia" -#: pkg/carousel/admin.go:274 pkg/campsite/types/carousel.go:242 +#: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:242 msgctxt "input" msgid "Slide image" msgstr "Imatge de la diapositiva" -#: pkg/carousel/admin.go:275 pkg/campsite/types/carousel.go:243 +#: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:243 msgctxt "action" msgid "Set slide image" msgstr "Estableix la imatge de la diapositiva" -#: pkg/carousel/admin.go:327 pkg/campsite/types/carousel.go:297 +#: pkg/carousel/admin.go:338 pkg/campsite/types/carousel.go:297 msgid "Slide image can not be empty." msgstr "No podeu deixar la imatge de la diapositiva en blanc." -#: pkg/carousel/admin.go:328 pkg/campsite/types/carousel.go:298 +#: pkg/carousel/admin.go:339 pkg/campsite/types/carousel.go:298 msgid "Slide image must be an image media type." msgstr "La imatge de la diapositiva ha de ser un mèdia de tipus imatge." @@ -1246,7 +1247,7 @@ msgstr "Automàtic" #: pkg/app/user.go:249 pkg/campsite/types/l10n.go:87 #: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 -#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:243 +#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:253 #: pkg/campsite/types/admin.go:447 pkg/season/l10n.go:69 #: pkg/season/admin.go:404 pkg/services/l10n.go:73 pkg/services/admin.go:266 msgid "Name can not be empty." @@ -1268,7 +1269,7 @@ msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida." msgid "Access forbidden" msgstr "Accés prohibit" -#: pkg/campsite/types/option.go:351 pkg/campsite/types/feature.go:244 +#: pkg/campsite/types/option.go:351 pkg/campsite/types/feature.go:254 #: pkg/campsite/types/admin.go:448 msgid "Name must have at least one letter." msgstr "El nom ha de tenir com a mínim una lletra." @@ -1309,7 +1310,7 @@ msgstr "El preu per nit ha de ser un número decimal." msgid "Price per night must be zero or greater." msgstr "El preu per nit ha de ser com a mínim zero." -#: pkg/campsite/types/feature.go:242 pkg/services/admin.go:265 +#: pkg/campsite/types/feature.go:252 pkg/services/admin.go:265 msgid "Selected icon is not valid." msgstr "La icona escollida no és vàlida." diff --git a/po/es.po b/po/es.po index 7bafbf7..a01d616 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-12-20 19:48+0100\n" +"POT-Creation-Date: 2023-12-21 17:32+0100\n" "PO-Revision-Date: 2023-07-22 23:46+0200\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -43,7 +43,7 @@ msgstr "Pago fallido" #: web/templates/public/services.gohtml:6 #: web/templates/public/services.gohtml:15 -#: web/templates/public/layout.gohtml:44 web/templates/public/layout.gohtml:71 +#: web/templates/public/layout.gohtml:52 web/templates/public/layout.gohtml:79 #: web/templates/admin/services/index.gohtml:66 msgctxt "title" msgid "Services" @@ -53,8 +53,8 @@ msgstr "Servicios" msgid "The campsite offers many different services." msgstr "El camping dispone de varios servicios." -#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:30 -#: web/templates/public/layout.gohtml:69 +#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:37 +#: web/templates/public/layout.gohtml:77 msgctxt "title" msgid "Home" msgstr "Inicio" @@ -72,34 +72,34 @@ msgstr "Reservar" msgid "Our services" msgstr "Nuestros servicios" -#: web/templates/public/home.gohtml:34 +#: web/templates/public/home.gohtml:33 +msgid "Come and enjoy!" +msgstr "¡Ven a disfrutar!" + +#: web/templates/public/home.gohtml:35 #: web/templates/public/surroundings.gohtml:6 #: web/templates/public/surroundings.gohtml:10 -#: web/templates/public/layout.gohtml:45 web/templates/public/layout.gohtml:72 +#: web/templates/public/layout.gohtml:53 web/templates/public/layout.gohtml:80 msgctxt "title" msgid "Surroundings" msgstr "El entorno" -#: web/templates/public/home.gohtml:37 +#: web/templates/public/home.gohtml:38 msgid "Located in Alta Garrotxa, between the Pyrenees and the Costa Brava." msgstr "Situados en la Alta Garrotxa, entre los Pirineos y la Costa Brava." -#: web/templates/public/home.gohtml:38 +#: web/templates/public/home.gohtml:39 msgid "Nearby there are the gorges of Sadernes, volcanoes, La Fageda d’en Jordà, the Jewish quarter of Besalú, the basaltic cliff of Castellfollit de la Roca… much to see and much to do." msgstr "Cerca tenéis los piletones de Sadernes, volcanes, La Fageda d’en Jordà, la judería de Besalú, el riscal basáltico de Castellfollit de la Roca… mucho por ver y mucho por hacer." -#: web/templates/public/home.gohtml:39 +#: web/templates/public/home.gohtml:40 msgid "Less than an hour from Girona, one from La Bisbal d’Empordà, and two from Barcelona." msgstr "A menos de una hora de Girona, a una de La Bisbal d’Empordà y a dos de Barcelona." -#: web/templates/public/home.gohtml:40 +#: web/templates/public/home.gohtml:41 msgid "Discover the surroundings" msgstr "Descubre el entorno" -#: web/templates/public/home.gohtml:54 -msgid "Come and enjoy!" -msgstr "¡Ven a disfrutar!" - #: web/templates/public/campsite/type.gohtml:41 msgctxt "input" msgid "Check-in Date" @@ -263,18 +263,19 @@ msgstr "Hay diversos puntos dónde podéis ir en kayak, desde tramos del río Te #: web/templates/public/campground.gohtml:6 #: web/templates/public/campground.gohtml:11 -#: web/templates/public/layout.gohtml:31 web/templates/public/layout.gohtml:70 +#: web/templates/public/layout.gohtml:38 web/templates/public/layout.gohtml:78 msgctxt "title" msgid "Campground" msgstr "El camping" #: web/templates/public/contact.gohtml:6 web/templates/public/contact.gohtml:18 -#: web/templates/public/layout.gohtml:46 web/templates/public/layout.gohtml:73 +#: web/templates/public/layout.gohtml:54 web/templates/public/layout.gohtml:81 msgctxt "title" msgid "Contact" msgstr "Contacto" #: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 +#: web/templates/public/layout.gohtml:51 msgctxt "title" msgid "Booking" msgstr "Reserva" @@ -362,8 +363,8 @@ msgctxt "input" msgid "I have read and I accept the reservation conditions" msgstr "He leído y acepto las condiciones de reserva" -#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:25 -#: web/templates/public/layout.gohtml:102 +#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:32 +#: web/templates/public/layout.gohtml:110 msgid "Campsite Montagut" msgstr "Camping Montagut" @@ -371,7 +372,7 @@ msgstr "Camping Montagut" msgid "Skip to main content" msgstr "Saltar al contenido principal" -#: web/templates/public/layout.gohtml:35 web/templates/public/layout.gohtml:80 +#: web/templates/public/layout.gohtml:42 web/templates/public/layout.gohtml:88 #: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/layout.gohtml:44 web/templates/admin/layout.gohtml:75 @@ -379,12 +380,12 @@ msgctxt "title" msgid "Campsites" msgstr "Alojamientos" -#: web/templates/public/layout.gohtml:67 +#: web/templates/public/layout.gohtml:75 msgctxt "title" msgid "Sections" msgstr "Apartados" -#: web/templates/public/layout.gohtml:99 +#: web/templates/public/layout.gohtml:107 msgid "RTC #%s" msgstr " RTC %s" @@ -525,7 +526,7 @@ msgctxt "action" msgid "Add Feature" msgstr "Añadir características" -#: web/templates/admin/campsite/feature/index.gohtml:17 +#: web/templates/admin/campsite/feature/index.gohtml:26 #: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/season/index.gohtml:26 @@ -533,7 +534,7 @@ msgctxt "header" msgid "Name" msgstr "Nombre" -#: web/templates/admin/campsite/feature/index.gohtml:18 +#: web/templates/admin/campsite/feature/index.gohtml:27 #: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/campsite/option/index.gohtml:26 #: web/templates/admin/campsite/type/index.gohtml:26 @@ -545,7 +546,7 @@ msgctxt "header" msgid "Translations" msgstr "Traducciones" -#: web/templates/admin/campsite/feature/index.gohtml:39 +#: web/templates/admin/campsite/feature/index.gohtml:53 msgid "No campsite type features added yet." msgstr "No se ha añadido ninguna característica al tipo de alojamiento todavía." @@ -1203,21 +1204,21 @@ msgctxt "title" msgid "Upload Media" msgstr "Subida de medio" -#: pkg/carousel/admin.go:274 pkg/campsite/types/carousel.go:242 +#: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:242 msgctxt "input" msgid "Slide image" msgstr "Imagen de la diapositiva" -#: pkg/carousel/admin.go:275 pkg/campsite/types/carousel.go:243 +#: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:243 msgctxt "action" msgid "Set slide image" msgstr "Establecer la imagen de la diapositiva" -#: pkg/carousel/admin.go:327 pkg/campsite/types/carousel.go:297 +#: pkg/carousel/admin.go:338 pkg/campsite/types/carousel.go:297 msgid "Slide image can not be empty." msgstr "No podéis dejar la imagen de la diapositiva en blanco." -#: pkg/carousel/admin.go:328 pkg/campsite/types/carousel.go:298 +#: pkg/carousel/admin.go:339 pkg/campsite/types/carousel.go:298 msgid "Slide image must be an image media type." msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen." @@ -1246,7 +1247,7 @@ msgstr "Automático" #: pkg/app/user.go:249 pkg/campsite/types/l10n.go:87 #: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 -#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:243 +#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:253 #: pkg/campsite/types/admin.go:447 pkg/season/l10n.go:69 #: pkg/season/admin.go:404 pkg/services/l10n.go:73 pkg/services/admin.go:266 msgid "Name can not be empty." @@ -1268,7 +1269,7 @@ msgstr "El archivo tiene que ser una imagen PNG o JPEG válida." msgid "Access forbidden" msgstr "Acceso prohibido" -#: pkg/campsite/types/option.go:351 pkg/campsite/types/feature.go:244 +#: pkg/campsite/types/option.go:351 pkg/campsite/types/feature.go:254 #: pkg/campsite/types/admin.go:448 msgid "Name must have at least one letter." msgstr "El nombre tiene que tener como mínimo una letra." @@ -1309,7 +1310,7 @@ msgstr "El precio por noche tien que ser un número decimal." msgid "Price per night must be zero or greater." msgstr "El precio por noche tiene que ser como mínimo cero." -#: pkg/campsite/types/feature.go:242 pkg/services/admin.go:265 +#: pkg/campsite/types/feature.go:252 pkg/services/admin.go:265 msgid "Selected icon is not valid." msgstr "El icono escogido no es válido." diff --git a/po/fr.po b/po/fr.po index 9b594bd..38c4018 100644 --- a/po/fr.po +++ b/po/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: camper\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2023-12-20 19:48+0100\n" +"POT-Creation-Date: 2023-12-21 17:32+0100\n" "PO-Revision-Date: 2023-12-20 10:13+0100\n" "Last-Translator: Oriol Carbonell \n" "Language-Team: French \n" @@ -44,7 +44,7 @@ msgstr "Le paiement a échoué" #: web/templates/public/services.gohtml:6 #: web/templates/public/services.gohtml:15 -#: web/templates/public/layout.gohtml:44 web/templates/public/layout.gohtml:71 +#: web/templates/public/layout.gohtml:52 web/templates/public/layout.gohtml:79 #: web/templates/admin/services/index.gohtml:66 msgctxt "title" msgid "Services" @@ -54,8 +54,8 @@ msgstr "Services" msgid "The campsite offers many different services." msgstr "Le camping propose de nombreux services différents." -#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:30 -#: web/templates/public/layout.gohtml:69 +#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:37 +#: web/templates/public/layout.gohtml:77 msgctxt "title" msgid "Home" msgstr "Accueil" @@ -73,34 +73,34 @@ msgstr "Réservation" msgid "Our services" msgstr "Nos services" -#: web/templates/public/home.gohtml:34 +#: web/templates/public/home.gohtml:33 +msgid "Come and enjoy!" +msgstr "Venez et profitez-en !" + +#: web/templates/public/home.gohtml:35 #: web/templates/public/surroundings.gohtml:6 #: web/templates/public/surroundings.gohtml:10 -#: web/templates/public/layout.gohtml:45 web/templates/public/layout.gohtml:72 +#: web/templates/public/layout.gohtml:53 web/templates/public/layout.gohtml:80 msgctxt "title" msgid "Surroundings" msgstr "Entourage" -#: web/templates/public/home.gohtml:37 +#: web/templates/public/home.gohtml:38 msgid "Located in Alta Garrotxa, between the Pyrenees and the Costa Brava." msgstr "Situé dans l’Alta Garrotxa, entre les Pyrénées et la Costa Brava." -#: web/templates/public/home.gohtml:38 +#: web/templates/public/home.gohtml:39 msgid "Nearby there are the gorges of Sadernes, volcanoes, La Fageda d’en Jordà, the Jewish quarter of Besalú, the basaltic cliff of Castellfollit de la Roca… much to see and much to do." msgstr "A proximité il y a les gorges de Sadernes, les volcans, La Fageda dâen Jordã , le quartier juif de Besalú, la falaise basaltique de Castellfollit de la Roca… beaucoup à voir et beaucoup à faire." -#: web/templates/public/home.gohtml:39 +#: web/templates/public/home.gohtml:40 msgid "Less than an hour from Girona, one from La Bisbal d’Empordà, and two from Barcelona." msgstr "À moins d’une heure de Gérone, un de La Bisbal d’Empordàet deux de Barcelone." -#: web/templates/public/home.gohtml:40 +#: web/templates/public/home.gohtml:41 msgid "Discover the surroundings" msgstr "Découvrir les environs" -#: web/templates/public/home.gohtml:54 -msgid "Come and enjoy!" -msgstr "Venez et profitez-en !" - #: web/templates/public/campsite/type.gohtml:41 msgctxt "input" msgid "Check-in Date" @@ -264,18 +264,19 @@ msgstr "Il y a plusieurs points où vous pouvez aller en kayak, à partir de sec #: web/templates/public/campground.gohtml:6 #: web/templates/public/campground.gohtml:11 -#: web/templates/public/layout.gohtml:31 web/templates/public/layout.gohtml:70 +#: web/templates/public/layout.gohtml:38 web/templates/public/layout.gohtml:78 msgctxt "title" msgid "Campground" msgstr "Camping" #: web/templates/public/contact.gohtml:6 web/templates/public/contact.gohtml:18 -#: web/templates/public/layout.gohtml:46 web/templates/public/layout.gohtml:73 +#: web/templates/public/layout.gohtml:54 web/templates/public/layout.gohtml:81 msgctxt "title" msgid "Contact" msgstr "Contact" #: web/templates/public/booking.gohtml:6 web/templates/public/booking.gohtml:11 +#: web/templates/public/layout.gohtml:51 msgctxt "title" msgid "Booking" msgstr "Reservation" @@ -363,8 +364,8 @@ msgctxt "input" msgid "I have read and I accept the reservation conditions" msgstr "J’ai lu et j’accepte les conditions de réservation" -#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:25 -#: web/templates/public/layout.gohtml:102 +#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:32 +#: web/templates/public/layout.gohtml:110 msgid "Campsite Montagut" msgstr "Camping Montagut" @@ -372,7 +373,7 @@ msgstr "Camping Montagut" msgid "Skip to main content" msgstr "Passer au contenu principal" -#: web/templates/public/layout.gohtml:35 web/templates/public/layout.gohtml:80 +#: web/templates/public/layout.gohtml:42 web/templates/public/layout.gohtml:88 #: web/templates/admin/campsite/index.gohtml:6 #: web/templates/admin/campsite/index.gohtml:12 #: web/templates/admin/layout.gohtml:44 web/templates/admin/layout.gohtml:75 @@ -380,12 +381,12 @@ msgctxt "title" msgid "Campsites" msgstr "Locatifs" -#: web/templates/public/layout.gohtml:67 +#: web/templates/public/layout.gohtml:75 msgctxt "title" msgid "Sections" msgstr "Sections" -#: web/templates/public/layout.gohtml:99 +#: web/templates/public/layout.gohtml:107 msgid "RTC #%s" msgstr "# RTC %s" @@ -526,7 +527,7 @@ msgctxt "action" msgid "Add Feature" msgstr "Ajouter une fonctionnalité" -#: web/templates/admin/campsite/feature/index.gohtml:17 +#: web/templates/admin/campsite/feature/index.gohtml:26 #: web/templates/admin/campsite/option/index.gohtml:25 #: web/templates/admin/campsite/type/index.gohtml:25 #: web/templates/admin/season/index.gohtml:26 @@ -534,7 +535,7 @@ msgctxt "header" msgid "Name" msgstr "Nom" -#: web/templates/admin/campsite/feature/index.gohtml:18 +#: web/templates/admin/campsite/feature/index.gohtml:27 #: web/templates/admin/campsite/carousel/index.gohtml:27 #: web/templates/admin/campsite/option/index.gohtml:26 #: web/templates/admin/campsite/type/index.gohtml:26 @@ -546,7 +547,7 @@ msgctxt "header" msgid "Translations" msgstr "Traductions" -#: web/templates/admin/campsite/feature/index.gohtml:39 +#: web/templates/admin/campsite/feature/index.gohtml:53 msgid "No campsite type features added yet." msgstr "Aucune fonctionnalité de type camping n’a encore été ajoutée." @@ -1204,21 +1205,21 @@ msgctxt "title" msgid "Upload Media" msgstr "Envoyer un fichier" -#: pkg/carousel/admin.go:274 pkg/campsite/types/carousel.go:242 +#: pkg/carousel/admin.go:285 pkg/campsite/types/carousel.go:242 msgctxt "input" msgid "Slide image" msgstr "Image du diaporama" -#: pkg/carousel/admin.go:275 pkg/campsite/types/carousel.go:243 +#: pkg/carousel/admin.go:286 pkg/campsite/types/carousel.go:243 msgctxt "action" msgid "Set slide image" msgstr "Définir l’image de la diapositive" -#: pkg/carousel/admin.go:327 pkg/campsite/types/carousel.go:297 +#: pkg/carousel/admin.go:338 pkg/campsite/types/carousel.go:297 msgid "Slide image can not be empty." msgstr "L’image de la diapositive ne peut pas être vide." -#: pkg/carousel/admin.go:328 pkg/campsite/types/carousel.go:298 +#: pkg/carousel/admin.go:339 pkg/campsite/types/carousel.go:298 msgid "Slide image must be an image media type." msgstr "L’image de la diapositive doit être de type média d’image." @@ -1247,7 +1248,7 @@ msgstr "Automatique" #: pkg/app/user.go:249 pkg/campsite/types/l10n.go:87 #: pkg/campsite/types/l10n.go:144 pkg/campsite/types/l10n.go:268 -#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:243 +#: pkg/campsite/types/option.go:350 pkg/campsite/types/feature.go:253 #: pkg/campsite/types/admin.go:447 pkg/season/l10n.go:69 #: pkg/season/admin.go:404 pkg/services/l10n.go:73 pkg/services/admin.go:266 msgid "Name can not be empty." @@ -1269,7 +1270,7 @@ msgstr "Le fichier doit être une image PNG ou JPEG valide." msgid "Access forbidden" msgstr "Accès interdit" -#: pkg/campsite/types/option.go:351 pkg/campsite/types/feature.go:244 +#: pkg/campsite/types/option.go:351 pkg/campsite/types/feature.go:254 #: pkg/campsite/types/admin.go:448 msgid "Name must have at least one letter." msgstr "Le nom doit comporter au moins une lettre." @@ -1310,7 +1311,7 @@ msgstr "Le prix par nuit doit être un nombre décimal." msgid "Price per night must be zero or greater." msgstr "Le prix par nuit doit être égal ou supérieur." -#: pkg/campsite/types/feature.go:242 pkg/services/admin.go:265 +#: pkg/campsite/types/feature.go:252 pkg/services/admin.go:265 msgid "Selected icon is not valid." msgstr "L’icône sélectionnée n’est pas valide." diff --git a/revert/order_campsite_type_features.sql b/revert/order_campsite_type_features.sql new file mode 100644 index 0000000..48a5c05 --- /dev/null +++ b/revert/order_campsite_type_features.sql @@ -0,0 +1,7 @@ +-- Revert camper:order_campsite_type_features from pg + +begin; + +drop function if exists camper.order_campsite_type_features(integer[]); + +commit; diff --git a/sqitch.plan b/sqitch.plan index aa6b070..49e8b19 100644 --- a/sqitch.plan +++ b/sqitch.plan @@ -125,3 +125,4 @@ order_campsite_type_options [schema_camper roles campsite_type_option] 2023-12-2 order_campsite_type_carousel [schema_camper roles campsite_type campsite_type_carousel] 2023-12-20T17:59:54Z jordi fita mas # Add function to order campsite type carousel order_home_carousel [schema_camper roles home_carousel] 2023-12-20T18:30:12Z jordi fita mas # Add function to order home carousel order_services_carousel [schema_camper roles services_carousel] 2023-12-20T18:39:18Z jordi fita mas # Add function to order services carousel +order_campsite_type_features [schema_camper roles campsite_type_feature] 2023-12-21T16:13:14Z jordi fita mas # Add function to order campsite type features diff --git a/test/campsite_type_feature.sql b/test/campsite_type_feature.sql index e560d0d..a9735c3 100644 --- a/test/campsite_type_feature.sql +++ b/test/campsite_type_feature.sql @@ -5,7 +5,7 @@ reset client_min_messages; begin; -select plan(41); +select plan(46); set search_path to camper, public; @@ -41,6 +41,12 @@ select col_type_is('campsite_type_feature', 'name', 'text'); select col_not_null('campsite_type_feature', 'name'); select col_hasnt_default('campsite_type_feature', 'name'); +select has_column('campsite_type_feature', 'position'); +select col_type_is('campsite_type_feature', 'position', 'integer'); +select col_not_null('campsite_type_feature', 'position'); +select col_has_default('campsite_type_feature', 'position'); +select col_default_is('campsite_type_feature', 'position', '2147483647'); + set client_min_messages to warning; truncate campsite_type_feature cascade; diff --git a/test/order_campsite_type_features.sql b/test/order_campsite_type_features.sql new file mode 100644 index 0000000..352dfce --- /dev/null +++ b/test/order_campsite_type_features.sql @@ -0,0 +1,91 @@ +-- Test order_campsite_type_features +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(11); + +set search_path to camper, public; + +select has_function('camper', 'order_campsite_type_features', array['integer[]']); +select function_lang_is('camper', 'order_campsite_type_features', array['integer[]'], 'sql'); +select function_returns('camper', 'order_campsite_type_features', array['integer[]'], 'void'); +select isnt_definer('camper', 'order_campsite_type_features', array['integer[]']); +select volatility_is('camper', 'order_campsite_type_features', array['integer[]'], 'volatile'); +select function_privs_are('camper', 'order_campsite_type_features', array ['integer[]'], 'guest', array[]::text[]); +select function_privs_are('camper', 'order_campsite_type_features', array ['integer[]'], 'employee', array[]::text[]); +select function_privs_are('camper', 'order_campsite_type_features', array ['integer[]'], 'admin', array['EXECUTE']); +select function_privs_are('camper', 'order_campsite_type_features', array ['integer[]'], 'authenticator', array[]::text[]); + + +set client_min_messages to warning; +truncate campsite_type_feature cascade; +truncate campsite_type cascade; +truncate media cascade; +truncate media_content cascade; +truncate company_host cascade; +truncate company_user cascade; +truncate company cascade; +truncate auth."user" cascade; +reset client_min_messages; + +insert into auth."user" (user_id, email, name, password, cookie, cookie_expires_at) +values (1, 'demo@tandem.blog', 'Demo', 'test', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month') + , (5, 'admin@tandem.blog', 'Demo', 'test', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month') +; + +insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, rtc_number, country_code, currency_code, default_lang_tag) +values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 'ES', 'EUR', 'ca') +; + +insert into company_user (company_id, user_id, role) +values (2, 1, 'admin') +; + +insert into company_host (company_id, host) +values (2, 'co2') +; + +insert into media_content (media_type, bytes) +values ('image/x-xpixmap', 'static char *s[]={"1 1 1 1","a c #ffffff","a"};') +; + +insert into media (media_id, company_id, original_filename, content_hash) +values (6, 2, 'cover2.xpm', sha256('static char *s[]={"1 1 1 1","a c #ffffff","a"};')) +; + +insert into campsite_type (campsite_type_id, company_id, name, media_id, dogs_allowed, max_campers) +values (16, 2, 'Wooden lodge', 6, false, 7) +; + +insert into campsite_type_feature (campsite_type_feature_id, campsite_type_id, icon_name, name) +values (21, 16, 'information', '1') + , (22, 16, 'ball', '2') + , (23, 16, 'bicycle', '3') + , (24, 16, 'campfire', '4') + , (25, 16, 'castle', '5') +; + + +select lives_ok( + $$ select order_campsite_type_features('{23,25,24,21,22}') $$, + 'Should be able to sort campsite type features using their ID' +); + +select bag_eq( + $$ select campsite_type_feature_id, position from campsite_type_feature $$, + $$ values (23, 1) + , (25, 2) + , (24, 3) + , (21, 4) + , (22, 5) + $$, + 'Should have sorted all campsite type features.' +); + +select * +from finish(); + +rollback; diff --git a/verify/campsite_type_feature.sql b/verify/campsite_type_feature.sql index 5f4418d..e644846 100644 --- a/verify/campsite_type_feature.sql +++ b/verify/campsite_type_feature.sql @@ -6,6 +6,7 @@ select campsite_type_feature_id , campsite_type_id , icon_name , name + , position from camper.campsite_type_feature where false; diff --git a/verify/order_campsite_type_features.sql b/verify/order_campsite_type_features.sql new file mode 100644 index 0000000..ef27145 --- /dev/null +++ b/verify/order_campsite_type_features.sql @@ -0,0 +1,7 @@ +-- Verify camper:order_campsite_type_features on pg + +begin; + +select has_function_privilege('camper.order_campsite_type_features(integer[])', 'execute'); + +rollback; diff --git a/web/templates/admin/campsite/feature/index.gohtml b/web/templates/admin/campsite/feature/index.gohtml index ab61948..69ea988 100644 --- a/web/templates/admin/campsite/feature/index.gohtml +++ b/web/templates/admin/campsite/feature/index.gohtml @@ -11,30 +11,44 @@ {{( pgettext "Add Feature" "action" )}}

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

{{ if .Features -}} - - - - - - - - - {{ range .Features -}} + + {{ CSRFInput }} +
{{( pgettext "Name" "header" )}}{{( pgettext "Translations" "header" )}}
+ - - + + + - {{- end }} - -
{{ .Name }} - {{ range .Translations }} - {{ .Endonym }} - {{ end }} - {{( pgettext "Name" "header" )}}{{( pgettext "Translations" "header" )}}
+ + + {{ range .Features -}} + + + + + + {{ .Name }} + + {{ range .Translations }} + {{ .Endonym }} + {{ end }} + + + {{- end }} + + + {{ else -}}

{{( gettext "No campsite type features added yet." )}}

{{- end }}