Add ad management for surroundings

They only want a single ad (for now, i guess).
This commit is contained in:
jordi fita mas 2024-01-23 14:53:15 +01:00
parent e34f253620
commit f514f9132e
32 changed files with 1335 additions and 142 deletions

BIN
demo/ad.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -73,6 +73,7 @@ select add_media(52, 'wooden_lodges_carousel9.avif', 'image/avif', decode('m4_es
select add_media(52, 'wooden_lodges_carouselA.avif', 'image/avif', decode('m4_esyscmd([[base64 -w0 demo/wooden_lodges_carouselA.avif]])', 'base64')); select add_media(52, 'wooden_lodges_carouselA.avif', 'image/avif', decode('m4_esyscmd([[base64 -w0 demo/wooden_lodges_carouselA.avif]])', 'base64'));
select add_media(52, 'wooden_lodges_carouselB.avif', 'image/avif', decode('m4_esyscmd([[base64 -w0 demo/wooden_lodges_carouselB.avif]])', 'base64')); select add_media(52, 'wooden_lodges_carouselB.avif', 'image/avif', decode('m4_esyscmd([[base64 -w0 demo/wooden_lodges_carouselB.avif]])', 'base64'));
select add_media(52, 'wooden_lodges_carouselC.avif', 'image/avif', decode('m4_esyscmd([[base64 -w0 demo/wooden_lodges_carouselC.avif]])', 'base64')); select add_media(52, 'wooden_lodges_carouselC.avif', 'image/avif', decode('m4_esyscmd([[base64 -w0 demo/wooden_lodges_carouselC.avif]])', 'base64'));
select add_media(52, 'ad.avif', 'image/avif', decode('m4_esyscmd([[base64 -w0 demo/ad.avif]])', 'base64'));
select setup_home(52, 'Vine a gaudir!'); select setup_home(52, 'Vine a gaudir!');
@ -659,6 +660,11 @@ select translate_surroundings_highlight(120, 'fr', 'Pyrénées', '<p>Pyrénées
select translate_surroundings_highlight(121, 'fr', 'Gérone', '<p>Visite incontournable, principalement: le quartier juifs, les Rambles, la cathédrale et les jardins qui lentourent … Sans oublier ses nombreuses boutiques !</p><p><a href="https://www.girona.cat/turisme/fra/">Turisme Girona</a></p>'); select translate_surroundings_highlight(121, 'fr', 'Gérone', '<p>Visite incontournable, principalement: le quartier juifs, les Rambles, la cathédrale et les jardins qui lentourent … Sans oublier ses nombreuses boutiques !</p><p><a href="https://www.girona.cat/turisme/fra/">Turisme Girona</a></p>');
select translate_surroundings_highlight(122, 'fr', 'Barcelone', '<p>Barcelone cest plus que des boutiques et le Barça … Découvrez la richesse de ces quartiers: Gràcia, Barceloneta, …</p><p><a href="https://www.barcelonaturisme.com/wv3/fr/">Turisme Barcelona</a></p>'); select translate_surroundings_highlight(122, 'fr', 'Barcelone', '<p>Barcelone cest plus que des boutiques et le Barça … Découvrez la richesse de ces quartiers: Gràcia, Barceloneta, …</p><p><a href="https://www.barcelonaturisme.com/wv3/fr/">Turisme Barcelona</a></p>');
select setup_surroundings_ad(52, 104, 'Vine a fer barranquisme per Sadernes!', 'Reserva el teu dia', 'https://www.guiesarania.com/ca/activitats/barrancs-de-perfeccionament/barranc-de-sant-aniol/');
select translate_surroundings_ad(52, 'en', 'Canyoneering in Sadernes!', 'Book your day');
select translate_surroundings_ad(52, 'es', '¡Ven a hacer barranquismo en Sadernes!', 'Reserva tu día');
select translate_surroundings_ad(52, 'fr', 'Venez faire du canyoning à Sadernes !', 'Réservez votre journée');
alter table booking alter column booking_id restart with 122; alter table booking alter column booking_id restart with 122;
insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card, booking_status) insert into booking (company_id, campsite_type_id, holder_name, arrival_date, departure_date, number_dogs, acsi_card, booking_status)

View File

@ -0,0 +1,22 @@
-- Deploy camper:remove_surroundings_ad to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_ad
-- requires: surroundings_ad_i18n
begin;
set search_path to camper, public;
create or replace function remove_surroundings_ad(company_id integer) returns void as
$$
delete from surroundings_ad_i18n where company_id = remove_surroundings_ad.company_id;
delete from surroundings_ad where company_id = remove_surroundings_ad.company_id;
$$
language sql
;
revoke execute on function remove_surroundings_ad(integer) from public;
grant execute on function remove_surroundings_ad(integer) to admin;
commit;

View File

@ -0,0 +1,28 @@
-- Deploy camper:setup_surroundings_ad to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_ad
begin;
set search_path to camper, public;
create or replace function setup_surroundings_ad(company integer, media_id integer, title text, anchor text, href uri) returns void as
$$
insert into surroundings_ad (company_id, media_id, title, anchor, href)
values (company, media_id, title, anchor, href)
on conflict (company_id)
do update
set media_id = excluded.media_id
, title = excluded.title
, anchor = excluded.anchor
, href = excluded.href
;
$$
language sql
;
revoke execute on function setup_surroundings_ad(integer, integer, text, text, uri) from public;
grant execute on function setup_surroundings_ad(integer, integer, text, text, uri) to admin;
commit;

View File

@ -0,0 +1,55 @@
-- Deploy camper:surroundings_ad to pg
-- requires: roles
-- requires: schema_camper
-- requires: company
-- requires: user_profile
begin;
set search_path to camper, public;
create table surroundings_ad (
company_id integer not null primary key references company,
media_id integer not null references media,
title text not null,
anchor text not null,
href uri not null
);
grant select on table surroundings_ad to guest;
grant select on table surroundings_ad to employee;
grant select, insert, update, delete on table surroundings_ad to admin;
alter table surroundings_ad enable row level security;
create policy guest_ok
on surroundings_ad
for select
using (true)
;
create policy insert_to_company
on surroundings_ad
for insert
with check (
company_id in (select company_id from user_profile)
)
;
create policy update_company
on surroundings_ad
for update
using (
company_id in (select company_id from user_profile)
)
;
create policy delete_from_company
on surroundings_ad
for delete
using (
company_id in (select company_id from user_profile)
)
;
commit;

View File

@ -0,0 +1,23 @@
-- Deploy camper:surroundings_ad_i18n to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_ad
-- requires: language
begin;
set search_path to camper, public;
create table surroundings_ad_i18n (
company_id integer not null references surroundings_ad,
lang_tag text not null references language,
title text not null,
anchor text not null,
primary key (company_id, lang_tag)
);
grant select on table surroundings_ad_i18n to guest;
grant select on table surroundings_ad_i18n to employee;
grant select, insert, update, delete on table surroundings_ad_i18n to admin;
commit;

View File

@ -0,0 +1,26 @@
-- Deploy camper:translate_surroundings_ad to pg
-- requires: roles
-- requires: schema_camper
-- requires: surroundings_ad_i18n
begin;
set search_path to camper, public;
create or replace function translate_surroundings_ad(company_id integer, lang_tag text, title text, anchor text) returns void as
$$
insert into surroundings_ad_i18n (company_id, lang_tag, title, anchor)
values (company_id, lang_tag, title, anchor)
on conflict (company_id, lang_tag)
do update
set title = excluded.title
, anchor = excluded.anchor
;
$$
language sql
;
revoke execute on function translate_surroundings_ad(integer, text, text, text) from public;
grant execute on function translate_surroundings_ad(integer, text, text, text) to admin;
commit;

View File

@ -190,6 +190,21 @@ func (c *Conn) RemoveSurroundingsHighlight(ctx context.Context, id int) error {
return err return err
} }
func (tx *Tx) SetupSurroundingsAd(ctx context.Context, companyID int, mediaID int, title string, anchor string, href string) error {
_, err := tx.Exec(ctx, "select setup_surroundings_ad($1, $2, $3, $4, $5)", companyID, mediaID, title, anchor, href)
return err
}
func (tx *Tx) TranslateSurroundingsAd(ctx context.Context, companyID int, langTag language.Tag, title string, anchor string) error {
_, err := tx.Exec(ctx, "select translate_surroundings_ad($1, $2, $3, $4)", companyID, langTag, title, anchor)
return err
}
func (c *Conn) RemoveSurroundingsAd(ctx context.Context, companyID int) error {
_, err := c.Exec(ctx, "select remove_surroundings_ad($1)", companyID)
return err
}
func (tx *Tx) SetupHome(ctx context.Context, companyID int, slogan string) error { func (tx *Tx) SetupHome(ctx context.Context, companyID int, slogan string) error {
_, err := tx.Exec(ctx, "select setup_home($1, $2)", companyID, slogan) _, err := tx.Exec(ctx, "select setup_home($1, $2)", companyID, slogan)
return err return err

View File

@ -57,6 +57,15 @@ func (h *AdminHandler) Handler(user *auth.User, company *auth.Company, conn *dat
default: default:
httplib.MethodNotAllowed(w, r, http.MethodPost) httplib.MethodNotAllowed(w, r, http.MethodPost)
} }
case "ad":
switch r.Method {
case http.MethodPut:
updateAd(w, r, user, company, conn)
case http.MethodDelete:
removeAd(w, r, company, conn)
default:
httplib.MethodNotAllowed(w, r, http.MethodPut, http.MethodDelete)
}
default: default:
id, err := strconv.Atoi(head) id, err := strconv.Atoi(head)
if err != nil { if err != nil {
@ -120,17 +129,27 @@ func orderHighlights(w http.ResponseWriter, r *http.Request, user *auth.User, co
} }
func serveHighlightsIndex(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { func serveHighlightsIndex(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
f := newAdForm(company)
if err := f.FillFromDatabase(r.Context(), company, conn); err != nil && !database.ErrorIsNotFound(err) {
panic(err)
}
serveHighlightsIndexWithForm(w, r, user, company, conn, f)
}
func serveHighlightsIndexWithForm(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn, f *adForm) {
highlights, err := collectHighlightEntries(r.Context(), company, conn) highlights, err := collectHighlightEntries(r.Context(), company, conn)
if err != nil { if err != nil {
panic(err) panic(err)
} }
page := &highlightIndex{ page := &highlightIndex{
Ad: f,
Highlights: highlights, Highlights: highlights,
} }
page.MustRender(w, r, user, company) page.MustRender(w, r, user, company)
} }
type highlightIndex struct { type highlightIndex struct {
Ad *adForm
Highlights []*highlightEntry Highlights []*highlightEntry
} }
@ -325,3 +344,127 @@ func (f *highlightForm) Valid(ctx context.Context, conn *database.Conn, l *local
func (f *highlightForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) { func (f *highlightForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
template.MustRenderAdmin(w, r, user, company, "surroundings/form.gohtml", f) template.MustRenderAdmin(w, r, user, company, "surroundings/form.gohtml", f)
} }
func updateAd(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
f := newAdForm(company)
if err := f.Parse(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := user.VerifyCSRFToken(r); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
if ok, err := f.Valid(r.Context(), conn, user.Locale); err != nil {
panic(err)
} else if !ok {
if !httplib.IsHTMxRequest(r) {
w.WriteHeader(http.StatusUnprocessableEntity)
}
serveHighlightsIndexWithForm(w, r, user, company, conn, f)
return
}
tx := conn.MustBegin(r.Context())
defer tx.Rollback(r.Context())
if err := tx.SetupSurroundingsAd(r.Context(), company.ID, f.Media.Int(), f.Title[f.DefaultLang].Val, f.Anchor[f.DefaultLang].Val, f.HRef.Val); err != nil {
panic(err)
}
for lang := range company.Locales {
l := lang.String()
if l == f.DefaultLang {
continue
}
if err := tx.TranslateSurroundingsAd(r.Context(), company.ID, lang, f.Title[l].Val, f.Anchor[l].Val); err != nil {
panic(err)
}
}
tx.MustCommit(r.Context())
httplib.Redirect(w, r, "/admin/surroundings", http.StatusSeeOther)
}
func removeAd(w http.ResponseWriter, r *http.Request, company *auth.Company, conn *database.Conn) {
if err := conn.RemoveSurroundingsAd(r.Context(), company.ID); err != nil {
panic(err)
}
httplib.Redirect(w, r, "/admin/surroundings", http.StatusSeeOther)
}
type adForm struct {
DefaultLang string
Media *form.Media
Title form.I18nInput
Anchor form.I18nInput
HRef *form.Input
}
func newAdForm(company *auth.Company) *adForm {
return &adForm{
DefaultLang: company.DefaultLanguage.String(),
Media: &form.Media{
Input: &form.Input{
Name: "media",
},
Label: locale.PgettextNoop("Ad image", "input"),
Prompt: locale.PgettextNoop("Set ad image", "action"),
},
Title: form.NewI18nInput(company.Locales, "title"),
Anchor: form.NewI18nInput(company.Locales, "anchor"),
HRef: &form.Input{Name: "href"},
}
}
func (f *adForm) FillFromDatabase(ctx context.Context, company *auth.Company, conn *database.Conn) error {
var titles database.RecordArray
var anchors database.RecordArray
err := conn.QueryRow(ctx, `
select ad.media_id::text
, ad.title
, ad.anchor
, ad.href::text
, array_agg((lang_tag, i18n.title))
, array_agg((lang_tag, i18n.anchor))
from surroundings_ad as ad
left join surroundings_ad_i18n as i18n using (company_id)
where company_id = $1
group by ad.media_id
, ad.title
, ad.anchor
, ad.href
`, pgx.QueryResultFormats{pgx.BinaryFormatCode}, company.ID).Scan(&f.Media.Val, &f.Title[f.DefaultLang].Val, &f.Anchor[f.DefaultLang].Val, &f.HRef.Val, &titles, &anchors)
if err != nil {
return err
}
if err := f.Title.FillArray(titles); err != nil {
return err
}
if err := f.Anchor.FillArray(anchors); err != nil {
return err
}
return nil
}
func (f *adForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
f.Media.FillValue(r)
f.Title.FillValue(r)
f.Anchor.FillValue(r)
f.HRef.FillValue(r)
return nil
}
func (f *adForm) Valid(ctx context.Context, conn *database.Conn, l *locale.Locale) (bool, error) {
v := form.NewValidator(l)
if v.CheckRequired(f.Media.Input, l.GettextNoop("Ad image can not be empty.")) {
if _, err := v.CheckImageMedia(ctx, conn, f.Media.Input, l.GettextNoop("Ad image must be an image media type.")); err != nil {
return false, err
}
}
v.CheckRequired(f.Title[f.DefaultLang], l.GettextNoop("The title can not be empty."))
v.CheckRequired(f.Anchor[f.DefaultLang], l.GettextNoop("The link text can not be empty."))
if v.CheckRequired(f.HRef, l.GettextNoop("The ad URL can not be empty")) {
v.CheckValidURL(f.HRef, l.GettextNoop("This web address is not valid. It should be like https://domain.com/."))
}
return v.AllOK, nil
}

View File

@ -45,6 +45,7 @@ func (h *PublicHandler) Handler(user *auth.User, company *auth.Company, conn *da
type surroundingsPage struct { type surroundingsPage struct {
*template.PublicPage *template.PublicPage
Ad *surroundingsAd
Highlights []*highlight Highlights []*highlight
} }
@ -55,6 +56,7 @@ func newSurroundingsPage() *surroundingsPage {
func (p *surroundingsPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) { func (p *surroundingsPage) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
p.Setup(r, user, company, conn) p.Setup(r, user, company, conn)
p.Highlights = mustCollectSurroundings(r.Context(), company, conn, user.Locale) p.Highlights = mustCollectSurroundings(r.Context(), company, conn, user.Locale)
p.Ad = mustCollectAd(r.Context(), company, conn, user.Locale)
template.MustRenderPublic(w, r, user, company, "surroundings.gohtml", p) template.MustRenderPublic(w, r, user, company, "surroundings.gohtml", p)
} }
@ -96,3 +98,31 @@ func mustCollectSurroundings(ctx context.Context, company *auth.Company, conn *d
return items return items
} }
type surroundingsAd struct {
MediaURL string
Title string
Anchor string
HRef string
}
func mustCollectAd(ctx context.Context, company *auth.Company, conn *database.Conn, loc *locale.Locale) *surroundingsAd {
ad := &surroundingsAd{}
err := conn.QueryRow(ctx, `
select media.path
, coalesce(i18n.title, ad.title) as l10_title
, coalesce(i18n.anchor, ad.anchor) as l10_anchor
, href::text
from surroundings_ad as ad
join media using (media_id)
left join surroundings_ad_i18n as i18n on ad.company_id = i18n.company_id and lang_tag = $1
where ad.company_id = $2
`, loc.Language, company.ID).Scan(&ad.MediaURL, &ad.Title, &ad.Anchor, &ad.HRef)
if err != nil {
if database.ErrorIsNotFound(err) {
return nil
}
panic(err)
}
return ad
}

114
po/ca.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-23 11:46+0100\n" "POT-Creation-Date: 2024-01-23 14:38+0100\n"
"PO-Revision-Date: 2023-07-22 23:45+0200\n" "PO-Revision-Date: 2023-07-22 23:45+0200\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n" "Language-Team: Catalan <ca@dodds.net>\n"
@ -241,45 +241,45 @@ msgctxt "day"
msgid "Sun" msgid "Sun"
msgstr "dg" msgstr "dg"
#: web/templates/public/surroundings.gohtml:32 #: web/templates/public/surroundings.gohtml:30
msgctxt "title" msgctxt "title"
msgid "What to Do Outside the Campsite?" msgid "What to Do Outside the Campsite?"
msgstr "Què fer des del càmping?" msgstr "Què fer des del càmping?"
#: web/templates/public/surroundings.gohtml:52 #: web/templates/public/surroundings.gohtml:50
msgctxt "title" msgctxt "title"
msgid "Once at the Campsite, We Can Inform You about What Activities are Available" msgid "Once at the Campsite, We Can Inform You about What Activities are Available"
msgstr "Un cop en el càmping, us podem informar de quines activitats fer" msgstr "Un cop en el càmping, us podem informar de quines activitats fer"
#: web/templates/public/surroundings.gohtml:55 #: web/templates/public/surroundings.gohtml:53
msgid "Cycle routes" msgid "Cycle routes"
msgstr "Rutes amb bicicleta" msgstr "Rutes amb bicicleta"
#: web/templates/public/surroundings.gohtml:56 #: web/templates/public/surroundings.gohtml:54
msgid "There are many bicycle rental companies in Olot." msgid "There are many bicycle rental companies in Olot."
msgstr "A Olot podeu trobar empreses de lloguer de bicicletes." msgstr "A Olot podeu trobar empreses de lloguer de bicicletes."
#: web/templates/public/surroundings.gohtml:60 #: web/templates/public/surroundings.gohtml:58
msgid "Routes" msgid "Routes"
msgstr "Rutes" msgstr "Rutes"
#: web/templates/public/surroundings.gohtml:61 #: web/templates/public/surroundings.gohtml:59
msgid "Routes of all kinds, climbing, mountain passes, for all levels." msgid "Routes of all kinds, climbing, mountain passes, for all levels."
msgstr "Rutes de tota mena, escalada, ports de muntanya, per a tots els nivells." msgstr "Rutes de tota mena, escalada, ports de muntanya, per a tots els nivells."
#: web/templates/public/surroundings.gohtml:65 #: web/templates/public/surroundings.gohtml:63
msgid "Family outing" msgid "Family outing"
msgstr "Excursions familiars" msgstr "Excursions familiars"
#: web/templates/public/surroundings.gohtml:66 #: web/templates/public/surroundings.gohtml:64
msgid "Many outing possibilities, for all ages." msgid "Many outing possibilities, for all ages."
msgstr "Múltiples excursions per a totes les edats." msgstr "Múltiples excursions per a totes les edats."
#: web/templates/public/surroundings.gohtml:70 #: web/templates/public/surroundings.gohtml:68
msgid "Kayak" msgid "Kayak"
msgstr "Caiac" msgstr "Caiac"
#: web/templates/public/surroundings.gohtml:71 #: web/templates/public/surroundings.gohtml:69
msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…." msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…."
msgstr "Hi ha diversos punts on poder anar amb caiac, des de trams del riu Ter com també a la costa…." msgstr "Hi ha diversos punts on poder anar amb caiac, des de trams del riu Ter com també a la costa…."
@ -475,6 +475,7 @@ msgstr "Contingut"
#: web/templates/admin/season/form.gohtml:73 #: web/templates/admin/season/form.gohtml:73
#: web/templates/admin/services/form.gohtml:80 #: web/templates/admin/services/form.gohtml:80
#: web/templates/admin/surroundings/form.gohtml:69 #: web/templates/admin/surroundings/form.gohtml:69
#: web/templates/admin/surroundings/index.gohtml:58
#: web/templates/admin/home/index.gohtml:34 #: web/templates/admin/home/index.gohtml:34
#: web/templates/admin/media/form.gohtml:39 #: web/templates/admin/media/form.gohtml:39
msgctxt "action" msgctxt "action"
@ -506,7 +507,7 @@ msgstr "Afegeix text legal"
#: web/templates/admin/campsite/type/index.gohtml:29 #: web/templates/admin/campsite/type/index.gohtml:29
#: web/templates/admin/season/index.gohtml:29 #: web/templates/admin/season/index.gohtml:29
#: web/templates/admin/user/index.gohtml:20 #: web/templates/admin/user/index.gohtml:20
#: web/templates/admin/surroundings/index.gohtml:29 #: web/templates/admin/surroundings/index.gohtml:83
msgctxt "header" msgctxt "header"
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
@ -636,7 +637,7 @@ msgstr "Afegeix diapositiva"
#: web/templates/admin/campsite/carousel/index.gohtml:30 #: web/templates/admin/campsite/carousel/index.gohtml:30
#: web/templates/admin/services/index.gohtml:28 #: web/templates/admin/services/index.gohtml:28
#: web/templates/admin/surroundings/index.gohtml:28 #: web/templates/admin/surroundings/index.gohtml:82
#: web/templates/admin/home/index.gohtml:52 #: web/templates/admin/home/index.gohtml:52
#: web/templates/admin/home/index.gohtml:97 #: web/templates/admin/home/index.gohtml:97
msgctxt "header" msgctxt "header"
@ -656,7 +657,7 @@ msgstr "Llegenda"
#: web/templates/admin/services/index.gohtml:30 #: web/templates/admin/services/index.gohtml:30
#: web/templates/admin/services/index.gohtml:75 #: web/templates/admin/services/index.gohtml:75
#: web/templates/admin/user/index.gohtml:23 #: web/templates/admin/user/index.gohtml:23
#: web/templates/admin/surroundings/index.gohtml:30 #: web/templates/admin/surroundings/index.gohtml:84
#: web/templates/admin/home/index.gohtml:54 #: web/templates/admin/home/index.gohtml:54
#: web/templates/admin/home/index.gohtml:99 #: web/templates/admin/home/index.gohtml:99
msgctxt "header" msgctxt "header"
@ -674,7 +675,8 @@ msgstr "Esteu segur de voler esborrar aquesta diapositiva?"
#: web/templates/admin/services/index.gohtml:47 #: web/templates/admin/services/index.gohtml:47
#: web/templates/admin/services/index.gohtml:91 #: web/templates/admin/services/index.gohtml:91
#: web/templates/admin/user/index.gohtml:37 #: web/templates/admin/user/index.gohtml:37
#: web/templates/admin/surroundings/index.gohtml:47 #: web/templates/admin/surroundings/index.gohtml:63
#: web/templates/admin/surroundings/index.gohtml:101
#: web/templates/admin/home/index.gohtml:71 #: web/templates/admin/home/index.gohtml:71
#: web/templates/admin/home/index.gohtml:116 #: web/templates/admin/home/index.gohtml:116
msgctxt "action" msgctxt "action"
@ -1209,19 +1211,43 @@ msgstr "Pàgina de lentorn"
#: web/templates/admin/surroundings/index.gohtml:14 #: web/templates/admin/surroundings/index.gohtml:14
msgctxt "title" msgctxt "title"
msgid "Ad"
msgstr "Anunci"
#: web/templates/admin/surroundings/index.gohtml:21
msgctxt "input"
msgid "Title"
msgstr "Títol"
#: web/templates/admin/surroundings/index.gohtml:37
msgctxt "input"
msgid "Link Text"
msgstr "Text de lenllaç"
#: web/templates/admin/surroundings/index.gohtml:50
msgctxt "input"
msgid "Link URL"
msgstr "Adreça de lenllaç"
#: web/templates/admin/surroundings/index.gohtml:59
msgid "Are you sure you wish to delete the ad?"
msgstr "Esteu segur de voler esborrar aquest anunci?"
#: web/templates/admin/surroundings/index.gohtml:68
msgctxt "title"
msgid "Highlights" msgid "Highlights"
msgstr "Punts dinterès" msgstr "Punts dinterès"
#: web/templates/admin/surroundings/index.gohtml:15 #: web/templates/admin/surroundings/index.gohtml:69
msgctxt "action" msgctxt "action"
msgid "Add highlight" msgid "Add highlight"
msgstr "Afegeix punt dinterès" msgstr "Afegeix punt dinterès"
#: web/templates/admin/surroundings/index.gohtml:34 #: web/templates/admin/surroundings/index.gohtml:88
msgid "Are you sure you wish to delete this highlight?" msgid "Are you sure you wish to delete this highlight?"
msgstr "Esteu segur de voler esborrar aquest punt dinterès?" msgstr "Esteu segur de voler esborrar aquest punt dinterès?"
#: web/templates/admin/surroundings/index.gohtml:56 #: web/templates/admin/surroundings/index.gohtml:110
msgid "No highlights added yet." msgid "No highlights added yet."
msgstr "No sha afegit cap punt dinterès encara." msgstr "No sha afegit cap punt dinterès encara."
@ -1441,7 +1467,7 @@ msgstr "No sha trobat cap reserva."
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357 #: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:483 #: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:483
#: pkg/season/admin.go:412 pkg/services/admin.go:316 #: pkg/season/admin.go:412 pkg/services/admin.go:316
#: pkg/surroundings/admin.go:321 #: pkg/surroundings/admin.go:340
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc." msgstr "No podeu deixar el nom en blanc."
@ -1461,12 +1487,12 @@ msgid "Set slide image"
msgstr "Estableix la imatge de la diapositiva" msgstr "Estableix la imatge de la diapositiva"
#: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299 #: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299
#: pkg/surroundings/admin.go:316 #: pkg/surroundings/admin.go:335
msgid "Slide image can not be empty." msgid "Slide image can not be empty."
msgstr "No podeu deixar la imatge de la diapositiva en blanc." msgstr "No podeu deixar la imatge de la diapositiva en blanc."
#: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300 #: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300
#: pkg/surroundings/admin.go:317 #: pkg/surroundings/admin.go:336
msgid "Slide image must be an image media type." msgid "Slide image must be an image media type."
msgstr "La imatge de la diapositiva ha de ser un mèdia de tipus imatge." msgstr "La imatge de la diapositiva ha de ser un mèdia de tipus imatge."
@ -1711,16 +1737,50 @@ msgctxt "role"
msgid "admin" msgid "admin"
msgstr "administrador" msgstr "administrador"
#: pkg/surroundings/admin.go:267 #: pkg/surroundings/admin.go:286
msgctxt "input" msgctxt "input"
msgid "Highlight image" msgid "Highlight image"
msgstr "Imatge del punt dinterès" msgstr "Imatge del punt dinterès"
#: pkg/surroundings/admin.go:268 #: pkg/surroundings/admin.go:287
msgctxt "action" msgctxt "action"
msgid "Set highlight image" msgid "Set highlight image"
msgstr "Estableix la imatge del punt dinterès" msgstr "Estableix la imatge del punt dinterès"
#: pkg/surroundings/admin.go:407
msgctxt "input"
msgid "Ad image"
msgstr "Imatge de lanunci"
#: pkg/surroundings/admin.go:408
msgctxt "action"
msgid "Set ad image"
msgstr "Estableix la imatge de lanunci"
#: pkg/surroundings/admin.go:459
msgid "Ad image can not be empty."
msgstr "No podeu deixar la imatge de lanunci en blanc."
#: pkg/surroundings/admin.go:460
msgid "Ad image must be an image media type."
msgstr "La imatge de lanunci ha de ser un mèdia de tipus imatge."
#: pkg/surroundings/admin.go:464
msgid "The title can not be empty."
msgstr "No podeu deixar el títol en blanc."
#: pkg/surroundings/admin.go:465
msgid "The link text can not be empty."
msgstr "No podeu deixar el text de lenllaç en blanc."
#: pkg/surroundings/admin.go:466
msgid "The ad URL can not be empty"
msgstr "No podeu deixar ladreça de lenllaç en blanc."
#: pkg/surroundings/admin.go:467 pkg/company/admin.go:221
msgid "This web address is not valid. It should be like https://domain.com/."
msgstr "Aquesta adreça web no és vàlida. Hauria de ser similar a https://domini.com/."
#: pkg/company/admin.go:200 pkg/booking/public.go:256 #: pkg/company/admin.go:200 pkg/booking/public.go:256
msgid "Selected country is not valid." msgid "Selected country is not valid."
msgstr "El país escollit no és vàlid." msgstr "El país escollit no és vàlid."
@ -1749,10 +1809,6 @@ msgstr "No podeu deixar el telèfon en blanc."
msgid "This phone number is not valid." msgid "This phone number is not valid."
msgstr "Aquest número de telèfon no és vàlid." msgstr "Aquest número de telèfon no és vàlid."
#: pkg/company/admin.go:221
msgid "This web address is not valid. It should be like https://domain.com/."
msgstr "Aquesta adreça web no és vàlida. Hauria de ser similar a https://domini.com/."
#: pkg/company/admin.go:223 #: pkg/company/admin.go:223
msgid "Address can not be empty." msgid "Address can not be empty."
msgstr "No podeu deixar ladreça en blanc." msgstr "No podeu deixar ladreça en blanc."
@ -2057,10 +2113,6 @@ msgstr "El valor de %s ha de ser com a màxim %d."
#~ msgid "Legend" #~ msgid "Legend"
#~ msgstr "Llegenda" #~ msgstr "Llegenda"
#~ msgctxt "input"
#~ msgid "Title"
#~ msgstr "Títol"
#~ msgctxt "title" #~ msgctxt "title"
#~ msgid "Pages" #~ msgid "Pages"
#~ msgstr "Pàgines" #~ msgstr "Pàgines"

114
po/es.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-23 11:46+0100\n" "POT-Creation-Date: 2024-01-23 14:38+0100\n"
"PO-Revision-Date: 2023-07-22 23:46+0200\n" "PO-Revision-Date: 2023-07-22 23:46+0200\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n" "Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n" "Language-Team: Spanish <es@tp.org.es>\n"
@ -241,45 +241,45 @@ msgctxt "day"
msgid "Sun" msgid "Sun"
msgstr "do" msgstr "do"
#: web/templates/public/surroundings.gohtml:32 #: web/templates/public/surroundings.gohtml:30
msgctxt "title" msgctxt "title"
msgid "What to Do Outside the Campsite?" msgid "What to Do Outside the Campsite?"
msgstr "¿Qué hacer desde el camping?" msgstr "¿Qué hacer desde el camping?"
#: web/templates/public/surroundings.gohtml:52 #: web/templates/public/surroundings.gohtml:50
msgctxt "title" msgctxt "title"
msgid "Once at the Campsite, We Can Inform You about What Activities are Available" msgid "Once at the Campsite, We Can Inform You about What Activities are Available"
msgstr "Una vez en el camping, os podemos informar de qué actividades hacer" msgstr "Una vez en el camping, os podemos informar de qué actividades hacer"
#: web/templates/public/surroundings.gohtml:55 #: web/templates/public/surroundings.gohtml:53
msgid "Cycle routes" msgid "Cycle routes"
msgstr "Rutas en bicicleta" msgstr "Rutas en bicicleta"
#: web/templates/public/surroundings.gohtml:56 #: web/templates/public/surroundings.gohtml:54
msgid "There are many bicycle rental companies in Olot." msgid "There are many bicycle rental companies in Olot."
msgstr "A Olot podéis encontrar empresas de alquiler de bicicletas." msgstr "A Olot podéis encontrar empresas de alquiler de bicicletas."
#: web/templates/public/surroundings.gohtml:60 #: web/templates/public/surroundings.gohtml:58
msgid "Routes" msgid "Routes"
msgstr "Rutas" msgstr "Rutas"
#: web/templates/public/surroundings.gohtml:61 #: web/templates/public/surroundings.gohtml:59
msgid "Routes of all kinds, climbing, mountain passes, for all levels." msgid "Routes of all kinds, climbing, mountain passes, for all levels."
msgstr "Rutas de todo tipo, escalada, puertos de montaña, para todos los niveles." msgstr "Rutas de todo tipo, escalada, puertos de montaña, para todos los niveles."
#: web/templates/public/surroundings.gohtml:65 #: web/templates/public/surroundings.gohtml:63
msgid "Family outing" msgid "Family outing"
msgstr "Excusiones familiares" msgstr "Excusiones familiares"
#: web/templates/public/surroundings.gohtml:66 #: web/templates/public/surroundings.gohtml:64
msgid "Many outing possibilities, for all ages." msgid "Many outing possibilities, for all ages."
msgstr "Múltiples excursiones para todas las edades." msgstr "Múltiples excursiones para todas las edades."
#: web/templates/public/surroundings.gohtml:70 #: web/templates/public/surroundings.gohtml:68
msgid "Kayak" msgid "Kayak"
msgstr "Kayak" msgstr "Kayak"
#: web/templates/public/surroundings.gohtml:71 #: web/templates/public/surroundings.gohtml:69
msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…." msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…."
msgstr "Hay diversos puntos dónde podéis ir en kayak, desde tramos del río Ter como también en la costa…." msgstr "Hay diversos puntos dónde podéis ir en kayak, desde tramos del río Ter como también en la costa…."
@ -475,6 +475,7 @@ msgstr "Contenido"
#: web/templates/admin/season/form.gohtml:73 #: web/templates/admin/season/form.gohtml:73
#: web/templates/admin/services/form.gohtml:80 #: web/templates/admin/services/form.gohtml:80
#: web/templates/admin/surroundings/form.gohtml:69 #: web/templates/admin/surroundings/form.gohtml:69
#: web/templates/admin/surroundings/index.gohtml:58
#: web/templates/admin/home/index.gohtml:34 #: web/templates/admin/home/index.gohtml:34
#: web/templates/admin/media/form.gohtml:39 #: web/templates/admin/media/form.gohtml:39
msgctxt "action" msgctxt "action"
@ -506,7 +507,7 @@ msgstr "Añadir texto legal"
#: web/templates/admin/campsite/type/index.gohtml:29 #: web/templates/admin/campsite/type/index.gohtml:29
#: web/templates/admin/season/index.gohtml:29 #: web/templates/admin/season/index.gohtml:29
#: web/templates/admin/user/index.gohtml:20 #: web/templates/admin/user/index.gohtml:20
#: web/templates/admin/surroundings/index.gohtml:29 #: web/templates/admin/surroundings/index.gohtml:83
msgctxt "header" msgctxt "header"
msgid "Name" msgid "Name"
msgstr "Nombre" msgstr "Nombre"
@ -636,7 +637,7 @@ msgstr "Añadir diapositiva"
#: web/templates/admin/campsite/carousel/index.gohtml:30 #: web/templates/admin/campsite/carousel/index.gohtml:30
#: web/templates/admin/services/index.gohtml:28 #: web/templates/admin/services/index.gohtml:28
#: web/templates/admin/surroundings/index.gohtml:28 #: web/templates/admin/surroundings/index.gohtml:82
#: web/templates/admin/home/index.gohtml:52 #: web/templates/admin/home/index.gohtml:52
#: web/templates/admin/home/index.gohtml:97 #: web/templates/admin/home/index.gohtml:97
msgctxt "header" msgctxt "header"
@ -656,7 +657,7 @@ msgstr "Leyenda"
#: web/templates/admin/services/index.gohtml:30 #: web/templates/admin/services/index.gohtml:30
#: web/templates/admin/services/index.gohtml:75 #: web/templates/admin/services/index.gohtml:75
#: web/templates/admin/user/index.gohtml:23 #: web/templates/admin/user/index.gohtml:23
#: web/templates/admin/surroundings/index.gohtml:30 #: web/templates/admin/surroundings/index.gohtml:84
#: web/templates/admin/home/index.gohtml:54 #: web/templates/admin/home/index.gohtml:54
#: web/templates/admin/home/index.gohtml:99 #: web/templates/admin/home/index.gohtml:99
msgctxt "header" msgctxt "header"
@ -674,7 +675,8 @@ msgstr "¿Estáis seguro de querer borrar esta diapositiva?"
#: web/templates/admin/services/index.gohtml:47 #: web/templates/admin/services/index.gohtml:47
#: web/templates/admin/services/index.gohtml:91 #: web/templates/admin/services/index.gohtml:91
#: web/templates/admin/user/index.gohtml:37 #: web/templates/admin/user/index.gohtml:37
#: web/templates/admin/surroundings/index.gohtml:47 #: web/templates/admin/surroundings/index.gohtml:63
#: web/templates/admin/surroundings/index.gohtml:101
#: web/templates/admin/home/index.gohtml:71 #: web/templates/admin/home/index.gohtml:71
#: web/templates/admin/home/index.gohtml:116 #: web/templates/admin/home/index.gohtml:116
msgctxt "action" msgctxt "action"
@ -1209,19 +1211,43 @@ msgstr "Página del entorno"
#: web/templates/admin/surroundings/index.gohtml:14 #: web/templates/admin/surroundings/index.gohtml:14
msgctxt "title" msgctxt "title"
msgid "Ad"
msgstr "Anuncio"
#: web/templates/admin/surroundings/index.gohtml:21
msgctxt "input"
msgid "Title"
msgstr "Título"
#: web/templates/admin/surroundings/index.gohtml:37
msgctxt "input"
msgid "Link Text"
msgstr "Texto del enlace"
#: web/templates/admin/surroundings/index.gohtml:50
msgctxt "input"
msgid "Link URL"
msgstr "Dirección del enlace"
#: web/templates/admin/surroundings/index.gohtml:59
msgid "Are you sure you wish to delete the ad?"
msgstr "¿Estáis seguro de querer borrar este enlace?"
#: web/templates/admin/surroundings/index.gohtml:68
msgctxt "title"
msgid "Highlights" msgid "Highlights"
msgstr "Puntos de interés" msgstr "Puntos de interés"
#: web/templates/admin/surroundings/index.gohtml:15 #: web/templates/admin/surroundings/index.gohtml:69
msgctxt "action" msgctxt "action"
msgid "Add highlight" msgid "Add highlight"
msgstr "Añadir punto de interés" msgstr "Añadir punto de interés"
#: web/templates/admin/surroundings/index.gohtml:34 #: web/templates/admin/surroundings/index.gohtml:88
msgid "Are you sure you wish to delete this highlight?" msgid "Are you sure you wish to delete this highlight?"
msgstr "¿Estáis seguro de querer borrar este punto de interés?" msgstr "¿Estáis seguro de querer borrar este punto de interés?"
#: web/templates/admin/surroundings/index.gohtml:56 #: web/templates/admin/surroundings/index.gohtml:110
msgid "No highlights added yet." msgid "No highlights added yet."
msgstr "No se ha añadido ningún punto de interés todavía." msgstr "No se ha añadido ningún punto de interés todavía."
@ -1441,7 +1467,7 @@ msgstr "No se ha encontrado ninguna reserva."
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357 #: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:483 #: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:483
#: pkg/season/admin.go:412 pkg/services/admin.go:316 #: pkg/season/admin.go:412 pkg/services/admin.go:316
#: pkg/surroundings/admin.go:321 #: pkg/surroundings/admin.go:340
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco." msgstr "No podéis dejar el nombre en blanco."
@ -1461,12 +1487,12 @@ msgid "Set slide image"
msgstr "Establecer la imagen de la diapositiva" msgstr "Establecer la imagen de la diapositiva"
#: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299 #: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299
#: pkg/surroundings/admin.go:316 #: pkg/surroundings/admin.go:335
msgid "Slide image can not be empty." msgid "Slide image can not be empty."
msgstr "No podéis dejar la imagen de la diapositiva en blanco." msgstr "No podéis dejar la imagen de la diapositiva en blanco."
#: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300 #: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300
#: pkg/surroundings/admin.go:317 #: pkg/surroundings/admin.go:336
msgid "Slide image must be an image media type." msgid "Slide image must be an image media type."
msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen." msgstr "La imagen de la diapositiva tiene que ser un medio de tipo imagen."
@ -1711,16 +1737,50 @@ msgctxt "role"
msgid "admin" msgid "admin"
msgstr "administrador" msgstr "administrador"
#: pkg/surroundings/admin.go:267 #: pkg/surroundings/admin.go:286
msgctxt "input" msgctxt "input"
msgid "Highlight image" msgid "Highlight image"
msgstr "Imagen del punto de interés" msgstr "Imagen del punto de interés"
#: pkg/surroundings/admin.go:268 #: pkg/surroundings/admin.go:287
msgctxt "action" msgctxt "action"
msgid "Set highlight image" msgid "Set highlight image"
msgstr "Establecer la imagen del punto de interés" msgstr "Establecer la imagen del punto de interés"
#: pkg/surroundings/admin.go:407
msgctxt "input"
msgid "Ad image"
msgstr "Imagen del anuncio"
#: pkg/surroundings/admin.go:408
msgctxt "action"
msgid "Set ad image"
msgstr "Establecer la imagen del anuncio"
#: pkg/surroundings/admin.go:459
msgid "Ad image can not be empty."
msgstr "No podéis dejar la imagen del anuncio en blanco."
#: pkg/surroundings/admin.go:460
msgid "Ad image must be an image media type."
msgstr "La imagen del anuncio tiene que ser un medio de tipo imagen."
#: pkg/surroundings/admin.go:464
msgid "The title can not be empty."
msgstr "No podéis dejar el título en blanco."
#: pkg/surroundings/admin.go:465
msgid "The link text can not be empty."
msgstr "No podéis dejar el texto del enlace en blanco."
#: pkg/surroundings/admin.go:466
msgid "The ad URL can not be empty"
msgstr "No podéis dejar la dirección del enlace en blanco."
#: pkg/surroundings/admin.go:467 pkg/company/admin.go:221
msgid "This web address is not valid. It should be like https://domain.com/."
msgstr "Esta dirección web no es válida. Tiene que ser parecido a https://dominio.com/."
#: pkg/company/admin.go:200 pkg/booking/public.go:256 #: pkg/company/admin.go:200 pkg/booking/public.go:256
msgid "Selected country is not valid." msgid "Selected country is not valid."
msgstr "El país escogido no es válido." msgstr "El país escogido no es válido."
@ -1749,10 +1809,6 @@ msgstr "No podéis dejar el teléfono en blanco."
msgid "This phone number is not valid." msgid "This phone number is not valid."
msgstr "Este teléfono no es válido." msgstr "Este teléfono no es válido."
#: pkg/company/admin.go:221
msgid "This web address is not valid. It should be like https://domain.com/."
msgstr "Esta dirección web no es válida. Tiene que ser parecido a https://dominio.com/."
#: pkg/company/admin.go:223 #: pkg/company/admin.go:223
msgid "Address can not be empty." msgid "Address can not be empty."
msgstr "No podéis dejar la dirección en blanco." msgstr "No podéis dejar la dirección en blanco."
@ -2057,10 +2113,6 @@ msgstr "%s tiene que ser como máximo %d"
#~ msgid "Legend" #~ msgid "Legend"
#~ msgstr "Leyenda" #~ msgstr "Leyenda"
#~ msgctxt "input"
#~ msgid "Title"
#~ msgstr "Título"
#~ msgctxt "title" #~ msgctxt "title"
#~ msgid "Pages" #~ msgid "Pages"
#~ msgstr "Páginas" #~ msgstr "Páginas"

110
po/fr.po
View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: camper\n" "Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2024-01-23 11:46+0100\n" "POT-Creation-Date: 2024-01-23 14:38+0100\n"
"PO-Revision-Date: 2023-12-20 10:13+0100\n" "PO-Revision-Date: 2023-12-20 10:13+0100\n"
"Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n" "Last-Translator: Oriol Carbonell <info@oriolcarbonell.cat>\n"
"Language-Team: French <traduc@traduc.org>\n" "Language-Team: French <traduc@traduc.org>\n"
@ -242,45 +242,45 @@ msgctxt "day"
msgid "Sun" msgid "Sun"
msgstr "Dim." msgstr "Dim."
#: web/templates/public/surroundings.gohtml:32 #: web/templates/public/surroundings.gohtml:30
msgctxt "title" msgctxt "title"
msgid "What to Do Outside the Campsite?" msgid "What to Do Outside the Campsite?"
msgstr "Que faire à lextérieur du camping ?" msgstr "Que faire à lextérieur du camping ?"
#: web/templates/public/surroundings.gohtml:52 #: web/templates/public/surroundings.gohtml:50
msgctxt "title" msgctxt "title"
msgid "Once at the Campsite, We Can Inform You about What Activities are Available" msgid "Once at the Campsite, We Can Inform You about What Activities are Available"
msgstr "Une fois au camping, nous pourrons vous informer sur les activités disponibles" msgstr "Une fois au camping, nous pourrons vous informer sur les activités disponibles"
#: web/templates/public/surroundings.gohtml:55 #: web/templates/public/surroundings.gohtml:53
msgid "Cycle routes" msgid "Cycle routes"
msgstr "Pistes cyclables" msgstr "Pistes cyclables"
#: web/templates/public/surroundings.gohtml:56 #: web/templates/public/surroundings.gohtml:54
msgid "There are many bicycle rental companies in Olot." msgid "There are many bicycle rental companies in Olot."
msgstr "Il existe de nombreuses sociétés de location de vélos à Olot." msgstr "Il existe de nombreuses sociétés de location de vélos à Olot."
#: web/templates/public/surroundings.gohtml:60 #: web/templates/public/surroundings.gohtml:58
msgid "Routes" msgid "Routes"
msgstr "Itinéraires" msgstr "Itinéraires"
#: web/templates/public/surroundings.gohtml:61 #: web/templates/public/surroundings.gohtml:59
msgid "Routes of all kinds, climbing, mountain passes, for all levels." msgid "Routes of all kinds, climbing, mountain passes, for all levels."
msgstr "Itinéraires de toutes sortes, escalade, cols de montagne, pour tous les niveaux." msgstr "Itinéraires de toutes sortes, escalade, cols de montagne, pour tous les niveaux."
#: web/templates/public/surroundings.gohtml:65 #: web/templates/public/surroundings.gohtml:63
msgid "Family outing" msgid "Family outing"
msgstr "Sortie en famille" msgstr "Sortie en famille"
#: web/templates/public/surroundings.gohtml:66 #: web/templates/public/surroundings.gohtml:64
msgid "Many outing possibilities, for all ages." msgid "Many outing possibilities, for all ages."
msgstr "Nombreuses possibilités de sorties, pour tous les âges." msgstr "Nombreuses possibilités de sorties, pour tous les âges."
#: web/templates/public/surroundings.gohtml:70 #: web/templates/public/surroundings.gohtml:68
msgid "Kayak" msgid "Kayak"
msgstr "Kayak" msgstr "Kayak"
#: web/templates/public/surroundings.gohtml:71 #: web/templates/public/surroundings.gohtml:69
msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…." msgid "There are several points where you can go by kayak, from sections of the Ter river as well as on the coast…."
msgstr "Il y a plusieurs points où vous pouvez aller en kayak, à partir de sections de la rivière Ter ainsi que sur la côte…." msgstr "Il y a plusieurs points où vous pouvez aller en kayak, à partir de sections de la rivière Ter ainsi que sur la côte…."
@ -476,6 +476,7 @@ msgstr "Contenu"
#: web/templates/admin/season/form.gohtml:73 #: web/templates/admin/season/form.gohtml:73
#: web/templates/admin/services/form.gohtml:80 #: web/templates/admin/services/form.gohtml:80
#: web/templates/admin/surroundings/form.gohtml:69 #: web/templates/admin/surroundings/form.gohtml:69
#: web/templates/admin/surroundings/index.gohtml:58
#: web/templates/admin/home/index.gohtml:34 #: web/templates/admin/home/index.gohtml:34
#: web/templates/admin/media/form.gohtml:39 #: web/templates/admin/media/form.gohtml:39
msgctxt "action" msgctxt "action"
@ -507,7 +508,7 @@ msgstr "Ajouter un texte juridique"
#: web/templates/admin/campsite/type/index.gohtml:29 #: web/templates/admin/campsite/type/index.gohtml:29
#: web/templates/admin/season/index.gohtml:29 #: web/templates/admin/season/index.gohtml:29
#: web/templates/admin/user/index.gohtml:20 #: web/templates/admin/user/index.gohtml:20
#: web/templates/admin/surroundings/index.gohtml:29 #: web/templates/admin/surroundings/index.gohtml:83
msgctxt "header" msgctxt "header"
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
@ -637,7 +638,7 @@ msgstr "Ajouter la diapositive"
#: web/templates/admin/campsite/carousel/index.gohtml:30 #: web/templates/admin/campsite/carousel/index.gohtml:30
#: web/templates/admin/services/index.gohtml:28 #: web/templates/admin/services/index.gohtml:28
#: web/templates/admin/surroundings/index.gohtml:28 #: web/templates/admin/surroundings/index.gohtml:82
#: web/templates/admin/home/index.gohtml:52 #: web/templates/admin/home/index.gohtml:52
#: web/templates/admin/home/index.gohtml:97 #: web/templates/admin/home/index.gohtml:97
msgctxt "header" msgctxt "header"
@ -657,7 +658,7 @@ msgstr "Légende"
#: web/templates/admin/services/index.gohtml:30 #: web/templates/admin/services/index.gohtml:30
#: web/templates/admin/services/index.gohtml:75 #: web/templates/admin/services/index.gohtml:75
#: web/templates/admin/user/index.gohtml:23 #: web/templates/admin/user/index.gohtml:23
#: web/templates/admin/surroundings/index.gohtml:30 #: web/templates/admin/surroundings/index.gohtml:84
#: web/templates/admin/home/index.gohtml:54 #: web/templates/admin/home/index.gohtml:54
#: web/templates/admin/home/index.gohtml:99 #: web/templates/admin/home/index.gohtml:99
msgctxt "header" msgctxt "header"
@ -675,7 +676,8 @@ msgstr "Êtes-vous sûr de vouloir supprimer cette diapositive ?"
#: web/templates/admin/services/index.gohtml:47 #: web/templates/admin/services/index.gohtml:47
#: web/templates/admin/services/index.gohtml:91 #: web/templates/admin/services/index.gohtml:91
#: web/templates/admin/user/index.gohtml:37 #: web/templates/admin/user/index.gohtml:37
#: web/templates/admin/surroundings/index.gohtml:47 #: web/templates/admin/surroundings/index.gohtml:63
#: web/templates/admin/surroundings/index.gohtml:101
#: web/templates/admin/home/index.gohtml:71 #: web/templates/admin/home/index.gohtml:71
#: web/templates/admin/home/index.gohtml:116 #: web/templates/admin/home/index.gohtml:116
msgctxt "action" msgctxt "action"
@ -1210,19 +1212,43 @@ msgstr "Page de lentourage"
#: web/templates/admin/surroundings/index.gohtml:14 #: web/templates/admin/surroundings/index.gohtml:14
msgctxt "title" msgctxt "title"
msgid "Ad"
msgstr "Annonce"
#: web/templates/admin/surroundings/index.gohtml:21
msgctxt "input"
msgid "Title"
msgstr "Titre"
#: web/templates/admin/surroundings/index.gohtml:37
msgctxt "input"
msgid "Link Text"
msgstr "Texte du lien"
#: web/templates/admin/surroundings/index.gohtml:50
msgctxt "input"
msgid "Link URL"
msgstr "Address du lien"
#: web/templates/admin/surroundings/index.gohtml:59
msgid "Are you sure you wish to delete the ad?"
msgstr "Êtes-vous sûr de vouloir supprimer cette annonce ?"
#: web/templates/admin/surroundings/index.gohtml:68
msgctxt "title"
msgid "Highlights" msgid "Highlights"
msgstr "Points dintérêt" msgstr "Points dintérêt"
#: web/templates/admin/surroundings/index.gohtml:15 #: web/templates/admin/surroundings/index.gohtml:69
msgctxt "action" msgctxt "action"
msgid "Add highlight" msgid "Add highlight"
msgstr "Ajouter un point dintérêt" msgstr "Ajouter un point dintérêt"
#: web/templates/admin/surroundings/index.gohtml:34 #: web/templates/admin/surroundings/index.gohtml:88
msgid "Are you sure you wish to delete this highlight?" msgid "Are you sure you wish to delete this highlight?"
msgstr "Êtes-vous sûr de vouloir supprimer cette point dintérêt ?" msgstr "Êtes-vous sûr de vouloir supprimer cette point dintérêt ?"
#: web/templates/admin/surroundings/index.gohtml:56 #: web/templates/admin/surroundings/index.gohtml:110
msgid "No highlights added yet." msgid "No highlights added yet."
msgstr "Aucun point dintérêt na encore été ajoutée." msgstr "Aucun point dintérêt na encore été ajoutée."
@ -1442,7 +1468,7 @@ msgstr "Aucune réservation trouvée."
#: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357 #: pkg/legal/admin.go:258 pkg/app/user.go:249 pkg/campsite/types/option.go:357
#: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:483 #: pkg/campsite/types/feature.go:259 pkg/campsite/types/admin.go:483
#: pkg/season/admin.go:412 pkg/services/admin.go:316 #: pkg/season/admin.go:412 pkg/services/admin.go:316
#: pkg/surroundings/admin.go:321 #: pkg/surroundings/admin.go:340
msgid "Name can not be empty." msgid "Name can not be empty."
msgstr "Le nom ne peut pas être laissé vide." msgstr "Le nom ne peut pas être laissé vide."
@ -1462,12 +1488,12 @@ msgid "Set slide image"
msgstr "Définir limage de la diapositive" msgstr "Définir limage de la diapositive"
#: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299 #: pkg/carousel/admin.go:346 pkg/campsite/types/carousel.go:299
#: pkg/surroundings/admin.go:316 #: pkg/surroundings/admin.go:335
msgid "Slide image can not be empty." msgid "Slide image can not be empty."
msgstr "Limage de la diapositive ne peut pas être vide." msgstr "Limage de la diapositive ne peut pas être vide."
#: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300 #: pkg/carousel/admin.go:347 pkg/campsite/types/carousel.go:300
#: pkg/surroundings/admin.go:317 #: pkg/surroundings/admin.go:336
msgid "Slide image must be an image media type." msgid "Slide image must be an image media type."
msgstr "Limage de la diapositive doit être de type média dimage." msgstr "Limage de la diapositive doit être de type média dimage."
@ -1712,16 +1738,50 @@ msgctxt "role"
msgid "admin" msgid "admin"
msgstr "administrateur" msgstr "administrateur"
#: pkg/surroundings/admin.go:267 #: pkg/surroundings/admin.go:286
msgctxt "input" msgctxt "input"
msgid "Highlight image" msgid "Highlight image"
msgstr "Image du point dintérêt" msgstr "Image du point dintérêt"
#: pkg/surroundings/admin.go:268 #: pkg/surroundings/admin.go:287
msgctxt "action" msgctxt "action"
msgid "Set highlight image" msgid "Set highlight image"
msgstr "Définir limage du point dintérêt" msgstr "Définir limage du point dintérêt"
#: pkg/surroundings/admin.go:407
msgctxt "input"
msgid "Ad image"
msgstr "Image de lannonce"
#: pkg/surroundings/admin.go:408
msgctxt "action"
msgid "Set ad image"
msgstr "Définir limage de lannonce"
#: pkg/surroundings/admin.go:459
msgid "Ad image can not be empty."
msgstr "Limage de lannonce ne peut pas être vide."
#: pkg/surroundings/admin.go:460
msgid "Ad image must be an image media type."
msgstr "Limage de lannonce doit être de type média dimage."
#: pkg/surroundings/admin.go:464
msgid "The title can not be empty."
msgstr "Le titre ne peut pas être vide."
#: pkg/surroundings/admin.go:465
msgid "The link text can not be empty."
msgstr "Le texte du lien ne peut pas être vide."
#: pkg/surroundings/admin.go:466
msgid "The ad URL can not be empty"
msgstr "Laddresse du lien ne peut pas être vide."
#: pkg/surroundings/admin.go:467 pkg/company/admin.go:221
msgid "This web address is not valid. It should be like https://domain.com/."
msgstr "Cette adresse web nest pas valide. Il devrait en être https://domain.com/."
#: pkg/company/admin.go:200 pkg/booking/public.go:256 #: pkg/company/admin.go:200 pkg/booking/public.go:256
msgid "Selected country is not valid." msgid "Selected country is not valid."
msgstr "Le pays sélectionné nest pas valide." msgstr "Le pays sélectionné nest pas valide."
@ -1750,10 +1810,6 @@ msgstr "Le téléphone ne peut pas être vide."
msgid "This phone number is not valid." msgid "This phone number is not valid."
msgstr "Ce numéro de téléphone nest pas valide." msgstr "Ce numéro de téléphone nest pas valide."
#: pkg/company/admin.go:221
msgid "This web address is not valid. It should be like https://domain.com/."
msgstr "Cette adresse web nest pas valide. Il devrait en être https://domain.com/."
#: pkg/company/admin.go:223 #: pkg/company/admin.go:223
msgid "Address can not be empty." msgid "Address can not be empty."
msgstr "Ladresse ne peut pas être vide." msgstr "Ladresse ne peut pas être vide."

View File

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

View File

@ -0,0 +1,7 @@
-- Revert camper:setup_surroundings_ad from pg
begin;
drop function if exists camper.setup_surroundings_ad(integer, integer, text, text, uri);
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:surroundings_ad from pg
begin;
drop table if exists camper.surroundings_ad;
commit;

View File

@ -0,0 +1,7 @@
-- Revert camper:surroundings_ad_i18n from pg
begin;
drop table if exists camper.surroundings_ad_i18n;
commit;

View File

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

View File

@ -172,3 +172,8 @@ home [roles schema_camper company user_profile] 2024-01-23T10:02:08Z jordi fita
setup_home [roles schema_camper home] 2024-01-23T10:14:14Z jordi fita mas <jordi@tandem.blog> # Add function to set up home page setup_home [roles schema_camper home] 2024-01-23T10:14:14Z jordi fita mas <jordi@tandem.blog> # Add function to set up home page
home_i18n [roles schema_camper home] 2024-01-23T10:19:47Z jordi fita mas <jordi@tandem.blog> # Add table to hold translated texts for home page home_i18n [roles schema_camper home] 2024-01-23T10:19:47Z jordi fita mas <jordi@tandem.blog> # Add table to hold translated texts for home page
translate_home [roles schema_camper home_i18n] 2024-01-23T10:24:02Z jordi fita mas <jordi@tandem.blog> # Add function to translate home texts translate_home [roles schema_camper home_i18n] 2024-01-23T10:24:02Z jordi fita mas <jordi@tandem.blog> # Add function to translate home texts
surroundings_ad [roles schema_camper company user_profile] 2024-01-23T11:23:58Z jordi fita mas <jordi@tandem.blog> # Add table to hold the ad in surroundings page
setup_surroundings_ad [roles schema_camper surroundings_ad] 2024-01-23T11:32:26Z jordi fita mas <jordi@tandem.blog> # Add function to set up surroundings ad
surroundings_ad_i18n [roles schema_camper surroundings_ad language] 2024-01-23T11:44:44Z jordi fita mas <jordi@tandem.blog> # Add relation for the translation of the surrounding ad
remove_surroundings_ad [roles schema_camper surroundings_ad surroundings_ad_i18n] 2024-01-23T11:41:47Z jordi fita mas <jordi@tandem.blog> # Add function to remove surroundings ad
translate_surroundings_ad [roles schema_camper surroundings_ad_i18n] 2024-01-23T12:06:32Z jordi fita mas <jordi@tandem.blog> # Add function to translate surroundings ad

View File

@ -0,0 +1,99 @@
-- Test remove_surroundings_ad
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(12);
set search_path to camper, public;
select has_function('camper', 'remove_surroundings_ad', array['integer']);
select function_lang_is('camper', 'remove_surroundings_ad', array['integer'], 'sql');
select function_returns('camper', 'remove_surroundings_ad', array['integer'], 'void');
select isnt_definer('camper', 'remove_surroundings_ad', array['integer']);
select volatility_is('camper', 'remove_surroundings_ad', array['integer'], 'volatile');
select function_privs_are('camper', 'remove_surroundings_ad', array['integer'], 'guest', array[]::text[]);
select function_privs_are('camper', 'remove_surroundings_ad', array['integer'], 'employee', array[]::text[]);
select function_privs_are('camper', 'remove_surroundings_ad', array['integer'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'remove_surroundings_ad', array['integer'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_ad_i18n cascade;
truncate surroundings_ad 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, tourist_tax, country_code, currency_code, default_lang_tag)
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, 'FR', 'USD', 'ca')
;
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 media_content (media_type, bytes)
values ('text/plain', 'content2')
, ('text/plain', 'content4')
;
insert into media (media_id, company_id, original_filename, content_hash)
values ( 7, 2, 'text2.txt', sha256('content2'))
, ( 8, 4, 'text3.txt', sha256('content4'))
;
insert into surroundings_ad (company_id, media_id, title, anchor, href)
values (2, 7, 'Ad 2', 'Go!', 'https://ddg.gg/')
, (4, 8, 'Ad 4', 'Go!', 'https://ddg.gg/')
;
insert into surroundings_ad_i18n (company_id, lang_tag, title, anchor)
values (2, 'ca', 'Anunci 2', 'Ves!')
, (2, 'es', 'Anuncio 2', '¡Ve!')
, (4, 'ca', 'Anunci 4', 'Ves!')
, (4, 'es', 'Anuncio 4', '¡Ve!')
;
select lives_ok(
$$ select remove_surroundings_ad(2) $$,
'Should be able to delete the ad from the first company'
);
select bag_eq(
$$ select company_id, media_id, title, anchor, href::text from surroundings_ad $$,
$$ values (4, 8, 'Ad 4', 'Go!', 'https://ddg.gg/')
$$,
'The row should have been deleted.'
);
select bag_eq(
$$ select company_id, lang_tag, title, anchor from surroundings_ad_i18n $$,
$$ values (4, 'ca', 'Anunci 4', 'Ves!')
, (4, 'es', 'Anuncio 4', '¡Ve!')
$$,
'The translations should have been deleted.'
);
select *
from finish();
rollback;

View File

@ -0,0 +1,95 @@
-- Test setup_surroundings_ad
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_surroundings_ad', array['integer', 'integer', 'text', 'text', 'uri']);
select function_lang_is('camper', 'setup_surroundings_ad', array['integer', 'integer', 'text', 'text', 'uri'], 'sql');
select function_returns('camper', 'setup_surroundings_ad', array['integer', 'integer', 'text', 'text', 'uri'], 'void');
select isnt_definer('camper', 'setup_surroundings_ad', array['integer', 'integer', 'text', 'text', 'uri']);
select volatility_is('camper', 'setup_surroundings_ad', array['integer', 'integer', 'text', 'text', 'uri'], 'volatile');
select function_privs_are('camper', 'setup_surroundings_ad', array ['integer', 'integer', 'text', 'text', 'uri'], 'guest', array[]::text[]);
select function_privs_are('camper', 'setup_surroundings_ad', array ['integer', 'integer', 'text', 'text', 'uri'], 'employee', array[]::text[]);
select function_privs_are('camper', 'setup_surroundings_ad', array ['integer', 'integer', 'text', 'text', 'uri'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'setup_surroundings_ad', array ['integer', 'integer', 'text', 'text', 'uri'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_ad cascade;
truncate media cascade;
truncate media_content 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, tourist_tax, country_code, currency_code, default_lang_tag)
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
, (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, 'FR', 'USD', 'ca')
;
insert into media_content (media_type, bytes)
values ('text/plain', 'content2')
, ('text/plain', 'content3')
, ('text/plain', 'content4')
, ('text/plain', 'content5')
;
insert into media (media_id, company_id, original_filename, content_hash)
values ( 7, 1, 'text2.txt', sha256('content2'))
, ( 8, 1, 'text3.txt', sha256('content3'))
, ( 9, 2, 'text4.txt', sha256('content4'))
, (10, 2, 'text5.txt', sha256('content5'))
;
prepare surroundings_ad_data as
select company_id, media_id, title, anchor, href::text
from surroundings_ad
;
select lives_ok(
$$ select setup_surroundings_ad(1, 7, 'Enjoy!', 'Good Link', 'https://ddg.gg/') $$,
'Should be able to setup surroundings_ad for the first company'
);
select lives_ok(
$$ select setup_surroundings_ad(2, 9, 'Go Away!', 'Bad Link', 'https://google.es/') $$,
'Should be able to setup surroundings_ad for the second company'
);
select bag_eq(
'surroundings_ad_data',
$$ values (1, 7, 'Enjoy!', 'Good Link', 'https://ddg.gg/')
, (2, 9, 'Go Away!', 'Bad Link', 'https://google.es/')
$$,
'Should have inserted all surrounding ad'
);
select lives_ok(
$$ select setup_surroundings_ad(1, 8, 'Come Back!', 'Good Memories', 'https://astalavista.box.sk/') $$,
'Should be able to update surroundings_ad for the first company'
);
select lives_ok(
$$ select setup_surroundings_ad(2, 10, 'Quoi?', 'Ecs', 'https://yahoo.fr/') $$,
'Should be able to update surroundings_ad for the second company'
);
select bag_eq(
'surroundings_ad_data',
$$ values (1, 8, 'Come Back!', 'Good Memories', 'https://astalavista.box.sk/')
, (2, 10, 'Quoi?', 'Ecs', 'https://yahoo.fr/')
$$,
'Should have updated all surrounding ad'
);
select *
from finish();
rollback;

196
test/surroundings_ad.sql Normal file
View File

@ -0,0 +1,196 @@
-- Test surroundings_ad
set client_min_messages to warning;
create extension if not exists pgtap;
reset client_min_messages;
begin;
select plan(44);
set search_path to camper, public;
select has_table('surroundings_ad');
select has_pk('surroundings_ad');
select table_privs_are('surroundings_ad', 'guest', array['SELECT']);
select table_privs_are('surroundings_ad', 'employee', array['SELECT']);
select table_privs_are('surroundings_ad', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
select table_privs_are('surroundings_ad', 'authenticator', array[]::text[]);
select has_column('surroundings_ad', 'company_id');
select col_is_pk('surroundings_ad', 'company_id');
select col_is_fk('surroundings_ad', 'company_id');
select fk_ok('surroundings_ad', 'company_id', 'company', 'company_id');
select col_type_is('surroundings_ad', 'company_id', 'integer');
select col_not_null('surroundings_ad', 'company_id');
select col_hasnt_default('surroundings_ad', 'company_id');
select has_column('surroundings_ad', 'media_id');
select col_is_fk('surroundings_ad', 'media_id');
select fk_ok('surroundings_ad', 'media_id', 'media', 'media_id');
select col_type_is('surroundings_ad', 'media_id', 'integer');
select col_not_null('surroundings_ad', 'media_id');
select col_hasnt_default('surroundings_ad', 'media_id');
select has_column('surroundings_ad', 'title');
select col_type_is('surroundings_ad', 'title', 'text');
select col_not_null('surroundings_ad', 'title');
select col_hasnt_default('surroundings_ad', 'title');
select has_column('surroundings_ad', 'anchor');
select col_type_is('surroundings_ad', 'anchor', 'text');
select col_not_null('surroundings_ad', 'anchor');
select col_hasnt_default('surroundings_ad', 'anchor');
select has_column('surroundings_ad', 'href');
select col_type_is('surroundings_ad', 'href', 'uri');
select col_not_null('surroundings_ad', 'href');
select col_hasnt_default('surroundings_ad', 'href');
set client_min_messages to warning;
truncate surroundings_ad 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, tourist_tax, country_code, currency_code, default_lang_tag)
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, 'FR', 'USD', 'ca')
, (6, 'Company 5', 'XX345', '', '777-777-777', 'c@c', '', '', '', '', '', '', 60, 'FR', 'USD', 'ca')
;
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 media_content (media_type, bytes)
values ('text/plain', 'content2')
, ('text/plain', 'content4')
;
insert into media (media_id, company_id, original_filename, content_hash)
values ( 7, 2, 'text2.txt', sha256('content2'))
, ( 8, 4, 'text3.txt', sha256('content4'))
;
insert into surroundings_ad (company_id, media_id, title, anchor, href)
values (2, 7, 'Ad 2', 'Go!', 'https://ddg.gg/')
, (4, 8, 'Ad 4', 'Go!', 'https://ddg.gg/')
;
prepare surroundings_ad_data as
select company_id, title
from surroundings_ad
order by company_id, title;
set role guest;
select bag_eq(
'surroundings_ad_data',
$$ values (2, 'Ad 2')
, (4, 'Ad 4')
$$,
'Everyone should be able to list all surrounding ad across all companies'
);
reset role;
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog', 'co2');
select lives_ok(
$$ delete from surroundings_ad where company_id = 2 $$,
'Admin from company 2 should be able to delete surrounding ad from that company.'
);
select bag_eq(
'surroundings_ad_data',
$$ values (4, 'Ad 4')
$$,
'The row should have been deleted.'
);
select lives_ok(
$$ insert into surroundings_ad(company_id, media_id, title, anchor, href) values (2, 7, 'Another Ad', 'Go!', 'https://ddg.gg/') $$,
'Admin from company 2 should be able to insert a new surrounding ad to that company.'
);
select bag_eq(
'surroundings_ad_data',
$$ values (2, 'Another Ad')
, (4, 'Ad 4')
$$,
'The new row should have been added'
);
select lives_ok(
$$ update surroundings_ad set title = 'Ad 2' where company_id = 2 $$,
'Admin from company 2 should be able to update surrounding ad of that company.'
);
select bag_eq(
'surroundings_ad_data',
$$ values (2, 'Ad 2')
, (4, 'Ad 4')
$$,
'The row should have been updated.'
);
select throws_ok(
$$ insert into surroundings_ad (company_id, title) values (6, 'Ad 6') $$,
'42501', 'new row violates row-level security policy for table "surroundings_ad"',
'Admin from company 2 should NOT be able to insert new surrounding ad to company 6.'
);
select lives_ok(
$$ update surroundings_ad set title = 'Nope' where company_id = 4 $$,
'Admin from company 2 should not be able to update new surrounding ad of company 4, but no error if company_id is not changed.'
);
select bag_eq(
'surroundings_ad_data',
$$ values (2, 'Ad 2')
, (4, 'Ad 4')
$$,
'No row should have been changed.'
);
select throws_ok(
$$ update surroundings_ad set company_id = 6 where company_id = 2 $$,
'42501', 'new row violates row-level security policy for table "surroundings_ad"',
'Admin from company 2 should NOT be able to move surrounding ad to company 6'
);
select lives_ok(
$$ delete from surroundings_ad where company_id = 4 $$,
'Admin from company 2 should NOT be able to delete surrounding ad from company 4, but not error is thrown'
);
select bag_eq(
'surroundings_ad_data',
$$ values (2, 'Ad 2')
, (4, 'Ad 4')
$$,
'No row should have been changed'
);
reset role;
select *
from finish();
rollback;

View File

@ -0,0 +1,49 @@
-- Test surroundings_ad_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('surroundings_ad_i18n');
select has_pk('surroundings_ad_i18n');
select col_is_pk('surroundings_ad_i18n', array['company_id', 'lang_tag']);
select table_privs_are('surroundings_ad_i18n', 'guest', array['SELECT']);
select table_privs_are('surroundings_ad_i18n', 'employee', array['SELECT']);
select table_privs_are('surroundings_ad_i18n', 'admin', array['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
select table_privs_are('surroundings_ad_i18n', 'authenticator', array[]::text[]);
select has_column('surroundings_ad_i18n', 'company_id');
select col_is_fk('surroundings_ad_i18n', 'company_id');
select fk_ok('surroundings_ad_i18n', 'company_id', 'surroundings_ad', 'company_id');
select col_type_is('surroundings_ad_i18n', 'company_id', 'integer');
select col_not_null('surroundings_ad_i18n', 'company_id');
select col_hasnt_default('surroundings_ad_i18n', 'company_id');
select has_column('surroundings_ad_i18n', 'lang_tag');
select col_is_fk('surroundings_ad_i18n', 'lang_tag');
select fk_ok('surroundings_ad_i18n', 'lang_tag', 'language', 'lang_tag');
select col_type_is('surroundings_ad_i18n', 'lang_tag', 'text');
select col_not_null('surroundings_ad_i18n', 'lang_tag');
select col_hasnt_default('surroundings_ad_i18n', 'lang_tag');
select has_column('surroundings_ad_i18n', 'title');
select col_type_is('surroundings_ad_i18n', 'title', 'text');
select col_not_null('surroundings_ad_i18n', 'title');
select col_hasnt_default('surroundings_ad_i18n', 'title');
select has_column('surroundings_ad_i18n', 'anchor');
select col_type_is('surroundings_ad_i18n', 'anchor', 'text');
select col_not_null('surroundings_ad_i18n', 'anchor');
select col_hasnt_default('surroundings_ad_i18n', 'anchor');
select *
from finish();
rollback;

View File

@ -0,0 +1,101 @@
-- Test translate_surroundings_ad
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_surroundings_ad', array['integer', 'text', 'text', 'text']);
select function_lang_is('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text'], 'sql');
select function_returns('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text'], 'void');
select isnt_definer('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text']);
select volatility_is('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text'], 'volatile');
select function_privs_are('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text'], 'guest', array[]::text[]);
select function_privs_are('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text'], 'employee', array[]::text[]);
select function_privs_are('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text'], 'admin', array['EXECUTE']);
select function_privs_are('camper', 'translate_surroundings_ad', array['integer', 'text', 'text', 'text'], 'authenticator', array[]::text[]);
set client_min_messages to warning;
truncate surroundings_ad_i18n cascade;
truncate surroundings_ad 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, tourist_tax, country_code, currency_code, default_lang_tag)
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', '', 60, 'ES', 'EUR', 'ca')
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', '', 60, 'FR', 'USD', 'ca')
;
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 media_content (media_type, bytes)
values ('text/plain', 'content2')
, ('text/plain', 'content4')
;
insert into media (media_id, company_id, original_filename, content_hash)
values ( 7, 2, 'text2.txt', sha256('content2'))
, ( 8, 4, 'text3.txt', sha256('content4'))
;
insert into surroundings_ad (company_id, media_id, title, anchor, href)
values (2, 7, 'Ad 2', 'Go!', 'https://ddg.gg/')
, (4, 8, 'Ad 4', 'Go!', 'https://ddg.gg/')
;
insert into surroundings_ad_i18n (company_id, lang_tag, title, anchor)
values (2, 'ca', 'anun 2', 'au!')
;
select lives_ok(
$$ select translate_surroundings_ad(4, 'es', 'Anuncio 4', '¡Ve!') $$,
'Should be able to translate the ad from the first company to Spanish'
);
select lives_ok(
$$ select translate_surroundings_ad(4, 'ca', 'Anunci 4', 'Ves!') $$,
'Should be able to translate the ad from the first company to Catalan'
);
select lives_ok(
$$ select translate_surroundings_ad(2, 'ca', 'Anunci 2', 'Ups!') $$,
'Should be able to update Catalan translation of the ad from the first company'
);
select bag_eq(
$$ select company_id, lang_tag, title, anchor from surroundings_ad_i18n $$,
$$ values (2, 'ca', 'Anunci 2', 'Ups!')
, (4, 'ca', 'Anunci 4', 'Ves!')
, (4, 'es', 'Anuncio 4', '¡Ve!')
$$,
'The translations should have been updated.'
);
select *
from finish();
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:remove_surroundings_ad on pg
begin;
select has_function_privilege('camper.remove_surroundings_ad(integer)', 'execute');
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:setup_surroundings_ad on pg
begin;
select has_function_privilege('camper.setup_surroundings_ad(integer, integer, text, text, uri)', 'execute');
rollback;

View File

@ -0,0 +1,19 @@
-- Verify camper:surroundings_ad on pg
begin;
select company_id
, media_id
, title
, anchor
, href
from camper.surroundings_ad
where false;
select 1 / count(*) from pg_class where oid = 'camper.surroundings_ad'::regclass and relrowsecurity;
select 1 / count(*) from pg_policy where polname = 'guest_ok' and polrelid = 'camper.surroundings_ad'::regclass;
select 1 / count(*) from pg_policy where polname = 'insert_to_company' and polrelid = 'camper.surroundings_ad'::regclass;
select 1 / count(*) from pg_policy where polname = 'update_company' and polrelid = 'camper.surroundings_ad'::regclass;
select 1 / count(*) from pg_policy where polname = 'delete_from_company' and polrelid = 'camper.surroundings_ad'::regclass;
rollback;

View File

@ -0,0 +1,12 @@
-- Verify camper:surroundings_ad_i18n on pg
begin;
select company_id
, lang_tag
, title
, anchor
from camper.surroundings_ad_i18n
where false;
rollback;

View File

@ -0,0 +1,7 @@
-- Verify camper:translate_surroundings_ad on pg
begin;
select has_function_privilege('camper.translate_surroundings_ad(integer, text, text, text)', 'execute');
rollback;

View File

@ -1443,65 +1443,66 @@ address {
/* surrounding */ /* surrounding */
.ad-container { #surroundings-ad {
display: flex; display: flex;
flex-direction: row; margin: 5rem 0;
flex-wrap: wrap; border-radius: .6rem;
margin: 50px 0; overflow: hidden;
}
.ad-image-container {
width: 50%;
min-height: 300px;
border-top-left-radius: .6rem;
border-bottom-left-radius:.8rem;
background-image: url(https://campingmontagut.tandem.ws/media/0c0625998215b6caec6e871ab26d791c330f34bb46a2facc9d502d769d207e7b/barranquisme.jpg);
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
}
.ad-description-container {
width: 50%;
min-height: 300px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 50px;
border-top-right-radius: .6rem;
border-bottom-right-radius: .6rem;
background-color: var(--accent-2); background-color: var(--accent-2);
} }
.ad-description-container h3 { #surroundings-ad::before {
font-size: calc(16px + .7vw); content: '';
font-weight: 400; background: var(--background-image) center center no-repeat;
line-height: 9rem; background-size: cover;
min-height: 30rem;
} }
.ad-button { #surroundings-ad::before, #surroundings-ad > div {
font-size: calc(18px + 1.7vw); flex: 1;
}
#surroundings-ad > div {
display: flex;
flex-direction: column;
justify-content: center;
padding: 5rem;
}
#surroundings-ad h3 {
font-size: calc(1.6rem + .7vw);
font-weight: 400;
margin-bottom: 2.585rem;
}
#surroundings-ad a {
font-size: calc(1.8rem + 1.7vw);
font-weight: 600; font-weight: 600;
line-height: 0.9em; line-height: 0.9em;
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
column-gap: 0.5em; gap: 0.5em;
border-radius: .6rem;
color: var(--contrast); color: var(--contrast);
} }
.ad-button .ad-icon svg { #surroundings-ad svg {
width: 40px; width: 4rem;
transform: rotate(320deg) translate3d(-5px, -10px, 0); transform: rotate(320deg) translate3d(-5px, -10px, 0);
transition: all 0.5s ease; transition: transform 0.5s ease;
} }
.ad-button:hover .gb-icon svg { #surroundings-ad a:hover svg {
transform: rotate(320deg) translate3d(10px, 0, 0); transform: rotate(320deg) translate3d(10px, 0, 0);
} }
.arrow_link { @media (max-width: 48rem) {
fill: var(--contrast); #surroundings-ad {
flex-direction: column-reverse;
}
#surroundings-ad > div {
justify-content: start;
}
} }
/* services */ /* services */

View File

@ -11,6 +11,60 @@
{{ define "content" -}} {{ define "content" -}}
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/surroundings.highlightIndex*/ -}} {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/surroundings.highlightIndex*/ -}}
<h2>{{( pgettext "Ad" "title" )}}</h2>
{{ with .Ad -}}
<form data-hx-put="/admin/surroundings/ad">
{{ CSRFInput }}
<fieldset {{ template "init-lang" . }}>
{{ with .Title -}}
<fieldset>
<legend>{{( pgettext "Title" "input")}}</legend>
{{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<input type="text" name="{{ $input.Name }}" value="{{ $input.Val }}"
{{ template "error-attrs" . }}><br>
</label>
{{- end }}
{{ template "error-message" . }}
</fieldset>
{{- end }}
{{ with .Media -}}
{{ template "media-picker" . }}
{{- end }}
{{ with .Anchor -}}
<fieldset>
<legend>{{( pgettext "Link Text" "input")}}</legend>
{{ template "lang-selector" . }}
{{ range $lang, $input := . -}}
<label x-cloak x-show="lang === '{{ $lang }}'"><span>{{ $lang }}</span><br>
<input type="text" name="{{ $input.Name }}" value="{{ $input.Val }}"
{{ template "error-attrs" . }}><br>
</label>
{{- end }}
{{ template "error-message" . }}
</fieldset>
{{- end }}
{{ with .HRef -}}
<label>
{{( pgettext "Link URL" "input")}}<br>
<input type="url" name="{{ .Name }}" value="{{ .Val }}"
required {{ template "error-attrs" . }}><br>
</label>
{{ template "error-message" . }}
{{- end }}
</fieldset>
<footer>
<button type="submit">{{( pgettext "Update" "action" )}}</button>
{{ $confirm := ( gettext "Are you sure you wish to delete the ad?" )}}
<button data-hx-delete="/admin/surroundings/ad"
data-hx-confirm="{{ $confirm }}"
data-hx-headers='{ {{ CSRFHeader }} }'>
{{( pgettext "Delete" "action" )}}
</button>
</footer>
</form>
{{- end }}
<h2>{{( pgettext "Highlights" "title" )}}</h2> <h2>{{( pgettext "Highlights" "title" )}}</h2>
<a href="/admin/surroundings/new">{{( pgettext "Add highlight" "action" )}}</a> <a href="/admin/surroundings/new">{{( pgettext "Add highlight" "action" )}}</a>
{{ if .Highlights -}} {{ if .Highlights -}}

View File

@ -11,22 +11,20 @@
{{- /*gotype: dev.tandem.ws/tandem/camper/pkg/surroundings.surroundingsPage*/ -}} {{- /*gotype: dev.tandem.ws/tandem/camper/pkg/surroundings.surroundingsPage*/ -}}
<h2>{{( pgettext "Surroundings" "title" )}}</h2> <h2>{{( pgettext "Surroundings" "title" )}}</h2>
<section> {{ with .Ad -}}
<div class="ad-container"> <div id="surroundings-ad" style="--background-image: url('{{ .MediaURL }}')">
<div class="ad-image-container"></div> <div>
<div class="ad-description-container"> <h3>{{ .Title }}</h3>
<h3 class="ad-title">Vine a fer barranquisme per Sadernes!</h3> <a href="{{ .HRef }}" rel="nofollow noopener">{{ .Anchor}}
<a class="ad-button" href="#">Reserva el teu dia<span class="ad-icon">
<svg viewBox="0 0 93.69895 67.38545" <svg viewBox="0 0 93.69895 67.38545"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
class="arrow_link"> <path fill="currentColor"
<path d="m67.38545,67.38545l-13.49997-2.97457c.57203-5.72033,2.74576-10.99256,6.52117-15.8167,3.77542-4.82414,8.04659-7.94172,12.81353-9.35273H0v-11.09743h73.22018c-4.76694-1.41101-9.03812-4.53813-12.81353-9.38134-3.77542-4.84321-5.94914-10.12498-6.52117-15.8453l13.49997-2.91737c.26695,8.38981,2.70762,15.01586,7.32202,19.87813s10.94489,7.61757,18.99148,8.26587v11.09743c-8.04659.6483-14.37709,3.40359-18.99148,8.26587-4.6144,4.86228-7.05507,11.48832-7.32202,19.87813Z"/> d="m67.38545,67.38545l-13.49997-2.97457c.57203-5.72033,2.74576-10.99256,6.52117-15.8167,3.77542-4.82414,8.04659-7.94172,12.81353-9.35273H0v-11.09743h73.22018c-4.76694-1.41101-9.03812-4.53813-12.81353-9.38134-3.77542-4.84321-5.94914-10.12498-6.52117-15.8453l13.49997-2.91737c.26695,8.38981,2.70762,15.01586,7.32202,19.87813s10.94489,7.61757,18.99148,8.26587v11.09743c-8.04659.6483-14.37709,3.40359-18.99148,8.26587-4.6144,4.86228-7.05507,11.48832-7.32202,19.87813Z"/>
</svg> </svg>
</span>
</a> </a>
</div> </div>
</div> </div>
</section> {{- end }}
<section class="outside_activities"> <section class="outside_activities">
<h3>{{( pgettext "What to Do Outside the Campsite?" "title" )}}</h3> <h3>{{( pgettext "What to Do Outside the Campsite?" "title" )}}</h3>