diff --git a/demo/demo.sql b/demo/demo.sql index 12c4624..2f702f6 100644 --- a/demo/demo.sql +++ b/demo/demo.sql @@ -18,10 +18,6 @@ values (52, 'localhost:8080') , (52, 'camper.tandem.ws') ; -insert into company_geography (company_id, geog) -values (52, 'SRID=4326;POINT(2.598825853208973 42.24256146290889)') -; - insert into company_user (company_id, user_id, role) values (52, 42, 'employee') , (52, 43, 'admin') diff --git a/deploy/extension_postgis.sql b/deploy/extension_postgis.sql deleted file mode 100644 index e6e3d95..0000000 --- a/deploy/extension_postgis.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Deploy camper:extension_postgis to pg --- requires: schema_public - -begin; - -create extension if not exists postgis; - -commit; diff --git a/deploy/company_geography.sql b/deploy/location.sql similarity index 54% rename from deploy/company_geography.sql rename to deploy/location.sql index 86b9a56..c513677 100644 --- a/deploy/company_geography.sql +++ b/deploy/location.sql @@ -1,33 +1,33 @@ --- Deploy camper:company_geography to pg --- requires: roles +-- Deploy camper:location to pg -- requires: schema_camper +-- requires: roles -- requires: company --- requires: user_profile --- requires: extension_postgis begin; set search_path to camper, public; -create table company_geography ( +create table location ( company_id integer primary key references company, - geog geography not null + directions xml not null, + map_embed xml not null, + opening_dates xml not null ); -grant select on table company_geography to guest; -grant select on table company_geography to employee; -grant select, insert, update, delete on table company_geography to admin; +grant select on table location to guest; +grant select on table location to employee; +grant select, insert, update, delete on table location to admin; -alter table company_geography enable row level security; +alter table location enable row level security; create policy guest_ok -on company_geography +on location for select using (true) ; create policy insert_to_company -on company_geography +on location for insert with check ( company_id in (select company_id from user_profile) @@ -35,7 +35,7 @@ with check ( ; create policy update_company -on company_geography +on location for update using ( company_id in (select company_id from user_profile) @@ -43,7 +43,7 @@ using ( ; create policy delete_from_company -on company_geography +on location for delete using ( company_id in (select company_id from user_profile) diff --git a/deploy/location_i18n.sql b/deploy/location_i18n.sql new file mode 100644 index 0000000..9e2af51 --- /dev/null +++ b/deploy/location_i18n.sql @@ -0,0 +1,23 @@ +-- Deploy camper:location_i18n to pg +-- requires: roles +-- requires: schema_camper +-- requires: location +-- requires: language + +begin; + +set search_path to camper, public; + +create table location_i18n ( + company_id integer not null references location, + lang_tag text not null references language, + directions xml not null, + opening_dates xml not null, + primary key (company_id, lang_tag) +); + +grant select on table location_i18n to guest; +grant select on table location_i18n to employee; +grant select, insert, update, delete on table location_i18n to admin; + +commit; diff --git a/deploy/setup_location.sql b/deploy/setup_location.sql new file mode 100644 index 0000000..e4e1cb9 --- /dev/null +++ b/deploy/setup_location.sql @@ -0,0 +1,26 @@ +-- Deploy camper:setup_location to pg +-- requires: roles +-- requires: schema_camper +-- requires: location + +begin; + +set search_path to camper, public; + +create or replace function setup_location(company integer, directions text, map_embed text, opening_dates text) returns void as +$$ + insert into location (company_id, directions, map_embed, opening_dates) + values (company, xmlparse(content directions), xmlparse(content map_embed), xmlparse(content opening_dates)) + on conflict (company_id) do update + set directions = excluded.directions + , map_embed = excluded.map_embed + , opening_dates = excluded.opening_dates + ; +$$ + language sql +; + +revoke execute on function setup_location(integer, text, text, text) from public; +grant execute on function setup_location(integer, text, text, text) to admin; + +commit; diff --git a/deploy/translate_location.sql b/deploy/translate_location.sql new file mode 100644 index 0000000..88c731d --- /dev/null +++ b/deploy/translate_location.sql @@ -0,0 +1,25 @@ +-- Deploy camper:translate_location to pg +-- requires: roles +-- requires: schema_camper +-- requires: location_i18n + +begin; + +set search_path to camper, public; + +create or replace function translate_location(company_id integer, lang_tag text, directions text, opening_dates text) returns void as +$$ + insert into location_i18n (company_id, lang_tag, directions, opening_dates) + values (company_id, lang_tag, xmlparse(content coalesce(directions, '')), xmlparse(content coalesce(opening_dates, ''))) + on conflict (company_id, lang_tag) do update + set directions = excluded.directions + , opening_dates = excluded.opening_dates + ; +$$ + language sql +; + +revoke execute on function translate_location(integer, text, text, text) from public; +grant execute on function translate_location(integer, text, text, text) to admin; + +commit; diff --git a/pkg/app/admin.go b/pkg/app/admin.go index a84fdc6..a89d9bd 100644 --- a/pkg/app/admin.go +++ b/pkg/app/admin.go @@ -6,6 +6,7 @@ package app import ( + "dev.tandem.ws/tandem/camper/pkg/location" "net/http" "dev.tandem.ws/tandem/camper/pkg/auth" @@ -26,6 +27,7 @@ type adminHandler struct { campsite *campsite.AdminHandler company *company.AdminHandler home *home.AdminHandler + location *location.AdminHandler media *media.AdminHandler payment *booking.AdminHandler season *season.AdminHandler @@ -37,6 +39,7 @@ func newAdminHandler(locales locale.Locales, mediaDir string) *adminHandler { campsite: campsite.NewAdminHandler(locales), company: company.NewAdminHandler(), home: home.NewAdminHandler(locales), + location: location.NewAdminHandler(), media: media.NewAdminHandler(mediaDir), payment: booking.NewAdminHandler(), season: season.NewAdminHandler(locales), @@ -66,6 +69,8 @@ func (h *adminHandler) Handle(user *auth.User, company *auth.Company, conn *data h.company.Handler(user, company, conn).ServeHTTP(w, r) case "home": h.home.Handler(user, company, conn).ServeHTTP(w, r) + case "location": + h.location.Handler(user, company, conn).ServeHTTP(w, r) case "media": h.media.Handler(user, company, conn).ServeHTTP(w, r) case "payment": diff --git a/pkg/app/public.go b/pkg/app/public.go index e2a59db..eecbd72 100644 --- a/pkg/app/public.go +++ b/pkg/app/public.go @@ -14,6 +14,7 @@ import ( "dev.tandem.ws/tandem/camper/pkg/database" "dev.tandem.ws/tandem/camper/pkg/home" httplib "dev.tandem.ws/tandem/camper/pkg/http" + "dev.tandem.ws/tandem/camper/pkg/location" "dev.tandem.ws/tandem/camper/pkg/services" "dev.tandem.ws/tandem/camper/pkg/template" ) @@ -22,6 +23,7 @@ type publicHandler struct { home *home.PublicHandler booking *booking.PublicHandler campsite *campsite.PublicHandler + location *location.PublicHandler services *services.PublicHandler } @@ -30,6 +32,7 @@ func newPublicHandler() *publicHandler { home: home.NewPublicHandler(), booking: booking.NewPublicHandler(), campsite: campsite.NewPublicHandler(), + location: location.NewPublicHandler(), services: services.NewPublicHandler(), } } @@ -47,8 +50,8 @@ func (h *publicHandler) Handler(user *auth.User, company *auth.Company, conn *da campgroundHandler(user, company, conn).ServeHTTP(w, r) case "campsites": h.campsite.Handler(user, company, conn).ServeHTTP(w, r) - case "contact": - contactHandler(user, company, conn).ServeHTTP(w, r) + case "location": + h.location.Handler(user, company, conn).ServeHTTP(w, r) case "services": h.services.Handler(user, company, conn).ServeHTTP(w, r) case "surroundings": @@ -98,53 +101,3 @@ func campgroundHandler(user *auth.User, company *auth.Company, conn *database.Co } }) } - -func contactHandler(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 "": - switch r.Method { - case http.MethodGet: - page := newContactPage() - page.MustRender(w, r, user, company, conn) - default: - httplib.MethodNotAllowed(w, r, http.MethodGet) - } - default: - http.NotFound(w, r) - } - }) -} - -type contactPage struct { - *template.PublicPage - CompanyGeography *geographyPoint -} - -func newContactPage() *contactPage { - page := &contactPage{ - PublicPage: template.NewPublicPage(), - } - return page -} - -func (p *contactPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { - p.Setup(r, user, company, conn) - row := conn.QueryRow(r.Context(), `select st_x(geog::geometry)::text, st_y(geog::geometry)::text from company_geography where company_id = $1`, company.ID) - geography := &geographyPoint{} - if err := row.Scan(&geography.Lng, &geography.Lat); err != nil { - if !database.ErrorIsNotFound(err) { - panic(err) - } - } else { - p.CompanyGeography = geography - } - template.MustRenderPublic(w, r, user, company, "contact.gohtml", p) -} - -type geographyPoint struct { - Lat string - Lng string -} diff --git a/pkg/auth/company.go b/pkg/auth/company.go index 755641c..2833bed 100644 --- a/pkg/auth/company.go +++ b/pkg/auth/company.go @@ -7,19 +7,22 @@ package auth import ( "context" + "golang.org/x/text/language" "dev.tandem.ws/tandem/camper/pkg/database" "dev.tandem.ws/tandem/camper/pkg/locale" ) type Company struct { - ID int - Locales locale.Locales + ID int + DefaultLanguage language.Tag + Locales locale.Locales } func CompanyByHost(ctx context.Context, conn *database.Conn, host string, allLocales locale.Locales) (*Company, error) { company := &Company{ - Locales: allLocales, + Locales: allLocales, + DefaultLanguage: language.Catalan, } if err := conn.QueryRow(ctx, ` select company_id diff --git a/pkg/database/funcs.go b/pkg/database/funcs.go index da1788b..68cf458 100644 --- a/pkg/database/funcs.go +++ b/pkg/database/funcs.go @@ -92,3 +92,13 @@ func (c *Conn) OrderSeasons(ctx context.Context, slugs []string) error { _, err := c.Exec(ctx, "select order_seasons($1)", slugs) return err } + +func (tx *Tx) SetupLocation(ctx context.Context, companyID int, directions string, mapEmbed string, openingHours string) error { + _, err := tx.Exec(ctx, "select setup_location($1, $2, $3, $4)", companyID, directions, mapEmbed, openingHours) + return err +} + +func (tx *Tx) TranslateLocation(ctx context.Context, companyID int, langTag language.Tag, directions string, openingHours string) error { + _, err := tx.Exec(ctx, "select translate_location($1, $2, $3, $4)", companyID, langTag, directions, openingHours) + return err +} diff --git a/pkg/form/input.go b/pkg/form/input.go index 0e74c3c..926beed 100644 --- a/pkg/form/input.go +++ b/pkg/form/input.go @@ -7,6 +7,7 @@ package form import ( "database/sql/driver" + "dev.tandem.ws/tandem/camper/pkg/locale" "net/http" "strconv" "strings" @@ -50,3 +51,21 @@ type L10nInput struct { Input Source string } + +type I18nInput map[string]*Input + +func NewI18nInput(locales locale.Locales, name string) I18nInput { + input := make(I18nInput) + for lang := range locales { + input[lang.String()] = &Input{ + Name: name + "." + lang.String(), + } + } + return input +} + +func (input I18nInput) FillValue(r *http.Request) { + for _, inner := range input { + inner.FillValue(r) + } +} diff --git a/pkg/location/admin.go b/pkg/location/admin.go new file mode 100644 index 0000000..7379e5d --- /dev/null +++ b/pkg/location/admin.go @@ -0,0 +1,156 @@ +package location + +import ( + "context" + "golang.org/x/text/language" + "net/http" + + "github.com/jackc/pgx/v4" + + "dev.tandem.ws/tandem/camper/pkg/auth" + "dev.tandem.ws/tandem/camper/pkg/database" + "dev.tandem.ws/tandem/camper/pkg/form" + httplib "dev.tandem.ws/tandem/camper/pkg/http" + "dev.tandem.ws/tandem/camper/pkg/locale" + "dev.tandem.ws/tandem/camper/pkg/template" +) + +type AdminHandler struct { +} + +func NewAdminHandler() *AdminHandler { + return &AdminHandler{} +} + +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) + + switch head { + case "": + switch r.Method { + case http.MethodGet: + f := newLocationForm(company.Locales) + if err := f.FillFromDatabase(r.Context(), company, conn); err != nil { + if !database.ErrorIsNotFound(err) { + panic(err) + } + } + f.MustRender(w, r, user, company) + case http.MethodPut: + updateLocationSettings(w, r, user, company, conn) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet) + } + default: + http.NotFound(w, r) + } + }) +} + +func updateLocationSettings(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + f := newLocationForm(company.Locales) + if ok, err := form.Handle(f, w, r, user); err != nil { + return + } else if !ok { + f.MustRender(w, r, user, company) + return + } + tx := conn.MustBegin(r.Context()) + defer tx.Rollback(r.Context()) + var defaultLang = company.DefaultLanguage.String() + if err := tx.SetupLocation(r.Context(), company.ID, f.Directions[defaultLang].Val, f.MapEmbed.Val, f.OpeningDates[defaultLang].Val); err != nil { + panic(err) + } + for lang := range company.Locales { + if lang == company.DefaultLanguage { + continue + } + if err := tx.TranslateLocation(r.Context(), company.ID, lang, f.Directions[lang.String()].Val, f.OpeningDates[lang.String()].Val); err != nil { + panic(err) + } + } + tx.MustCommit(r.Context()) + httplib.Redirect(w, r, "/admin/location", http.StatusSeeOther) +} + +type locationForm struct { + Directions form.I18nInput + MapEmbed *form.Input + OpeningDates form.I18nInput +} + +func newLocationForm(locales locale.Locales) *locationForm { + return &locationForm{ + Directions: form.NewI18nInput(locales, "directions"), + MapEmbed: &form.Input{ + Name: "map_embed", + }, + OpeningDates: form.NewI18nInput(locales, "opening_dates"), + } +} + +func (f *locationForm) FillFromDatabase(ctx context.Context, company *auth.Company, conn *database.Conn) error { + var directions database.RecordArray + var openingDates database.RecordArray + err := conn.QueryRow(ctx, ` + select location.directions::text + , location.map_embed::text + , location.opening_dates::text + , array_agg((lang_tag, i18n.directions::text)) + , array_agg((lang_tag, i18n.opening_dates::text)) + from location + left join location_i18n as i18n using (company_id) + where company_id = $1 + group by location.directions::text + , location.map_embed::text + , location.opening_dates::text +`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, company.ID).Scan( + &f.Directions[company.DefaultLanguage.String()].Val, + &f.MapEmbed.Val, + &f.OpeningDates[company.DefaultLanguage.String()].Val, + &directions, + &openingDates, + ) + if err != nil { + return err + } + if err := fillI18nInput(f.Directions, directions); err != nil { + return err + } + if err := fillI18nInput(f.OpeningDates, openingDates); err != nil { + return err + } + return nil +} + +func fillI18nInput(input form.I18nInput, array database.RecordArray) error { + for _, el := range array.Elements { + tag, err := language.Parse(el.Fields[0].Get().(string)) + if err != nil { + return err + } + input[tag.String()].Val = el.Fields[1].Get().(string) + } + return nil +} + +func (f *locationForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { + template.MustRenderAdmin(w, r, user, company, "location.gohtml", f) +} + +func (f *locationForm) Parse(r *http.Request) error { + if err := r.ParseForm(); err != nil { + return err + } + f.Directions.FillValue(r) + f.MapEmbed.FillValue(r) + f.OpeningDates.FillValue(r) + return nil +} + +func (f *locationForm) Valid(l *locale.Locale) bool { + v := form.NewValidator(l) + return v.AllOK +} diff --git a/pkg/location/public.go b/pkg/location/public.go new file mode 100644 index 0000000..ccbedb9 --- /dev/null +++ b/pkg/location/public.go @@ -0,0 +1,67 @@ +package location + +import ( + "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" + gotemplate "html/template" + "net/http" +) + +type PublicHandler struct { +} + +func NewPublicHandler() *PublicHandler { + return &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 "": + switch r.Method { + case http.MethodGet: + page := newLocationPage() + page.MustRender(w, r, user, company, conn) + default: + httplib.MethodNotAllowed(w, r, http.MethodGet) + } + default: + http.NotFound(w, r) + } + }) +} + +type locationPage struct { + *template.PublicPage + Directions gotemplate.HTML + MapEmbed gotemplate.HTML +} + +func newLocationPage() *locationPage { + page := &locationPage{ + PublicPage: template.NewPublicPage(), + } + return page +} + +func (p *locationPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { + p.Setup(r, user, company, conn) + row := conn.QueryRow(r.Context(), ` + select coalesce(i18n.directions, location.directions)::text + , map_embed::text + from location + left join location_i18n as i18n on location.company_id = i18n.company_id and i18n.lang_tag = $1 + where location.company_id = $2 + `, user.Locale.Language, company.ID) + if err := row.Scan(&p.Directions, &p.MapEmbed); err != nil { + if !database.ErrorIsNotFound(err) { + panic(err) + } + } + template.MustRenderPublic(w, r, user, company, "location.gohtml", p) +} diff --git a/pkg/template/page.go b/pkg/template/page.go index 2264573..e9727c0 100644 --- a/pkg/template/page.go +++ b/pkg/template/page.go @@ -8,6 +8,7 @@ package template import ( "context" "fmt" + gotemplate "html/template" "net/http" "sort" @@ -21,6 +22,7 @@ type PublicPage struct { LocalizedAlternates []*LocalizedAlternate Menu *siteMenu CompanyAddress *address + OpeningDates gotemplate.HTML } func NewPublicPage() *PublicPage { @@ -54,6 +56,15 @@ func (p *PublicPage) Setup(r *http.Request, user *auth.User, company *auth.Compa `, user.Locale.Language, company.ID), } + if err := conn.QueryRow(r.Context(), ` + select coalesce(i18n.opening_dates, location.opening_dates) + from location + left join location_i18n as i18n on location.company_id = i18n.company_id and i18n.lang_tag = $1 + where location.company_id = $2 + `, user.Locale.Language, company.ID).Scan(&p.OpeningDates); err != nil { + panic(err) + } + if err := p.CompanyAddress.FillFromDatabase(r.Context(), conn, user, company); err != nil { panic(err) } @@ -113,19 +124,19 @@ type address struct { func (addr *address) FillFromDatabase(ctx context.Context, conn *database.Conn, user *auth.User, company *auth.Company) error { row := conn.QueryRow(ctx, ` - select trade_name - , address - , postal_code - , province - , city - , coalesce(country_i18n.name, country.name) as country_name - , phone::text - , email::text - , rtc_number - from company - join country using (country_code) - left join country_i18n on country.country_code = country_i18n.country_code and country_i18n.lang_tag = $2 - where company_id = $1 +select trade_name +, address +, postal_code +, province +, city +, coalesce(country_i18n.name, country.name) as country_name +, phone::text +, email::text +, rtc_number +from company +join country using (country_code) +left join country_i18n on country.country_code = country_i18n.country_code and country_i18n.lang_tag = $2 +where company_id = $1 `, company.ID, user.Locale.Language) return row.Scan( &addr.TradeName, diff --git a/po/ca.po b/po/ca.po index 4fd22b7..66814de 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-21 17:32+0100\n" +"POT-Creation-Date: 2023-12-21 21:08+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:52 web/templates/public/layout.gohtml:79 +#: web/templates/public/layout.gohtml:51 web/templates/public/layout.gohtml:79 #: web/templates/admin/services/index.gohtml:66 msgctxt "title" msgid "Services" @@ -53,6 +53,14 @@ msgstr "Serveis" msgid "The campsite offers many different services." msgstr "El càmping disposa de diversos serveis." +#: web/templates/public/location.gohtml:6 +#: web/templates/public/location.gohtml:12 +#: web/templates/public/layout.gohtml:53 web/templates/public/layout.gohtml:81 +#: web/templates/admin/layout.gohtml:60 +msgctxt "title" +msgid "Location" +msgstr "Com arribar" + #: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:37 #: web/templates/public/layout.gohtml:77 msgctxt "title" @@ -79,7 +87,7 @@ 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:53 web/templates/public/layout.gohtml:80 +#: web/templates/public/layout.gohtml:52 web/templates/public/layout.gohtml:80 msgctxt "title" msgid "Surroundings" msgstr "L’entorn" @@ -268,14 +276,8 @@ 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: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 +#: web/templates/public/layout.gohtml:54 msgctxt "title" msgid "Booking" msgstr "Reserva" @@ -364,18 +366,18 @@ 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:32 -#: web/templates/public/layout.gohtml:110 +#: web/templates/public/layout.gohtml:109 msgid "Campsite Montagut" msgstr "Càmping Montagut" -#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:19 +#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:20 msgid "Skip to main content" msgstr "Salta al contingut principal" #: 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 +#: web/templates/admin/layout.gohtml:45 web/templates/admin/layout.gohtml:79 msgctxt "title" msgid "Campsites" msgstr "Allotjaments" @@ -385,7 +387,12 @@ msgctxt "title" msgid "Sections" msgstr "Apartats" -#: web/templates/public/layout.gohtml:107 +#: web/templates/public/layout.gohtml:99 +msgctxt "title" +msgid "Opening" +msgstr "Obertura" + +#: web/templates/public/layout.gohtml:106 msgid "RTC #%s" msgstr "Núm. RTC %s" @@ -482,6 +489,33 @@ msgctxt "action" msgid "Translate" msgstr "Tradueix" +#: web/templates/admin/location.gohtml:6 web/templates/admin/location.gohtml:12 +msgctxt "title" +msgid "Location Settings" +msgstr "Paràmetres de com arribar" + +#: web/templates/admin/location.gohtml:17 +msgctxt "input" +msgid "Directions" +msgstr "Instruccions" + +#: web/templates/admin/location.gohtml:35 +msgctxt "input" +msgid "Opening Dates" +msgstr "Data d’obertura" + +#: web/templates/admin/location.gohtml:53 +msgctxt "input" +msgid "Map Embed" +msgstr "Incrustació del mapa" + +#: web/templates/admin/location.gohtml:60 web/templates/admin/payment.gohtml:62 +#: web/templates/admin/profile.gohtml:75 +#: web/templates/admin/taxDetails.gohtml:152 +msgctxt "action" +msgid "Save changes" +msgstr "Desa els canvis" + #: web/templates/admin/campsite/feature/form.gohtml:8 #: web/templates/admin/campsite/feature/form.gohtml:25 msgctxt "title" @@ -802,7 +836,7 @@ msgstr "Descripció" #: web/templates/admin/campsite/type/index.gohtml:6 #: web/templates/admin/campsite/type/index.gohtml:12 -#: web/templates/admin/layout.gohtml:41 +#: web/templates/admin/layout.gohtml:42 msgctxt "title" msgid "Campsite Types" msgstr "Tipus d’allotjaments" @@ -877,7 +911,7 @@ msgstr "Color" #: web/templates/admin/season/index.gohtml:6 #: web/templates/admin/season/index.gohtml:12 -#: web/templates/admin/layout.gohtml:47 +#: web/templates/admin/layout.gohtml:48 msgctxt "title" msgid "Seasons" msgstr "Temporades" @@ -909,7 +943,7 @@ msgid "Cancel" msgstr "Canceŀla" #: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12 -#: web/templates/admin/layout.gohtml:38 +#: web/templates/admin/layout.gohtml:39 msgctxt "title" msgid "Payment Settings" msgstr "Paràmetres de pagament" @@ -944,14 +978,8 @@ msgctxt "title" msgid "Integration" msgstr "Integració" -#: web/templates/admin/payment.gohtml:62 web/templates/admin/profile.gohtml:75 -#: web/templates/admin/taxDetails.gohtml:152 -msgctxt "action" -msgid "Save changes" -msgstr "Desa els canvis" - #: web/templates/admin/dashboard.gohtml:6 -#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:72 +#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:76 msgctxt "title" msgid "Dashboard" msgstr "Tauler" @@ -984,7 +1012,7 @@ msgid "New Service" msgstr "Nou servei" #: web/templates/admin/services/index.gohtml:6 -#: web/templates/admin/layout.gohtml:56 +#: web/templates/admin/layout.gohtml:57 msgctxt "title" msgid "Services Page" msgstr "Pàgina de serveis" @@ -1020,7 +1048,7 @@ msgid "Translate Service to %s" msgstr "Traducció del servei a %s" #: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:12 -#: web/templates/admin/layout.gohtml:31 +#: web/templates/admin/layout.gohtml:32 msgctxt "title" msgid "Profile" msgstr "Perfil" @@ -1112,29 +1140,29 @@ msgctxt "input" msgid "Legal Disclaimer" msgstr "Nota legal" -#: web/templates/admin/layout.gohtml:27 +#: web/templates/admin/layout.gohtml:28 msgctxt "title" msgid "User Menu" msgstr "Menú d’usuari" -#: web/templates/admin/layout.gohtml:35 +#: web/templates/admin/layout.gohtml:36 msgctxt "title" msgid "Company Settings" msgstr "Paràmetres de l’empresa" -#: web/templates/admin/layout.gohtml:50 +#: web/templates/admin/layout.gohtml:51 #: web/templates/admin/media/index.gohtml:6 #: web/templates/admin/media/index.gohtml:11 msgctxt "title" msgid "Media" msgstr "Mèdia" -#: web/templates/admin/layout.gohtml:53 web/templates/admin/home/index.gohtml:6 +#: web/templates/admin/layout.gohtml:54 web/templates/admin/home/index.gohtml:6 msgctxt "title" msgid "Home Page" msgstr "Pàgina d’inici" -#: web/templates/admin/layout.gohtml:61 +#: web/templates/admin/layout.gohtml:65 msgctxt "action" msgid "Logout" msgstr "Surt" @@ -1265,7 +1293,7 @@ msgstr "L’idioma escollit no és vàlid." msgid "File must be a valid PNG or JPEG image." msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida." -#: pkg/app/admin.go:56 +#: pkg/app/admin.go:59 msgid "Access forbidden" msgstr "Accés prohibit" @@ -1534,55 +1562,55 @@ msgstr "No podeu deixar el fitxer del mèdia en blanc." msgid "Filename can not be empty." msgstr "No podeu deixar el nom del fitxer en blanc." -#: pkg/booking/admin.go:74 +#: pkg/booking/admin.go:76 msgctxt "redsys environment" msgid "Test" msgstr "Proves" -#: pkg/booking/admin.go:78 +#: pkg/booking/admin.go:80 msgctxt "redsys environment" msgid "Live" msgstr "Real" -#: pkg/booking/admin.go:87 +#: pkg/booking/admin.go:89 msgctxt "redsys integration" msgid "InSite" msgstr "InSite" -#: pkg/booking/admin.go:91 +#: pkg/booking/admin.go:93 msgctxt "redsys integration" msgid "Redirect" msgstr "Redirecció" -#: pkg/booking/admin.go:135 +#: pkg/booking/admin.go:137 msgid "Merchant code can not be empty." msgstr "No podeu deixar el codi del comerç en blanc." -#: pkg/booking/admin.go:136 +#: pkg/booking/admin.go:138 msgid "Merchant code must be exactly nine digits long." msgstr "El codi del comerç ha de ser de nou dígits." -#: pkg/booking/admin.go:137 +#: pkg/booking/admin.go:139 msgid "Merchant code must be a number." msgstr "El codi del comerç." -#: pkg/booking/admin.go:141 +#: pkg/booking/admin.go:143 msgid "Terminal number can not be empty." msgstr "No podeu deixar el número del terminal en blanc." -#: pkg/booking/admin.go:142 +#: pkg/booking/admin.go:144 msgid "Terminal number must be a number between 1 and 999." msgstr "El número del terminal ha de ser entre 1 i 999" -#: pkg/booking/admin.go:150 +#: pkg/booking/admin.go:152 msgid "Selected environment is not valid." msgstr "L’entorn escollit no és vàlid." -#: pkg/booking/admin.go:151 +#: pkg/booking/admin.go:153 msgid "Selected integration is not valid." msgstr "La integració escollida no és vàlida." -#: pkg/booking/admin.go:154 +#: pkg/booking/admin.go:156 msgid "The merchant key is not valid." msgstr "Aquesta clau del comerç no és vàlid." @@ -1638,6 +1666,10 @@ msgstr "El valor de %s ha de ser com a mínim %d." msgid "%s must be at most %d." msgstr "El valor de %s ha de ser com a màxim %d." +#~ msgctxt "title" +#~ msgid "Contact" +#~ msgstr "Contacte" + #~ msgctxt "title" #~ msgid "Party Details" #~ msgstr "Dades dels visitants" diff --git a/po/es.po b/po/es.po index a01d616..727c026 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-21 17:32+0100\n" +"POT-Creation-Date: 2023-12-21 21:08+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:52 web/templates/public/layout.gohtml:79 +#: web/templates/public/layout.gohtml:51 web/templates/public/layout.gohtml:79 #: web/templates/admin/services/index.gohtml:66 msgctxt "title" msgid "Services" @@ -53,6 +53,14 @@ msgstr "Servicios" msgid "The campsite offers many different services." msgstr "El camping dispone de varios servicios." +#: web/templates/public/location.gohtml:6 +#: web/templates/public/location.gohtml:12 +#: web/templates/public/layout.gohtml:53 web/templates/public/layout.gohtml:81 +#: web/templates/admin/layout.gohtml:60 +msgctxt "title" +msgid "Location" +msgstr "Cómo llegar" + #: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:37 #: web/templates/public/layout.gohtml:77 msgctxt "title" @@ -79,7 +87,7 @@ 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:53 web/templates/public/layout.gohtml:80 +#: web/templates/public/layout.gohtml:52 web/templates/public/layout.gohtml:80 msgctxt "title" msgid "Surroundings" msgstr "El entorno" @@ -268,14 +276,8 @@ msgctxt "title" msgid "Campground" msgstr "El camping" -#: web/templates/public/contact.gohtml:6 web/templates/public/contact.gohtml:18 -#: 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 +#: web/templates/public/layout.gohtml:54 msgctxt "title" msgid "Booking" msgstr "Reserva" @@ -364,18 +366,18 @@ 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:32 -#: web/templates/public/layout.gohtml:110 +#: web/templates/public/layout.gohtml:109 msgid "Campsite Montagut" msgstr "Camping Montagut" -#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:19 +#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:20 msgid "Skip to main content" msgstr "Saltar al contenido principal" #: 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 +#: web/templates/admin/layout.gohtml:45 web/templates/admin/layout.gohtml:79 msgctxt "title" msgid "Campsites" msgstr "Alojamientos" @@ -385,7 +387,12 @@ msgctxt "title" msgid "Sections" msgstr "Apartados" -#: web/templates/public/layout.gohtml:107 +#: web/templates/public/layout.gohtml:99 +msgctxt "title" +msgid "Opening" +msgstr "Apertura" + +#: web/templates/public/layout.gohtml:106 msgid "RTC #%s" msgstr " RTC %s" @@ -482,6 +489,33 @@ msgctxt "action" msgid "Translate" msgstr "Traducir" +#: web/templates/admin/location.gohtml:6 web/templates/admin/location.gohtml:12 +msgctxt "title" +msgid "Location Settings" +msgstr "Parámetros de cómo llegar" + +#: web/templates/admin/location.gohtml:17 +msgctxt "input" +msgid "Directions" +msgstr "Instrucciones" + +#: web/templates/admin/location.gohtml:35 +msgctxt "input" +msgid "Opening Dates" +msgstr "Fechas de apertura" + +#: web/templates/admin/location.gohtml:53 +msgctxt "input" +msgid "Map Embed" +msgstr "Incrustación del mapa" + +#: web/templates/admin/location.gohtml:60 web/templates/admin/payment.gohtml:62 +#: web/templates/admin/profile.gohtml:75 +#: web/templates/admin/taxDetails.gohtml:152 +msgctxt "action" +msgid "Save changes" +msgstr "Guardar los cambios" + #: web/templates/admin/campsite/feature/form.gohtml:8 #: web/templates/admin/campsite/feature/form.gohtml:25 msgctxt "title" @@ -802,7 +836,7 @@ msgstr "Descripción" #: web/templates/admin/campsite/type/index.gohtml:6 #: web/templates/admin/campsite/type/index.gohtml:12 -#: web/templates/admin/layout.gohtml:41 +#: web/templates/admin/layout.gohtml:42 msgctxt "title" msgid "Campsite Types" msgstr "Tipos de alojamientos" @@ -877,7 +911,7 @@ msgstr "Color" #: web/templates/admin/season/index.gohtml:6 #: web/templates/admin/season/index.gohtml:12 -#: web/templates/admin/layout.gohtml:47 +#: web/templates/admin/layout.gohtml:48 msgctxt "title" msgid "Seasons" msgstr "Temporadas" @@ -909,7 +943,7 @@ msgid "Cancel" msgstr "Cancelar" #: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12 -#: web/templates/admin/layout.gohtml:38 +#: web/templates/admin/layout.gohtml:39 msgctxt "title" msgid "Payment Settings" msgstr "Parámetros de pago" @@ -944,14 +978,8 @@ msgctxt "title" msgid "Integration" msgstr "Integración" -#: web/templates/admin/payment.gohtml:62 web/templates/admin/profile.gohtml:75 -#: web/templates/admin/taxDetails.gohtml:152 -msgctxt "action" -msgid "Save changes" -msgstr "Guardar los cambios" - #: web/templates/admin/dashboard.gohtml:6 -#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:72 +#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:76 msgctxt "title" msgid "Dashboard" msgstr "Panel" @@ -984,7 +1012,7 @@ msgid "New Service" msgstr "Nuevo servicio" #: web/templates/admin/services/index.gohtml:6 -#: web/templates/admin/layout.gohtml:56 +#: web/templates/admin/layout.gohtml:57 msgctxt "title" msgid "Services Page" msgstr "Página de servicios" @@ -1020,7 +1048,7 @@ msgid "Translate Service to %s" msgstr "Traducción del servicio a %s" #: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:12 -#: web/templates/admin/layout.gohtml:31 +#: web/templates/admin/layout.gohtml:32 msgctxt "title" msgid "Profile" msgstr "Perfil" @@ -1112,29 +1140,29 @@ msgctxt "input" msgid "Legal Disclaimer" msgstr "Nota legal" -#: web/templates/admin/layout.gohtml:27 +#: web/templates/admin/layout.gohtml:28 msgctxt "title" msgid "User Menu" msgstr "Menú de usuario" -#: web/templates/admin/layout.gohtml:35 +#: web/templates/admin/layout.gohtml:36 msgctxt "title" msgid "Company Settings" msgstr "Parámetros de la empresa" -#: web/templates/admin/layout.gohtml:50 +#: web/templates/admin/layout.gohtml:51 #: web/templates/admin/media/index.gohtml:6 #: web/templates/admin/media/index.gohtml:11 msgctxt "title" msgid "Media" msgstr "Medios" -#: web/templates/admin/layout.gohtml:53 web/templates/admin/home/index.gohtml:6 +#: web/templates/admin/layout.gohtml:54 web/templates/admin/home/index.gohtml:6 msgctxt "title" msgid "Home Page" msgstr "Página de inicio" -#: web/templates/admin/layout.gohtml:61 +#: web/templates/admin/layout.gohtml:65 msgctxt "action" msgid "Logout" msgstr "Salir" @@ -1265,7 +1293,7 @@ msgstr "El idioma escogido no es válido." msgid "File must be a valid PNG or JPEG image." msgstr "El archivo tiene que ser una imagen PNG o JPEG válida." -#: pkg/app/admin.go:56 +#: pkg/app/admin.go:59 msgid "Access forbidden" msgstr "Acceso prohibido" @@ -1534,55 +1562,55 @@ msgstr "No podéis dejar el archivo del medio en blanco." msgid "Filename can not be empty." msgstr "No podéis dejar el nombre del archivo en blanco." -#: pkg/booking/admin.go:74 +#: pkg/booking/admin.go:76 msgctxt "redsys environment" msgid "Test" msgstr "Pruebas" -#: pkg/booking/admin.go:78 +#: pkg/booking/admin.go:80 msgctxt "redsys environment" msgid "Live" msgstr "Real" -#: pkg/booking/admin.go:87 +#: pkg/booking/admin.go:89 msgctxt "redsys integration" msgid "InSite" msgstr "InSite" -#: pkg/booking/admin.go:91 +#: pkg/booking/admin.go:93 msgctxt "redsys integration" msgid "Redirect" msgstr "Redirección" -#: pkg/booking/admin.go:135 +#: pkg/booking/admin.go:137 msgid "Merchant code can not be empty." msgstr "No podéis dejar el código del comercio en blanco." -#: pkg/booking/admin.go:136 +#: pkg/booking/admin.go:138 msgid "Merchant code must be exactly nine digits long." msgstr "El código del comercio tiene que ser de nueve dígitos." -#: pkg/booking/admin.go:137 +#: pkg/booking/admin.go:139 msgid "Merchant code must be a number." msgstr "El código del comercio tiene que ser un número." -#: pkg/booking/admin.go:141 +#: pkg/booking/admin.go:143 msgid "Terminal number can not be empty." msgstr "No podéis dejar el número de terminal en blanco." -#: pkg/booking/admin.go:142 +#: pkg/booking/admin.go:144 msgid "Terminal number must be a number between 1 and 999." msgstr "El número de terminal tiene que ser entre 1 y 999." -#: pkg/booking/admin.go:150 +#: pkg/booking/admin.go:152 msgid "Selected environment is not valid." msgstr "El entorno escogido no es válido." -#: pkg/booking/admin.go:151 +#: pkg/booking/admin.go:153 msgid "Selected integration is not valid." msgstr "La integración escogida no es válida." -#: pkg/booking/admin.go:154 +#: pkg/booking/admin.go:156 msgid "The merchant key is not valid." msgstr "Esta clave del comercio no es válida." @@ -1638,6 +1666,10 @@ msgstr "%s tiene que ser como mínimo %d." msgid "%s must be at most %d." msgstr "%s tiene que ser como máximo %d" +#~ msgctxt "title" +#~ msgid "Contact" +#~ msgstr "Contacto" + #~ msgctxt "title" #~ msgid "Party Details" #~ msgstr "Datos de los visitantes" diff --git a/po/fr.po b/po/fr.po index 38c4018..a6d5878 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-21 17:32+0100\n" +"POT-Creation-Date: 2023-12-21 21:08+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:52 web/templates/public/layout.gohtml:79 +#: web/templates/public/layout.gohtml:51 web/templates/public/layout.gohtml:79 #: web/templates/admin/services/index.gohtml:66 msgctxt "title" msgid "Services" @@ -54,6 +54,14 @@ msgstr "Services" msgid "The campsite offers many different services." msgstr "Le camping propose de nombreux services différents." +#: web/templates/public/location.gohtml:6 +#: web/templates/public/location.gohtml:12 +#: web/templates/public/layout.gohtml:53 web/templates/public/layout.gohtml:81 +#: web/templates/admin/layout.gohtml:60 +msgctxt "title" +msgid "Location" +msgstr "Comment nous rejoindre" + #: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:37 #: web/templates/public/layout.gohtml:77 msgctxt "title" @@ -80,7 +88,7 @@ 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:53 web/templates/public/layout.gohtml:80 +#: web/templates/public/layout.gohtml:52 web/templates/public/layout.gohtml:80 msgctxt "title" msgid "Surroundings" msgstr "Entourage" @@ -269,14 +277,8 @@ msgctxt "title" msgid "Campground" msgstr "Camping" -#: web/templates/public/contact.gohtml:6 web/templates/public/contact.gohtml:18 -#: 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 +#: web/templates/public/layout.gohtml:54 msgctxt "title" msgid "Booking" msgstr "Reservation" @@ -365,18 +367,18 @@ 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:32 -#: web/templates/public/layout.gohtml:110 +#: web/templates/public/layout.gohtml:109 msgid "Campsite Montagut" msgstr "Camping Montagut" -#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:19 +#: web/templates/public/layout.gohtml:23 web/templates/admin/layout.gohtml:20 msgid "Skip to main content" msgstr "Passer au contenu principal" #: 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 +#: web/templates/admin/layout.gohtml:45 web/templates/admin/layout.gohtml:79 msgctxt "title" msgid "Campsites" msgstr "Locatifs" @@ -386,7 +388,12 @@ msgctxt "title" msgid "Sections" msgstr "Sections" -#: web/templates/public/layout.gohtml:107 +#: web/templates/public/layout.gohtml:99 +msgctxt "title" +msgid "Opening" +msgstr "Ouverture" + +#: web/templates/public/layout.gohtml:106 msgid "RTC #%s" msgstr "# RTC %s" @@ -483,6 +490,33 @@ msgctxt "action" msgid "Translate" msgstr "Traduire" +#: web/templates/admin/location.gohtml:6 web/templates/admin/location.gohtml:12 +msgctxt "title" +msgid "Location Settings" +msgstr "Paramètres de comment nous rejoindre" + +#: web/templates/admin/location.gohtml:17 +msgctxt "input" +msgid "Directions" +msgstr "Directions" + +#: web/templates/admin/location.gohtml:35 +msgctxt "input" +msgid "Opening Dates" +msgstr "Dates d’ouverture" + +#: web/templates/admin/location.gohtml:53 +msgctxt "input" +msgid "Map Embed" +msgstr "Carte intégrée" + +#: web/templates/admin/location.gohtml:60 web/templates/admin/payment.gohtml:62 +#: web/templates/admin/profile.gohtml:75 +#: web/templates/admin/taxDetails.gohtml:152 +msgctxt "action" +msgid "Save changes" +msgstr "Enregistrer les changements" + #: web/templates/admin/campsite/feature/form.gohtml:8 #: web/templates/admin/campsite/feature/form.gohtml:25 msgctxt "title" @@ -803,7 +837,7 @@ msgstr "Description" #: web/templates/admin/campsite/type/index.gohtml:6 #: web/templates/admin/campsite/type/index.gohtml:12 -#: web/templates/admin/layout.gohtml:41 +#: web/templates/admin/layout.gohtml:42 msgctxt "title" msgid "Campsite Types" msgstr "Types d’emplacements de camping" @@ -878,7 +912,7 @@ msgstr "Couleur" #: web/templates/admin/season/index.gohtml:6 #: web/templates/admin/season/index.gohtml:12 -#: web/templates/admin/layout.gohtml:47 +#: web/templates/admin/layout.gohtml:48 msgctxt "title" msgid "Seasons" msgstr "Saisons" @@ -910,7 +944,7 @@ msgid "Cancel" msgstr "Annuler" #: web/templates/admin/payment.gohtml:6 web/templates/admin/payment.gohtml:12 -#: web/templates/admin/layout.gohtml:38 +#: web/templates/admin/layout.gohtml:39 msgctxt "title" msgid "Payment Settings" msgstr "Paramètres de paiement" @@ -945,14 +979,8 @@ msgctxt "title" msgid "Integration" msgstr "Intégration" -#: web/templates/admin/payment.gohtml:62 web/templates/admin/profile.gohtml:75 -#: web/templates/admin/taxDetails.gohtml:152 -msgctxt "action" -msgid "Save changes" -msgstr "Enregistrer les changements" - #: web/templates/admin/dashboard.gohtml:6 -#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:72 +#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:76 msgctxt "title" msgid "Dashboard" msgstr "Tableau de bord" @@ -985,7 +1013,7 @@ msgid "New Service" msgstr "Nouveau service" #: web/templates/admin/services/index.gohtml:6 -#: web/templates/admin/layout.gohtml:56 +#: web/templates/admin/layout.gohtml:57 msgctxt "title" msgid "Services Page" msgstr "La page des services" @@ -1021,7 +1049,7 @@ msgid "Translate Service to %s" msgstr "Traduire le service en %s" #: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:12 -#: web/templates/admin/layout.gohtml:31 +#: web/templates/admin/layout.gohtml:32 msgctxt "title" msgid "Profile" msgstr "Profil" @@ -1113,29 +1141,29 @@ msgctxt "input" msgid "Legal Disclaimer" msgstr "Avertissement juridique" -#: web/templates/admin/layout.gohtml:27 +#: web/templates/admin/layout.gohtml:28 msgctxt "title" msgid "User Menu" msgstr "Menu utilisateur" -#: web/templates/admin/layout.gohtml:35 +#: web/templates/admin/layout.gohtml:36 msgctxt "title" msgid "Company Settings" msgstr "Paramètres de l'entreprise" -#: web/templates/admin/layout.gohtml:50 +#: web/templates/admin/layout.gohtml:51 #: web/templates/admin/media/index.gohtml:6 #: web/templates/admin/media/index.gohtml:11 msgctxt "title" msgid "Media" msgstr "Média" -#: web/templates/admin/layout.gohtml:53 web/templates/admin/home/index.gohtml:6 +#: web/templates/admin/layout.gohtml:54 web/templates/admin/home/index.gohtml:6 msgctxt "title" msgid "Home Page" msgstr "Page d'accueil" -#: web/templates/admin/layout.gohtml:61 +#: web/templates/admin/layout.gohtml:65 msgctxt "action" msgid "Logout" msgstr "Déconnexion" @@ -1266,7 +1294,7 @@ msgstr "La langue sélectionnée n’est pas valide." msgid "File must be a valid PNG or JPEG image." msgstr "Le fichier doit être une image PNG ou JPEG valide." -#: pkg/app/admin.go:56 +#: pkg/app/admin.go:59 msgid "Access forbidden" msgstr "Accès interdit" @@ -1535,55 +1563,55 @@ msgstr "Le fichier téléchargé ne peut pas être vide." msgid "Filename can not be empty." msgstr "Le nom de fichier ne peut pas être vide." -#: pkg/booking/admin.go:74 +#: pkg/booking/admin.go:76 msgctxt "redsys environment" msgid "Test" msgstr "Test" -#: pkg/booking/admin.go:78 +#: pkg/booking/admin.go:80 msgctxt "redsys environment" msgid "Live" msgstr "Live" -#: pkg/booking/admin.go:87 +#: pkg/booking/admin.go:89 msgctxt "redsys integration" msgid "InSite" msgstr "Insite" -#: pkg/booking/admin.go:91 +#: pkg/booking/admin.go:93 msgctxt "redsys integration" msgid "Redirect" msgstr "Redirection" -#: pkg/booking/admin.go:135 +#: pkg/booking/admin.go:137 msgid "Merchant code can not be empty." msgstr "Le code marchand ne peut pas être vide." -#: pkg/booking/admin.go:136 +#: pkg/booking/admin.go:138 msgid "Merchant code must be exactly nine digits long." msgstr "Le code marchand doit comporter exactement neuf chiffres." -#: pkg/booking/admin.go:137 +#: pkg/booking/admin.go:139 msgid "Merchant code must be a number." msgstr "Le code du commerçant doit être un chiffre." -#: pkg/booking/admin.go:141 +#: pkg/booking/admin.go:143 msgid "Terminal number can not be empty." msgstr "Le numéro de terminal ne peut pas être vide." -#: pkg/booking/admin.go:142 +#: pkg/booking/admin.go:144 msgid "Terminal number must be a number between 1 and 999." msgstr "Le numéro de terminal doit être compris entre 1 et 999." -#: pkg/booking/admin.go:150 +#: pkg/booking/admin.go:152 msgid "Selected environment is not valid." msgstr "L’environnement sélectionné n’est pas valide." -#: pkg/booking/admin.go:151 +#: pkg/booking/admin.go:153 msgid "Selected integration is not valid." msgstr "L’intégration sélectionnée n’est pas valide." -#: pkg/booking/admin.go:154 +#: pkg/booking/admin.go:156 msgid "The merchant key is not valid." msgstr "La clé marchand n’est pas valide." @@ -1638,3 +1666,7 @@ msgstr "%s doit être %d ou plus." #, c-format msgid "%s must be at most %d." msgstr "%s doit être tout au plus %d." + +#~ msgctxt "title" +#~ msgid "Contact" +#~ msgstr "Contact" diff --git a/revert/company_geography.sql b/revert/company_geography.sql deleted file mode 100644 index 3f3c0b8..0000000 --- a/revert/company_geography.sql +++ /dev/null @@ -1,7 +0,0 @@ --- Revert camper:company_geography from pg - -begin; - -drop table if exists camper.company_geography; - -commit; diff --git a/revert/extension_postgis.sql b/revert/extension_postgis.sql deleted file mode 100644 index d70b18b..0000000 --- a/revert/extension_postgis.sql +++ /dev/null @@ -1,7 +0,0 @@ --- Revert camper:extension_postgis from pg - -begin; - -drop extension if exists postgis; - -commit; diff --git a/revert/location.sql b/revert/location.sql new file mode 100644 index 0000000..dd46108 --- /dev/null +++ b/revert/location.sql @@ -0,0 +1,7 @@ +-- Revert camper:location from pg + +begin; + +drop table if exists camper.location; + +commit; diff --git a/revert/location_i18n.sql b/revert/location_i18n.sql new file mode 100644 index 0000000..b74c366 --- /dev/null +++ b/revert/location_i18n.sql @@ -0,0 +1,7 @@ +-- Revert camper:location_i18n from pg + +begin; + +drop table if exists camper.location_i18n; + +commit; diff --git a/revert/setup_location.sql b/revert/setup_location.sql new file mode 100644 index 0000000..c26ea2f --- /dev/null +++ b/revert/setup_location.sql @@ -0,0 +1,7 @@ +-- Revert camper:setup_location from pg + +begin; + +drop function if exists camper.setup_location(integer, text, text, text); + +commit; diff --git a/revert/translate_location.sql b/revert/translate_location.sql new file mode 100644 index 0000000..fa42585 --- /dev/null +++ b/revert/translate_location.sql @@ -0,0 +1,7 @@ +-- Revert camper:translate_location from pg + +begin; + +drop function if exists camper.translate_location(integer, text, text, text); + +commit; diff --git a/sqitch.plan b/sqitch.plan index 49e8b19..38f8bdc 100644 --- a/sqitch.plan +++ b/sqitch.plan @@ -97,8 +97,6 @@ campsite_type_option_cost [roles schema_camper campsite_type season campsite_typ set_campsite_type_option_cost [roles schema_camper campsite_type_option_cost parse_price] 2023-10-05T17:41:58Z jordi fita mas # Add function to set cost of campsite type option add_campsite_type_option [roles schema_camper campsite_type_option campsite_type] 2023-10-06T09:40:03Z jordi fita mas # Add function to create new campsite type options edit_campsite_type_option [roles schema_camper campsite_type_option] 2023-10-06T09:51:02Z jordi fita mas # Add function to edit campsite type options -extension_postgis [schema_public] 2023-10-06T17:18:52Z jordi fita mas # Add PostGIS extension -company_geography [roles schema_camper company user_profile extension_postgis] 2023-10-06T17:53:34Z jordi fita mas # Add the relation for the GPS coordinates of companies campsite_type_carousel [roles schema_camper campsite_type media user_profile] 2023-10-09T17:18:38Z jordi fita mas # Add the carousel for campsite types campsite_type_carousel_i18n [roles schema_camper campsite_type_carousel language] 2023-10-09T17:45:09Z jordi fita mas # Add relation for campsite type carousel translations add_campsite_type_carousel_slide [roles schema_camper campsite_type_carousel campsite_type] 2023-10-09T17:59:49Z jordi fita mas # Add function to create slides for the campsite type carousel @@ -126,3 +124,7 @@ order_campsite_type_carousel [schema_camper roles campsite_type campsite_type_ca 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 +location [schema_camper roles company] 2023-12-21T17:01:28Z jordi fita mas # Add table to keep location information +location_i18n [roles schema_camper location language] 2023-12-21T17:32:50Z jordi fita mas # Add relation for location internationalization +translate_location [roles schema_camper location_i18n] 2023-12-21T17:37:47Z jordi fita mas # Add function to translate location +setup_location [roles schema_camper location] 2023-12-21T19:26:53Z jordi fita mas # Add function to setup location settings diff --git a/test/company_geography.sql b/test/company_geography.sql deleted file mode 100644 index 251ccb2..0000000 --- a/test/company_geography.sql +++ /dev/null @@ -1,168 +0,0 @@ --- Test company_geography -set client_min_messages to warning; -create extension if not exists pgtap; -reset client_min_messages; - -begin; - -select plan(30); - -set search_path to camper, public; - -select has_table('company_geography'); -select has_pk('company_geography'); -select table_privs_are('company_geography', 'guest', array['SELECT']); -select table_privs_are('company_geography', 'employee', array['SELECT']); -select table_privs_are('company_geography', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']); -select table_privs_are('company_geography', 'authenticator', array[]::text[]); - -select has_column('company_geography', 'company_id'); -select col_is_pk('company_geography', 'company_id'); -select col_is_fk('company_geography', 'company_id'); -select fk_ok('company_geography', 'company_id', 'company', 'company_id'); -select col_type_is('company_geography', 'company_id', 'integer'); -select col_not_null('company_geography', 'company_id'); -select col_hasnt_default('company_geography', 'company_id'); - -select has_column('company_geography', 'geog'); -select col_type_is('company_geography', 'geog', 'geography'); -select col_not_null('company_geography', 'geog'); -select col_hasnt_default('company_geography', 'geog'); - - -set client_min_messages to warning; -truncate company_geography 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') - , (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 'FR', 'USD', 'ca') - , (8, 'Company 8', 'XX345', '', '777-777-777', 'c@c', '', '', '', '', '', '', 'DE', 'USD', 'en') -; - -insert into company_user (company_id, user_id, role) -values (2, 1, 'admin') - , (4, 5, 'admin') -; - -insert into company_host (company_id, host) -values (2, 'co2') - , (4, 'co4') -; - -insert into company_geography (company_id, geog) -values (2, 'SRID=4326;POINT(-118.4079 33.9434)') - , (4, 'SRID=4326;POINT(2.5559 49.0083)') -; - -prepare geog_data as -select company_id, st_x(geog::geometry), st_y(geog::geometry) -from company_geography -; - -set role guest; -select bag_eq( - 'geog_data', - $$ values (2, -118.4079, 33.9434) - , (4, 2.5559, 49.0083) - $$, - 'Everyone should be able to list all geography across all companies' -); -reset role; - -select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog', 'co2'); - -select lives_ok( - $$ delete from company_geography where company_id = 2 $$, - 'Admin from company 2 should be able to delete geography from that company.' -); - -select bag_eq( - 'geog_data', - $$ values (4, 2.5559, 49.0083) - $$, - 'The row should have been deleted.' -); - -select lives_ok( - $$ insert into company_geography(company_id, geog) values (2, 'SRID=4326;POINT(-22.6056 63.9850)') $$, - 'Admin from company 2 should be able to insert a new geography to that company.' -); - -select bag_eq( - 'geog_data', - $$ values (2, -22.6056, 63.9850) - , (4, 2.5559, 49.0083) - $$, - 'The new row should have been added' -); - -select lives_ok( - $$ update company_geography set geog = 'SRID=4326;POINT(139.7330 35.5670)' where company_id = 2 $$, - 'Admin from company 2 should be able to update geography of that company.' -); - -select bag_eq( - 'geog_data', - $$ values (2, 139.7330, 35.5670) - , (4, 2.5559, 49.0083) - $$, - 'The row should have been updated.' -); - - -select throws_ok( - $$ insert into company_geography (company_id, geog) values (8, 'SRID=4326;POINT(2.5559 49.0083)') $$, - '42501', 'new row violates row-level security policy for table "company_geography"', - 'Admin from company 2 should NOT be able to insert new geography to another company 8.' -); - -select lives_ok( - $$ update company_geography set geog = 'SRID=4326;POINT(139.7330 35.5670)' where company_id = 4 $$, - 'Admin from company 2 should not be able to update geography of company 4, but no error if company_id is not changed.' -); - -select bag_eq( - 'geog_data', - $$ values (2, 139.7330, 35.5670) - , (4, 2.5559, 49.0083) - $$, - 'No row should have been changed.' -); - -select throws_ok( - $$ update company_geography set company_id = 4 where company_id = 2 $$, - '42501', 'new row violates row-level security policy for table "company_geography"', - 'Admin from company 2 should NOT be able to move geography to company 4' -); - -select lives_ok( - $$ delete from company_geography where company_id = 4 $$, - 'Admin from company 2 should NOT be able to delete geography from company 4, but not error is thrown' -); - -select bag_eq( - 'geog_data', - $$ values (2, 139.7330, 35.5670) - , (4, 2.5559, 49.0083) - $$, - 'No row should have been changed' -); - -reset role; - - -select * -from finish(); - -rollback; - diff --git a/test/extensions.sql b/test/extensions.sql index 39bfe10..7c31d17 100644 --- a/test/extensions.sql +++ b/test/extensions.sql @@ -14,7 +14,6 @@ select extensions_are(array [ , 'pg_libphonenumber' , 'pgtap' , 'plpgsql' - , 'postgis' , 'uri' , 'vat' ]); diff --git a/test/location.sql b/test/location.sql new file mode 100644 index 0000000..931d6a1 --- /dev/null +++ b/test/location.sql @@ -0,0 +1,178 @@ +-- Test location +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(38); + +set search_path to camper, public; + +select has_table('location'); +select has_pk('location'); +select table_privs_are('location', 'guest', array ['SELECT']); +select table_privs_are('location', 'employee', array ['SELECT']); +select table_privs_are('location', 'admin', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']); +select table_privs_are('location', 'authenticator', array []::text[]); + +select has_column('location', 'company_id'); +select col_is_pk('location', 'company_id'); +select col_is_fk('location', 'company_id'); +select fk_ok('location', 'company_id', 'company', 'company_id'); +select col_type_is('location', 'company_id', 'integer'); +select col_not_null('location', 'company_id'); +select col_hasnt_default('location', 'company_id'); + +select has_column('location', 'directions'); +select col_type_is('location', 'directions', 'xml'); +select col_not_null('location', 'directions'); +select col_hasnt_default('location', 'directions'); + +select has_column('location', 'map_embed'); +select col_type_is('location', 'map_embed', 'xml'); +select col_not_null('location', 'map_embed'); +select col_hasnt_default('location', 'map_embed'); + +select has_column('location', 'opening_dates'); +select col_type_is('location', 'opening_dates', 'xml'); +select col_not_null('location', 'opening_dates'); +select col_hasnt_default('location', 'opening_dates'); + + +set client_min_messages to warning; +truncate location 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') + , (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 'FR', 'USD', 'ca') + , (8, 'Company 8', 'XX345', '', '777-777-777', 'c@c', '', '', '', '', '', '', 'DE', 'USD', 'en') +; + +insert into company_user (company_id, user_id, role) +values (2, 1, 'admin') + , (4, 5, 'admin') +; + +insert into company_host (company_id, host) +values (2, 'co2') + , (4, 'co4') +; + +insert into location (company_id, directions, map_embed, opening_dates) +values (2, '

up

', '', '

today

') + , (4, '

down

', '', '

yesterday

') +; + +prepare location_data as +select company_id, directions::text, map_embed::text, opening_dates::text +from location +; + +set role guest; +select bag_eq( + 'location_data', + $$ values (2, '

up

', '', '

today

') + , (4, '

down

', '', '

yesterday

') + $$, + 'Everyone should be able to list all location across all companies' +); +reset role; + +select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog', 'co2'); + +select lives_ok( + $$ delete from location where company_id = 2 $$, + 'Admin from company 2 should be able to delete location from that company.' +); + +select bag_eq( + 'location_data', + $$ values (4, '

down

', '', '

yesterday

') + $$, + 'The row should have been deleted.' +); + +select lives_ok( + $$ insert into location(company_id, directions, map_embed, opening_dates) values (2, '

left

', '', '

tomorrow

') $$, + 'Admin from company 2 should be able to insert a new location to that company.' +); + +select bag_eq( + 'location_data', + $$ values (2, '

left

', '', '

tomorrow

') + , (4, '

down

', '', '

yesterday

') + $$, + 'The new row should have been added' +); + +select lives_ok( + $$ update location set directions = '

up

', map_embed = '', opening_dates = '

today

' where company_id = 2 $$, + 'Admin from company 2 should be able to update location of that company.' +); + +select bag_eq( + 'location_data', + $$ values (2, '

up

', '', '

today

') + , (4, '

down

', '', '

yesterday

') + $$, + 'The row should have been updated.' +); + + +select throws_ok( + $$ insert into location (company_id, directions, map_embed, opening_dates) values (8, '

', '

', '

') $$, + '42501', 'new row violates row-level security policy for table "location"', + 'Admin from company 2 should NOT be able to insert new location to another company.' +); + +select lives_ok( + $$ update location set opening_dates = '

never

' where company_id = 4 $$, + 'Admin from company 2 should not be able to update location of company 4, but no error if company_id is not changed.' +); + +select bag_eq( + 'location_data', + $$ values (2, '

up

', '', '

today

') + , (4, '

down

', '', '

yesterday

') + $$, + 'No row should have been changed.' +); + +select throws_ok( + $$ update location set company_id = 4 where company_id = 2 $$, + '42501', 'new row violates row-level security policy for table "location"', + 'Admin from company 2 should NOT be able to move location to company 4' +); + +select lives_ok( + $$ delete from location where company_id = 4 $$, + 'Admin from company 2 should NOT be able to delete location from company 4, but not error is thrown' +); + +select bag_eq( + 'location_data', + $$ values (2, '

up

', '', '

today

') + , (4, '

down

', '', '

yesterday

') + $$, + 'No row should have been changed' +); + +reset role; + + +select * +from finish(); + +rollback; + diff --git a/test/location_i18n.sql b/test/location_i18n.sql new file mode 100644 index 0000000..f3a9a15 --- /dev/null +++ b/test/location_i18n.sql @@ -0,0 +1,49 @@ +-- Test location_i18n +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(27); + +set search_path to camper, public; + +select has_table('location_i18n'); +select has_pk('location_i18n'); +select col_is_pk('location_i18n', array['company_id', 'lang_tag']); +select table_privs_are('location_i18n', 'guest', array['SELECT']); +select table_privs_are('location_i18n', 'employee', array['SELECT']); +select table_privs_are('location_i18n', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']); +select table_privs_are('location_i18n', 'authenticator', array[]::text[]); + +select has_column('location_i18n', 'company_id'); +select col_is_fk('location_i18n', 'company_id'); +select fk_ok('location_i18n', 'company_id', 'location', 'company_id'); +select col_type_is('location_i18n', 'company_id', 'integer'); +select col_not_null('location_i18n', 'company_id'); +select col_hasnt_default('location_i18n', 'company_id'); + +select has_column('location_i18n', 'lang_tag'); +select col_is_fk('location_i18n', 'lang_tag'); +select fk_ok('location_i18n', 'lang_tag', 'language', 'lang_tag'); +select col_type_is('location_i18n', 'lang_tag', 'text'); +select col_not_null('location_i18n', 'lang_tag'); +select col_hasnt_default('location_i18n', 'lang_tag'); + +select has_column('location_i18n', 'directions'); +select col_type_is('location_i18n', 'directions', 'xml'); +select col_not_null('location_i18n', 'directions'); +select col_hasnt_default('location_i18n', 'directions'); + +select has_column('location_i18n', 'opening_dates'); +select col_type_is('location_i18n', 'opening_dates', 'xml'); +select col_not_null('location_i18n', 'opening_dates'); +select col_hasnt_default('location_i18n', 'opening_dates'); + + +select * +from finish(); + +rollback; + diff --git a/test/setup_location.sql b/test/setup_location.sql new file mode 100644 index 0000000..12abb6f --- /dev/null +++ b/test/setup_location.sql @@ -0,0 +1,76 @@ +-- Test setup_location +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(15); + +set search_path to camper, public; + +select has_function('camper', 'setup_location', array['integer', 'text', 'text', 'text']); +select function_lang_is('camper', 'setup_location', array['integer', 'text', 'text', 'text'], 'sql'); +select function_returns('camper', 'setup_location', array['integer', 'text', 'text', 'text'], 'void'); +select isnt_definer('camper', 'setup_location', array['integer', 'text', 'text', 'text']); +select volatility_is('camper', 'setup_location', array['integer', 'text', 'text', 'text'], 'volatile'); +select function_privs_are('camper', 'setup_location', array ['integer', 'text', 'text', 'text'], 'guest', array[]::text[]); +select function_privs_are('camper', 'setup_location', array ['integer', 'text', 'text', 'text'], 'employee', array[]::text[]); +select function_privs_are('camper', 'setup_location', array ['integer', 'text', 'text', 'text'], 'admin', array['EXECUTE']); +select function_privs_are('camper', 'setup_location', array ['integer', 'text', 'text', 'text'], 'authenticator', array[]::text[]); + +set client_min_messages to warning; +truncate location 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, rtc_number, country_code, currency_code, default_lang_tag) +values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 'ES', 'EUR', 'ca') + , (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 'FR', 'USD', 'ca') +; + +prepare location_data as +select company_id, directions::text, map_embed::text, opening_dates::text +from location +; + +select lives_ok( + $$ select setup_location(1, '

Up

', '', '

Today

') $$, + 'Should be able to setup location parameters for the first company' +); + +select lives_ok( + $$ select setup_location(2, '

Left

', '', '

Tomorrow

') $$, + 'Should be able to setup location parameters for the second company' +); + +select bag_eq( + 'location_data', + $$ values (1, '

Up

', '', '

Today

'), + (2, '

Left

', '', '

Tomorrow

') + $$, + 'Should have inserted all location parameters' +); + +select lives_ok( + $$ select setup_location(1, '

Down

', '', '

Never

') $$, + 'Should be able to update location parameters for the first company' +); + +select lives_ok( + $$ select setup_location(2, '

Right

', '', '

Yesterday

') $$, + 'Should be able to update location parameters for the second company' +); + +select bag_eq( + 'location_data', + $$ values (1, '

Down

', '', '

Never

'), + (2, '

Right

', '', '

Yesterday

') + $$, + 'Should have updated all location parameters' +); + +select * +from finish(); + +rollback; diff --git a/test/translate_location.sql b/test/translate_location.sql new file mode 100644 index 0000000..49f5511 --- /dev/null +++ b/test/translate_location.sql @@ -0,0 +1,72 @@ +-- Test translate_location +set client_min_messages to warning; +create extension if not exists pgtap; +reset client_min_messages; + +begin; + +select plan(13); + +set search_path to camper, public; + +select has_function('camper', 'translate_location', array['integer', 'text', 'text', 'text']); +select function_lang_is('camper', 'translate_location', array['integer', 'text', 'text', 'text'], 'sql'); +select function_returns('camper', 'translate_location', array['integer', 'text', 'text', 'text'], 'void'); +select isnt_definer('camper', 'translate_location', array['integer', 'text', 'text', 'text']); +select volatility_is('camper', 'translate_location', array['integer', 'text', 'text', 'text'], 'volatile'); +select function_privs_are('camper', 'translate_location', array['integer', 'text', 'text', 'text'], 'guest', array[]::text[]); +select function_privs_are('camper', 'translate_location', array['integer', 'text', 'text', 'text'], 'employee', array[]::text[]); +select function_privs_are('camper', 'translate_location', array['integer', 'text', 'text', 'text'], 'admin', array['EXECUTE']); +select function_privs_are('camper', 'translate_location', array['integer', 'text', 'text', 'text'], 'authenticator', array[]::text[]); + + +set client_min_messages to warning; +truncate location_i18n cascade; +truncate location 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, rtc_number, country_code, currency_code, default_lang_tag) +values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 'ES', 'EUR', 'ca') + , (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 'FR', 'USD', 'ca') +; + +insert into location (company_id, directions, map_embed, opening_dates) +values (2, '

Up

', '', '

Tomorrow

') + , (4, '

Left

', '', '

Today

') +; + +insert into location_i18n (company_id, lang_tag, directions, opening_dates) +values (2, 'ca', '

Uh?

', '

Uh?

') + , (4, 'ca', '

Uh?

', '

Uh?

') +; + +select lives_ok( + $$ select translate_location(2, 'es', '

Arriba

', '

Mañana

') $$, + 'Should be able to translate the location of the first company to a new language' +); + +select lives_ok( + $$ select translate_location(2, 'ca', '

Dalt

', '

Demà

') $$, + 'Should be able to overwrite a location’s translation' +); + +select lives_ok( + $$ select translate_location(4, 'ca', null, null) $$, + 'Should be able to “translate” a location to empty strings' +); + + +select bag_eq( + $$ select company_id, lang_tag, directions::text, opening_dates::text from location_i18n $$, + $$ values (2, 'ca', '

Dalt

', '

Demà

') + , (2, 'es', '

Arriba

', '

Mañana

') + , (4, 'ca', '', '') + $$, + 'Should have translated all locations' +); + +select * +from finish(); + +rollback; diff --git a/verify/company_geography.sql b/verify/company_geography.sql deleted file mode 100644 index fa997d0..0000000 --- a/verify/company_geography.sql +++ /dev/null @@ -1,16 +0,0 @@ --- Verify camper:company_geography on pg - -begin; - -select company_id - , geog -from camper.company_geography -where false; - -select 1 / count(*) from pg_class where oid = 'camper.company_geography'::regclass and relrowsecurity; -select 1 / count(*) from pg_policy where polname = 'guest_ok' and polrelid = 'camper.company_geography'::regclass; -select 1 / count(*) from pg_policy where polname = 'insert_to_company' and polrelid = 'camper.company_geography'::regclass; -select 1 / count(*) from pg_policy where polname = 'update_company' and polrelid = 'camper.company_geography'::regclass; -select 1 / count(*) from pg_policy where polname = 'delete_from_company' and polrelid = 'camper.company_geography'::regclass; - -rollback; diff --git a/verify/extension_postgis.sql b/verify/extension_postgis.sql deleted file mode 100644 index d46342a..0000000 --- a/verify/extension_postgis.sql +++ /dev/null @@ -1,10 +0,0 @@ --- Verify camper:extension_postgis on pg - -begin; - -select 1 / count(*) -from pg_extension -where extname = 'postgis' -; - -rollback; diff --git a/verify/location.sql b/verify/location.sql new file mode 100644 index 0000000..4869e54 --- /dev/null +++ b/verify/location.sql @@ -0,0 +1,18 @@ +-- Verify camper:location on pg + +begin; + +select company_id + , directions + , map_embed + , opening_dates +from camper.location +where false; + +select 1 / count(*) from pg_class where oid = 'camper.location'::regclass and relrowsecurity; +select 1 / count(*) from pg_policy where polname = 'guest_ok' and polrelid = 'camper.location'::regclass; +select 1 / count(*) from pg_policy where polname = 'insert_to_company' and polrelid = 'camper.location'::regclass; +select 1 / count(*) from pg_policy where polname = 'update_company' and polrelid = 'camper.location'::regclass; +select 1 / count(*) from pg_policy where polname = 'delete_from_company' and polrelid = 'camper.location'::regclass; + +rollback; diff --git a/verify/location_i18n.sql b/verify/location_i18n.sql new file mode 100644 index 0000000..3796e54 --- /dev/null +++ b/verify/location_i18n.sql @@ -0,0 +1,12 @@ +-- Verify camper:location_i18n on pg + +begin; + +select company_id + , lang_tag + , directions + , opening_dates +from camper.location_i18n +where false; + +rollback; diff --git a/verify/setup_location.sql b/verify/setup_location.sql new file mode 100644 index 0000000..c2f0bdc --- /dev/null +++ b/verify/setup_location.sql @@ -0,0 +1,7 @@ +-- Verify camper:setup_location on pg + +begin; + +select has_function_privilege('camper.setup_location(integer, text, text, text)', 'execute'); + +rollback; diff --git a/verify/translate_location.sql b/verify/translate_location.sql new file mode 100644 index 0000000..4515a04 --- /dev/null +++ b/verify/translate_location.sql @@ -0,0 +1,7 @@ +-- Verify camper:translate_location on pg + +begin; + +select has_function_privilege('camper.translate_location(integer, text, text, text)', 'execute'); + +rollback; diff --git a/web/static/alpinejs@3.13.3.min.js b/web/static/alpinejs@3.13.3.min.js new file mode 100644 index 0000000..af7df64 --- /dev/null +++ b/web/static/alpinejs@3.13.3.min.js @@ -0,0 +1,5 @@ +(()=>{var tt=!1,rt=!1,V=[],nt=-1;function Vt(e){Sn(e)}function Sn(e){V.includes(e)||V.push(e),An()}function Ee(e){let t=V.indexOf(e);t!==-1&&t>nt&&V.splice(t,1)}function An(){!rt&&!tt&&(tt=!0,queueMicrotask(On))}function On(){tt=!1,rt=!0;for(let e=0;ee.effect(t,{scheduler:r=>{it?Vt(r):r()}}),ot=e.raw}function st(e){k=e}function Wt(e){let t=()=>{};return[n=>{let i=k(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),$(i))},i},()=>{t()}]}function q(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}function O(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>O(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)O(n,t,!1),n=n.nextElementSibling}function v(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var Gt=!1;function Jt(){Gt&&v("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),Gt=!0,document.body||v("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` + {{ block "head" . }}{{ end }} @@ -55,6 +56,9 @@
  • {{( pgettext "Services Page" "title" )}}
  • +
  • + {{( pgettext "Location" "title" )}} +
  • {{- end }}
  • + {{- end }} +
  • + {{ range $lang, $input := . -}} + + {{- end }} + {{ template "error-message" . }} + + {{- end }} + {{ with .OpeningDates -}} +
    + {{( pgettext "Opening Dates" "input" )}} + + {{ range $lang, $input := . -}} + + {{- end }} + {{ template "error-message" . }} +
    + {{- end }} + {{ with .MapEmbed -}} + + {{- end }} + +
    + +
    + +{{- end }} diff --git a/web/templates/public/contact.gohtml b/web/templates/public/contact.gohtml deleted file mode 100644 index 7d6391f..0000000 --- a/web/templates/public/contact.gohtml +++ /dev/null @@ -1,62 +0,0 @@ - -{{ define "title" -}} - {{( pgettext "Contact" "title" )}} -{{- end }} - -{{ define "head" -}} - -{{- end }} - -{{ define "content" -}} - {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/app.contactPage*/ -}} - -
    -
    -

    {{( pgettext "Contact" "title" )}}

    - - {{ template "companyAddress" .PublicPage.CompanyAddress }} -

    GPS: 42º 14’ 43,86’’ / 2º 35’ 58,26’’

    -
    - -
    -
    - - {{ if .CompanyGeography -}} - - - {{- end }} -{{- end }} diff --git a/web/templates/public/layout.gohtml b/web/templates/public/layout.gohtml index e11d669..4b696d1 100644 --- a/web/templates/public/layout.gohtml +++ b/web/templates/public/layout.gohtml @@ -50,7 +50,7 @@ {{- end }}
  • {{( pgettext "Services" "title" )}}
  • {{( pgettext "Surroundings" "title" )}}
  • -
  • {{( pgettext "Contact" "title" )}}
  • +
  • {{( pgettext "Location" "title" )}}
  • {{( pgettext "Booking" "title" )}}
  • {{ if .LocalizedAlternates -}}
  • {{ range .LocalizedAlternates -}} @@ -78,7 +78,7 @@
  • {{( pgettext "Campground" "title" )}}
  • {{( pgettext "Services" "title" )}}
  • {{( pgettext "Surroundings" "title" )}}
  • -
  • {{( pgettext "Contact" "title" )}}
  • +
  • {{( pgettext "Location" "title" )}}
  • @@ -96,9 +96,8 @@ {{- end }}
    -

    Obertura 2023

    -

    Camping i Safari tents:
    de 08/04 a 09/10

    -

    Cabanes i Bungalows:
    de 08/04 a 11/12

    +

    {{ (pgettext "Opening" "title" )}}

    + {{ .OpeningDates }}
    diff --git a/web/templates/public/location.gohtml b/web/templates/public/location.gohtml new file mode 100644 index 0000000..97480c4 --- /dev/null +++ b/web/templates/public/location.gohtml @@ -0,0 +1,21 @@ + +{{ define "title" -}} + {{( pgettext "Location" "title" )}} +{{- end }} + +{{ define "content" -}} + {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/location.locationPage*/ -}} + +

    {{( pgettext "Location" "title" )}}

    +
    +
    + + {{ .Directions }} +
    + + {{ .MapEmbed }} +
    +{{- end }}