Add position to campsite type features

This commit is contained in:
jordi fita mas 2023-12-21 17:33:01 +01:00
parent 8d3dd589aa
commit c9a6df658f
15 changed files with 318 additions and 120 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)
}

View File

@ -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

View File

@ -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 != "" {

View File

@ -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 <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\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 "Lentorn"
#: web/templates/public/home.gohtml:37
#: web/templates/public/home.gohtml:38
msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situats a l<strong>Alta Garrotxa</strong>, entre els <strong>Pirineus</strong> i la <strong>Costa Brava</strong>."
#: web/templates/public/home.gohtml:38
#: web/templates/public/home.gohtml:39
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
msgstr "A prop teniu els <strong>gorgs de Sadernes</strong>, <strong>volcans</strong>, <strong>La Fageda den Jordà</strong>, el call jueu de <strong>Besalú</strong>, la cinglera basàltica de <strong>Castellfollit de la Roca</strong>… 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 <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "A menys duna hora de <strong>Girona</strong>, a una de <strong>La Bisbal dEmpordà</strong> i a dues de <strong>Barcelona</strong>."
#: web/templates/public/home.gohtml:40
#: web/templates/public/home.gohtml:41
msgid "Discover the surroundings"
msgstr "Descobreix lentorn"
#: 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 "<abbr title=\"Catalonia Tourism Registry\">RTC</abbr> <abbr title=\"Number\">#</abbr>%s"
msgstr "<abbr title=\"Número\">Núm.</abbr> <abbr title=\"Registre de Turisme de Catalunya\">RTC</abbr> %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 sha afegit cap característica al tipus dallotjament 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."

View File

@ -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 <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\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 <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situados en la <strong>Alta Garrotxa</strong>, entre los <strong>Pirineos</strong> y la <strong>Costa Brava</strong>."
#: web/templates/public/home.gohtml:38
#: web/templates/public/home.gohtml:39
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
msgstr "Cerca tenéis los <strong>piletones de Sadernes</strong>, <strong>volcanes</strong>, <strong>La Fageda den Jordà</strong>, la judería de <strong>Besalú</strong>, el riscal basáltico de <strong>Castellfollit de la Roca</strong>… 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 <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "A menos de una hora de <strong>Girona</strong>, a una de <strong>La Bisbal dEmpordà</strong> y a dos de <strong>Barcelona</strong>."
#: 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 "<abbr title=\"Catalonia Tourism Registry\">RTC</abbr> <abbr title=\"Number\">#</abbr>%s"
msgstr "<abbr title=\"Número\">Nº</abbr> <abbr title=\"Registro de Turismo de Cataluña\">RTC</abbr> %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."

View File

@ -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 <info@oriolcarbonell.cat>\n"
"Language-Team: French <traduc@traduc.org>\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 <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situé dans <strong>lAlta Garrotxa</strong>, entre les <strong>Pyrénées</strong> et la <strong>Costa Brava</strong>."
#: web/templates/public/home.gohtml:38
#: web/templates/public/home.gohtml:39
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda den Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
msgstr "A proximité il y a les <strong>gorges de Sadernes</strong>, les <strong>volcans</strong>, <strong>La Fageda dâen Jordã </strong>, le quartier juif de <strong>Besalú</strong>, la falaise basaltique de <strong>Castellfollit de la Roca</strong>… beaucoup à voir et beaucoup à faire."
#: web/templates/public/home.gohtml:39
#: web/templates/public/home.gohtml:40
msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal dEmpordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "À moins dune heure de <strong>Gérone</strong>, un de <strong>La Bisbal dEmpordà</strong>et deux de <strong>Barcelone</strong>."
#: 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 "Jai lu et jaccepte 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 "<abbr title=\"Catalonia Tourism Registry\">RTC</abbr> <abbr title=\"Number\">#</abbr>%s"
msgstr "<abbr title=\"Registre du tourisme de Catalogne\"># RTC</abbr> %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 na 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 limage 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 "Limage 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 "Limage de la diapositive doit être de type média dimage."
@ -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 "Licône sélectionnée nest pas valide."

View File

@ -0,0 +1,7 @@
-- Revert camper:order_campsite_type_features from pg
begin;
drop function if exists camper.order_campsite_type_features(integer[]);
commit;

View File

@ -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 <jordi@tandem.blog> # Add function to order campsite type carousel
order_home_carousel [schema_camper roles home_carousel] 2023-12-20T18:30:12Z jordi fita mas <jordi@tandem.blog> # Add function to order home carousel
order_services_carousel [schema_camper roles services_carousel] 2023-12-20T18:39:18Z jordi fita mas <jordi@tandem.blog> # Add function to order services carousel
order_campsite_type_features [schema_camper roles campsite_type_feature] 2023-12-21T16:13:14Z jordi fita mas <jordi@tandem.blog> # Add function to order campsite type features

View File

@ -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;

View File

@ -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;

View File

@ -6,6 +6,7 @@ select campsite_type_feature_id
, campsite_type_id
, icon_name
, name
, position
from camper.campsite_type_feature
where false;

View File

@ -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;

View File

@ -11,30 +11,44 @@
<a href="/admin/campsites/types/{{ .TypeSlug }}/features/new">{{( pgettext "Add Feature" "action" )}}</a>
<h2>{{( pgettext "Campsite Type Features" "title" )}}</h2>
{{ if .Features -}}
<table class="services">
<thead>
<tr>
<th scope="col">{{( pgettext "Name" "header" )}}</th>
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
</tr>
</thead>
<tbody>
{{ range .Features -}}
<form id="feature-index"
class="sortable"
data-hx-post="/admin/campsites/types/{{ .TypeSlug }}/features/order"
data-hx-trigger="end"
data-hx-select="#feature-index"
data-hx-swap="outerHTML"
>
{{ CSRFInput }}
<table class="services">
<thead>
<tr>
<td class="icon_{{ .Icon }}"><a href="{{ .URL }}">{{ .Name }}</a></td>
<td>
{{ range .Translations }}
<a
{{ if .Missing }}
class="missing-translation"
{{ end }}
href="{{ .URL }}">{{ .Endonym }}</a>
{{ end }}
</td>
<th scope="col" style="width: 1.5em"></th>
<th scope="col">{{( pgettext "Name" "header" )}}</th>
<th scope="col">{{( pgettext "Translations" "header" )}}</th>
</tr>
{{- end }}
</tbody>
</table>
</thead>
<tbody>
{{ range .Features -}}
<tr>
<td>
<span class="handle"></span>
<input type="hidden" name="feature_id" value="{{ .ID }}">
</td>
<td class="icon_{{ .Icon }}"><a href="{{ .URL }}">{{ .Name }}</a></td>
<td>
{{ range .Translations }}
<a
{{ if .Missing }}
class="missing-translation"
{{ end }}
href="{{ .URL }}">{{ .Endonym }}</a>
{{ end }}
</td>
</tr>
{{- end }}
</tbody>
</table>
</form>
{{ else -}}
<p>{{( gettext "No campsite type features added yet." )}}</p>
{{- end }}