Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
# Catalan translations for camper package
# Traduccions al català del paquet «camper».
# Copyright (C) 2023 THE camper'S COPYRIGHT HOLDER
# This file is distributed under the same license as the camper package.
# jordi fita mas <jordi@tandem.blog>, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: camper\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
2023-09-25 18:10:33 +00:00
"POT-Creation-Date: 2023-09-25 20:03+0200\n"
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
"PO-Revision-Date: 2023-07-22 23:45+0200\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
#: web/templates/public/services.gohtml:6
#: web/templates/public/services.gohtml:15
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:50
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "title"
msgid "Services"
msgstr "Serveis"
#: web/templates/public/services.gohtml:18
msgid "The campsite offers many different services."
msgstr "El càmping disposa de diversos serveis."
2023-09-25 18:10:33 +00:00
#: web/templates/public/home.gohtml:6 web/templates/public/layout.gohtml:29
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
msgctxt "title"
msgid "Home"
msgstr "Inici"
Add the sample campsite types to the demo file
Since campsite types need a media, i have to insert also images to the
media relation. The best would be to use PostgreSQL’s
pg_read_binary_file to read the media content from actual files when
inserting the new rows, but the files need to be within the database
cluster directory, or have to use an absolute path when running as a
superuser to read from files outside the cluster directory, which means
that it would depend on the path where i leave the files, that is
different in development that in staging.
To avoid that problem i can simply insert the rows using their base64
strings, with PostgreSQL’s decode. The images are kind of small, but
i was worried that each change in demo.sql would duplicate that data in
git, even if the change is not related to the images, because git stores
the whole file; even if small, soon everything adds up.
I do not care if the _final_ demo.sql is big, as this file is packaged
in a different deb and is only installed in staging, so i’ve chosen to
use m4 to build a single “amalgamated” SQL file from the base .sql
file and the individual image files converted to base64 strings. That
way, each image is individually managed by git and the base .sql file
does not balloon up for each little change.
Changed m4’s quotes to [[ ]] because the default ` ' was interfering
with Intellij’s syntax highlighting.
2023-09-10 01:57:46 +00:00
#: web/templates/public/home.gohtml:17
2023-09-05 02:40:48 +00:00
msgid "The pleasure of camping in the middle of nature…"
msgstr "El plaer d’ acampar en plena natura…"
Add the sample campsite types to the demo file
Since campsite types need a media, i have to insert also images to the
media relation. The best would be to use PostgreSQL’s
pg_read_binary_file to read the media content from actual files when
inserting the new rows, but the files need to be within the database
cluster directory, or have to use an absolute path when running as a
superuser to read from files outside the cluster directory, which means
that it would depend on the path where i leave the files, that is
different in development that in staging.
To avoid that problem i can simply insert the rows using their base64
strings, with PostgreSQL’s decode. The images are kind of small, but
i was worried that each change in demo.sql would duplicate that data in
git, even if the change is not related to the images, because git stores
the whole file; even if small, soon everything adds up.
I do not care if the _final_ demo.sql is big, as this file is packaged
in a different deb and is only installed in staging, so i’ve chosen to
use m4 to build a single “amalgamated” SQL file from the base .sql
file and the individual image files converted to base64 strings. That
way, each image is individually managed by git and the base .sql file
does not balloon up for each little change.
Changed m4’s quotes to [[ ]] because the default ` ' was interfering
with Intellij’s syntax highlighting.
2023-09-10 01:57:46 +00:00
#: web/templates/public/home.gohtml:18
2023-09-05 02:40:48 +00:00
msgctxt "link"
msgid "Booking"
msgstr "Reserva"
Add the sample campsite types to the demo file
Since campsite types need a media, i have to insert also images to the
media relation. The best would be to use PostgreSQL’s
pg_read_binary_file to read the media content from actual files when
inserting the new rows, but the files need to be within the database
cluster directory, or have to use an absolute path when running as a
superuser to read from files outside the cluster directory, which means
that it would depend on the path where i leave the files, that is
different in development that in staging.
To avoid that problem i can simply insert the rows using their base64
strings, with PostgreSQL’s decode. The images are kind of small, but
i was worried that each change in demo.sql would duplicate that data in
git, even if the change is not related to the images, because git stores
the whole file; even if small, soon everything adds up.
I do not care if the _final_ demo.sql is big, as this file is packaged
in a different deb and is only installed in staging, so i’ve chosen to
use m4 to build a single “amalgamated” SQL file from the base .sql
file and the individual image files converted to base64 strings. That
way, each image is individually managed by git and the base .sql file
does not balloon up for each little change.
Changed m4’s quotes to [[ ]] because the default ` ' was interfering
with Intellij’s syntax highlighting.
2023-09-10 01:57:46 +00:00
#: web/templates/public/home.gohtml:31
2023-09-05 02:40:48 +00:00
msgid "Our services"
msgstr "Els nostres serveis"
Add the sample campsite types to the demo file
Since campsite types need a media, i have to insert also images to the
media relation. The best would be to use PostgreSQL’s
pg_read_binary_file to read the media content from actual files when
inserting the new rows, but the files need to be within the database
cluster directory, or have to use an absolute path when running as a
superuser to read from files outside the cluster directory, which means
that it would depend on the path where i leave the files, that is
different in development that in staging.
To avoid that problem i can simply insert the rows using their base64
strings, with PostgreSQL’s decode. The images are kind of small, but
i was worried that each change in demo.sql would duplicate that data in
git, even if the change is not related to the images, because git stores
the whole file; even if small, soon everything adds up.
I do not care if the _final_ demo.sql is big, as this file is packaged
in a different deb and is only installed in staging, so i’ve chosen to
use m4 to build a single “amalgamated” SQL file from the base .sql
file and the individual image files converted to base64 strings. That
way, each image is individually managed by git and the base .sql file
does not balloon up for each little change.
Changed m4’s quotes to [[ ]] because the default ` ' was interfering
with Intellij’s syntax highlighting.
2023-09-10 01:57:46 +00:00
#: web/templates/public/home.gohtml:34
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
#: web/templates/public/surroundings.gohtml:6
#: web/templates/public/surroundings.gohtml:10
msgctxt "title"
2023-09-11 02:20:21 +00:00
msgid "Surroundings"
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgstr "L’ entorn"
2023-09-05 02:40:48 +00:00
2023-09-11 02:20:21 +00:00
#: web/templates/public/home.gohtml:37
msgid "Located in <strong>Alta Garrotxa</strong>, between the <strong>Pyrenees</strong> and the <strong>Costa Brava</strong>."
msgstr "Situats a l’ <strong>Alta Garrotxa</strong>, entre els <strong>Pirineus</strong> i la <strong>Costa Brava</strong>."
#: web/templates/public/home.gohtml:38
msgid "Nearby there are the <strong>gorges of Sadernes</strong>, <strong>volcanoes</strong>, <strong>La Fageda d’ en Jordà</strong>, the Jewish quarter of <strong>Besalú</strong>, the basaltic cliff of <strong>Castellfollit de la Roca</strong>… much to see and much to do."
msgstr "A prop teniu els <strong>gorgs de Sadernes</strong>, <strong>volcans</strong>, <strong>La Fageda d’ en Jordà</strong>, el call jueu de <strong>Besalú</strong>, la cinglera basàltica de <strong>Castellfollit de la Roca</strong>… molt per veure i molt per fer."
#: web/templates/public/home.gohtml:39
msgid "Less than an hour from <strong>Girona</strong>, one from <strong>La Bisbal d’ Empordà</strong>, and two from <strong>Barcelona</strong>."
msgstr "A menys d’ una hora de <strong>Girona</strong>, a una de <strong>La Bisbal d’ Empordà</strong> i a dues de <strong>Barcelona</strong>."
#: web/templates/public/home.gohtml:40
msgid "Discover the surroundings"
msgstr "Descobreix l’ entorn"
Make home page’s carousel manageable via the database
I debated with myself whether to create the home_carousel relation or
rather if it would be better to have a single carousel relation for all
pages. However, i thought that it would be actually harder to maintain
a single relation because i would need an additional column to tell one
carrousel from another, and what would that column be? An enum? A
foreign key to another relation? home_carousel carries no such issues.
I was starting to duplicate logic all over the packages, such as the
way to encode media paths or “localization” (l10n) input fields.
Therefore, i refactorized them.
In the case of media path, i added a function that accepts rows of
media, because always need the same columns from the row, and it was
yet another repetition if i needed to pass them all the time. Plus,
these kind of functions can be called as `table.function`, that make
them look like columns from the table; if PostgreSQL implemented virtual
generated columns, i would have used that instead.
I am not sure whether that media_path function can be immutable. An
immutable function is “guaranteed to return the same results given the
same arguments forever”, which would be true if the inputs where the
hash and the original_filename columns, instead of the whole rows, but
i left it as static because i did not know whether PostgreSQL interprets
the “same row but with different values” as a different input. That is,
whether PostgreSQL’s concept of row is the actual tuple or the space
that has a rowid, irrespective of contents; in the latter case, the
function can not be immutable. Just to be in the safe side, i left it
stable.
The home page was starting to grow a bit too much inside the app
package, new that it has its own admin handler, and moved it all to a
separate package.
2023-09-14 23:05:38 +00:00
#: web/templates/public/home.gohtml:54
2023-09-05 02:40:48 +00:00
msgid "Come and enjoy!"
msgstr "Vine a gaudir!"
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
#: web/templates/public/surroundings.gohtml:13
msgctxt "title"
msgid "What to Do Outside the Campsite?"
msgstr "Què fer des del càmping?"
#: web/templates/public/surroundings.gohtml:15
msgid "Campsite Montagut is an ideal starting point for quiet outings, climbing, swimming in the river and gorges, volcanoes, the Fageda d’ en Jordà, cycle tours for all ages…."
msgstr "El Càmping Montagut és ideal com a punt de partida d’ excursions tranquil·les, escalada, banyar-se en el riu i gorgues, volcans, la Fageda d’ en Jordà, sortides amb bicicleta per a tots els nivells…."
#: web/templates/public/surroundings.gohtml:22
msgid "Get to the Costa Brava and enjoy the beaches, the gastronomy or go kayaking…."
msgstr "Arribar fins a la costa brava i gaudir de les platges, la gastronomia o anar amb caiac…."
#: web/templates/public/surroundings.gohtml:31
msgid "You will also find museums in Olot, Figures, Girona."
msgstr "També trobareu museus a Olot, Figueres, Girona."
#: web/templates/public/surroundings.gohtml:32
msgid "As well as music festivals, dance, theater…."
msgstr "Com festivals de música, dansa, teatre…."
#: web/templates/public/surroundings.gohtml:38
msgctxt "title"
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"
#: web/templates/public/surroundings.gohtml:41
msgid "Cycle routes"
msgstr "Rutes amb bicicleta"
#: web/templates/public/surroundings.gohtml:42
msgid "There are many bicycle rental companies in Olot."
msgstr "A Olot podeu trobar empreses de lloguer de bicicletes."
#: web/templates/public/surroundings.gohtml:46
msgid "Routes"
msgstr "Rutes"
#: web/templates/public/surroundings.gohtml:47
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."
#: web/templates/public/surroundings.gohtml:51
msgid "Family outing"
msgstr "Excursions familiars"
#: web/templates/public/surroundings.gohtml:52
msgid "Many outing possibilities, for all ages."
msgstr "Múltiples excursions per a totes les edats."
#: web/templates/public/surroundings.gohtml:56
msgid "Kayak"
msgstr "Caiac"
#: web/templates/public/surroundings.gohtml:57
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…."
2023-09-25 18:10:33 +00:00
#: web/templates/public/layout.gohtml:11 web/templates/public/layout.gohtml:24
#: web/templates/public/layout.gohtml:59
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
msgid "Campsite Montagut"
msgstr "Càmping Montagut"
2023-09-25 18:10:33 +00:00
#: web/templates/public/layout.gohtml:22 web/templates/admin/layout.gohtml:19
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
msgid "Skip to main content"
msgstr "Salta al contingut principal"
2023-09-25 18:10:33 +00:00
#: web/templates/public/layout.gohtml:33
2023-08-08 00:29:14 +00:00
msgid "Singular Lodges"
msgstr "Allotjaments singulars"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: web/templates/admin/carousel/form.gohtml:8
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/form.gohtml:25
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
msgid "Edit Carousel Slide"
msgstr "Edició de la diapositiva del carrusel"
#: web/templates/admin/carousel/form.gohtml:10
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/form.gohtml:27
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
msgid "New Carousel Slide"
msgstr "Nova diapositiva del carrusel"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/form.gohtml:37
#: web/templates/admin/carousel/l10n.gohtml:20
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
msgid "Caption"
msgstr "Llegenda"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/form.gohtml:47
#: web/templates/admin/campsite/form.gohtml:70
#: web/templates/admin/campsite/type/form.gohtml:66
#: web/templates/admin/season/form.gohtml:64
#: web/templates/admin/services/form.gohtml:69
#: web/templates/admin/media/form.gohtml:35
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Update"
msgstr "Actualitza"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/form.gohtml:49
#: web/templates/admin/campsite/form.gohtml:72
#: web/templates/admin/campsite/type/form.gohtml:68
#: web/templates/admin/season/form.gohtml:66
#: web/templates/admin/services/form.gohtml:71
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Add"
msgstr "Afegeix"
#: web/templates/admin/carousel/l10n.gohtml:7
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/l10n.gohtml:14
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
msgid "Translate Carousel Slide to %s"
msgstr "Traducció de la diapositiva del carrusel a %s"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:21
#: web/templates/admin/campsite/type/l10n.gohtml:33
#: web/templates/admin/services/l10n.gohtml:21
#: web/templates/admin/services/l10n.gohtml:33
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Source:"
msgstr "Origen:"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:23
#: web/templates/admin/campsite/type/l10n.gohtml:36
#: web/templates/admin/services/l10n.gohtml:23
#: web/templates/admin/services/l10n.gohtml:36
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
msgid "Translation:"
msgstr "Traducció:"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/carousel/l10n.gohtml:32
#: web/templates/admin/campsite/type/l10n.gohtml:45
#: web/templates/admin/services/l10n.gohtml:45
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Translate"
msgstr "Tradueix"
2023-08-14 18:18:26 +00:00
#: web/templates/admin/campsite/form.gohtml:8
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/form.gohtml:25
2023-08-08 00:29:14 +00:00
msgctxt "title"
2023-08-14 18:18:26 +00:00
msgid "Edit Campsite"
msgstr "Edició de l’ allotjament"
2023-08-08 00:29:14 +00:00
2023-08-14 18:18:26 +00:00
#: web/templates/admin/campsite/form.gohtml:10
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/form.gohtml:27
2023-08-04 17:59:58 +00:00
msgctxt "title"
2023-08-14 18:18:26 +00:00
msgid "New Campsite"
msgstr "Nou allotjament"
2023-08-04 17:59:58 +00:00
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/form.gohtml:37
#: web/templates/admin/campsite/index.gohtml:20
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "campsite"
2023-08-14 09:43:58 +00:00
msgid "Active"
msgstr "Actiu"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/form.gohtml:46
2023-08-04 17:59:58 +00:00
msgctxt "input"
2023-08-14 18:18:26 +00:00
msgid "Campsite Type"
msgstr "Tipus d’ allotjament"
2023-08-04 17:59:58 +00:00
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/form.gohtml:51
2023-08-14 18:18:26 +00:00
msgid "Select campsite type"
msgstr "Escolliu un tipus d’ allotjament"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/form.gohtml:60
2023-08-04 17:59:58 +00:00
msgctxt "input"
2023-08-14 18:18:26 +00:00
msgid "Label"
msgstr "Etiqueta"
2023-08-04 17:59:58 +00:00
2023-08-14 18:18:26 +00:00
#: web/templates/admin/campsite/index.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/index.gohtml:12
#: web/templates/admin/layout.gohtml:40 web/templates/admin/layout.gohtml:71
2023-08-14 18:18:26 +00:00
msgctxt "title"
msgid "Campsites"
msgstr "Allotjaments"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/index.gohtml:11
2023-08-14 18:18:26 +00:00
msgctxt "action"
msgid "Add Campsite"
msgstr "Afegeix allotjament"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/index.gohtml:18
2023-08-14 18:18:26 +00:00
msgctxt "header"
msgid "Label"
msgstr "Etiqueta"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/index.gohtml:19
2023-08-14 18:18:26 +00:00
msgctxt "header"
msgid "Type"
msgstr "Tipus"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:35
#: web/templates/admin/season/index.gohtml:31
2023-08-14 18:18:26 +00:00
msgid "Yes"
msgstr "Sí"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/index.gohtml:28
#: web/templates/admin/campsite/type/index.gohtml:35
#: web/templates/admin/season/index.gohtml:31
2023-08-14 18:18:26 +00:00
msgid "No"
msgstr "No"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/index.gohtml:34
2023-08-14 18:18:26 +00:00
msgid "No campsites added yet."
msgstr "No s’ ha afegit cap allotjament encara."
#: web/templates/admin/campsite/type/form.gohtml:8
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/form.gohtml:25
2023-08-14 18:18:26 +00:00
msgctxt "title"
msgid "Edit Campsite Type"
msgstr "Edició del tipus d’ allotjament"
#: web/templates/admin/campsite/type/form.gohtml:10
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/form.gohtml:27
2023-08-14 18:18:26 +00:00
msgctxt "title"
msgid "New Campsite Type"
msgstr "Nou tipus d’ allotjament"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/form.gohtml:37
#: web/templates/admin/campsite/type/index.gohtml:19
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "campsite type"
msgid "Active"
msgstr "Actiu"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/form.gohtml:46
#: web/templates/admin/campsite/type/l10n.gohtml:20
#: web/templates/admin/season/form.gohtml:46
#: web/templates/admin/services/form.gohtml:52
#: web/templates/admin/services/l10n.gohtml:20
2023-08-14 18:18:26 +00:00
#: web/templates/admin/profile.gohtml:26
msgctxt "input"
msgid "Name"
msgstr "Nom"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/form.gohtml:57
#: web/templates/admin/campsite/type/l10n.gohtml:32
#: web/templates/admin/services/form.gohtml:60
#: web/templates/admin/services/l10n.gohtml:32
2023-08-14 18:18:26 +00:00
msgctxt "input"
msgid "Description"
msgstr "Descripció"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/campsite/type/index.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/index.gohtml:12
#: web/templates/admin/layout.gohtml:37
2023-08-04 17:59:58 +00:00
msgctxt "title"
msgid "Campsite Types"
msgstr "Tipus d’ allotjaments"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/index.gohtml:11
2023-08-04 17:59:58 +00:00
msgctxt "action"
msgid "Add Type"
msgstr "Afegeix tipus"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/index.gohtml:17
#: web/templates/admin/season/index.gohtml:17
2023-08-04 17:59:58 +00:00
msgctxt "header"
msgid "Name"
msgstr "Nom"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/index.gohtml:18
#: web/templates/admin/services/index.gohtml:19
#: web/templates/admin/services/index.gohtml:56
#: web/templates/admin/home/index.gohtml:19
2023-09-12 18:20:23 +00:00
msgctxt "campsite type"
msgid "Translations"
msgstr "Traduccions"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/index.gohtml:41
2023-08-04 17:59:58 +00:00
msgid "No campsite types added yet."
msgstr "No s’ ha afegit cap tipus d’ allotjament encara."
2023-09-12 18:20:23 +00:00
#: web/templates/admin/campsite/type/l10n.gohtml:7
2023-09-25 18:10:33 +00:00
#: web/templates/admin/campsite/type/l10n.gohtml:14
2023-09-12 18:20:23 +00:00
msgctxt "title"
msgid "Translate Campsite Type to %s"
msgstr "Traducció del tipus d’ allotjament a %s"
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
#: web/templates/admin/season/form.gohtml:8
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/form.gohtml:25
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "title"
msgid "Edit Season"
msgstr "Edició de la temporada"
#: web/templates/admin/season/form.gohtml:10
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/form.gohtml:27
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "title"
msgid "New Season"
msgstr "Nova temporada"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/form.gohtml:37
#: web/templates/admin/season/index.gohtml:19
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "season"
msgid "Active"
msgstr "Activa"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/form.gohtml:54
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "input"
msgid "Color"
msgstr "Color"
#: web/templates/admin/season/index.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/index.gohtml:12
#: web/templates/admin/layout.gohtml:43
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "title"
msgid "Seasons"
msgstr "Temporades"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/index.gohtml:11
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "action"
msgid "Add Season"
msgstr "Afegeix temporada"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/index.gohtml:18
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgctxt "header"
msgid "Color"
msgstr "Color"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/season/index.gohtml:37
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
msgid "No seasons added yet."
msgstr "No s’ ha afegit cap temporada encara."
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/dashboard.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/dashboard.gohtml:10 web/templates/admin/layout.gohtml:68
Get user from database based on cookie and serve login if not logged in
To get the user from the database i have to set the cookie first, that
was already done in database.MustAcquire, but i thought they were too
far apart, even thought they are so related. So, the cookie, and thus
the role, is set when getting the user, that is actually the first thing
to do once the connection is acquired. However, that way the database
package has no knowledge of cookies, and the code that sets the cookie
and retrieves the user are next to each other.
I applied the same logic to the changes of locale.Match: it has not
business knowing that the accept language string comes from a request;
it only needs the actual string. Also, the TODO comment about getting
the user’s locale made no sense, now, because app already knows that
locale, so there is no need to pass the user to the locale package.
Getting the locale is done after retrieving the user from the database,
for the same reason the connection is Acquired as far up as possible:
almost every request will need this value, together with the user and
the database connection.
I am a bit affraid that i will end up with functions that always expect
these three values. Maybe i can put the locale inside user, as it is
the user’s locale, after all, no matter if it came from the database or
the user agent, but connection and user must be separate, i think.
We’ll see.
2023-07-25 23:50:39 +00:00
msgctxt "title"
msgid "Dashboard"
msgstr "Tauler"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/login.gohtml:6 web/templates/admin/login.gohtml:13
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
msgctxt "title"
msgid "Login"
msgstr "Entrada"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/login.gohtml:22 web/templates/admin/profile.gohtml:35
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:50
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
msgctxt "input"
msgid "Email"
msgstr "Correu-e"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/login.gohtml:31 web/templates/admin/profile.gohtml:46
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
msgctxt "input"
msgid "Password"
msgstr "Contrasenya"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/login.gohtml:40
Add the skeleton of the web application
It does nothing more than to server a single page that does nothing
interesting.
This time i do not use a router. Instead, i am trying out a technique
i have seen in an article[0] that i have tried in other, smaller,
projects and seems to work surprisingly well: it just “cuts off” the
URI path by path, passing the request from handler to handler until
it finds its way to a handler that actually serves the request.
That helps to loosen the coupling between the application and lower
handlers, and makes dependencies explicit, because i need to pass the
locale, company, etc. down instead of storing them in contexts. Let’s
see if i do not regret it on a later date.
I also made a lot more packages that in Numerus. In Numerus i actually
only have the single pkg package, and it works, kind of, but i notice
how i name my methods to avoid clashing instead of using packages for
that. That is, instead of pkg.NewApp i now have app.New.
Initially i thought that Locale should be inside app, but then there was
a circular dependency between app and template. That is why i created a
separate package, but now i am wondering if template should be inside
app too, but then i would have app.MustRenderTemplate instead of
template.MustRender.
The CSS is the most bare-bones file i could write because i am focusing
in markup right now; Oriol will fill in the file once the application is
working.
[0]: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
2023-07-22 22:11:00 +00:00
msgctxt "action"
msgid "Login"
msgstr "Entra"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/form.gohtml:8
#: web/templates/admin/services/form.gohtml:25
msgctxt "title"
msgid "Edit Service"
msgstr "Edició de servei"
#: web/templates/admin/services/form.gohtml:10
#: web/templates/admin/services/form.gohtml:27
msgctxt "title"
msgid "New Service"
msgstr "Nou servei"
#: web/templates/admin/services/form.gohtml:34
msgctxt "input"
msgid "Icon"
msgstr "Icona"
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
#: web/templates/admin/services/index.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/layout.gohtml:52
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "title"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Services Page"
msgstr "Pàgina de serveis"
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:11
#: web/templates/admin/home/index.gohtml:11
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "title"
msgid "Carousel"
msgstr "Carrusel"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:12
#: web/templates/admin/home/index.gohtml:12
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "action"
msgid "Add slide"
msgstr "Afegeix diapositiva"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:17
#: web/templates/admin/home/index.gohtml:17
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "header"
msgid "Image"
msgstr "Imatge"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:18
#: web/templates/admin/home/index.gohtml:18
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "header"
msgid "Caption"
msgstr "Llegenda"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:20
#: web/templates/admin/services/index.gohtml:57
#: web/templates/admin/home/index.gohtml:20
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "campsite type"
msgid "Actions"
msgstr "Accions"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:39
#: web/templates/admin/services/index.gohtml:73
#: web/templates/admin/home/index.gohtml:39
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgctxt "action"
msgid "Delete"
msgstr "Esborra"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:47
#: web/templates/admin/home/index.gohtml:47
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
msgid "No slides added yet."
msgstr "No s’ ha afegit cap diapositiva encara."
2023-09-25 18:10:33 +00:00
#: web/templates/admin/services/index.gohtml:55
msgctxt "header"
msgid "Service"
msgstr "Servei"
#: web/templates/admin/services/index.gohtml:81
msgid "No services added yet."
msgstr "No s’ ha afegit cap servei encara."
#: web/templates/admin/services/l10n.gohtml:7
#: web/templates/admin/services/l10n.gohtml:14
msgctxt "title"
msgid "Translate Service to %s"
msgstr "Traducció del servei a %s"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/profile.gohtml:6 web/templates/admin/profile.gohtml:12
2023-09-25 18:10:33 +00:00
#: web/templates/admin/layout.gohtml:30
2023-07-26 18:46:09 +00:00
msgctxt "title"
msgid "Profile"
msgstr "Perfil"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/profile.gohtml:17
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
msgctxt "inut"
msgid "Profile Image"
msgstr "Imatge del perfil"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/profile.gohtml:43
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
msgctxt "legend"
msgid "Change password"
msgstr "Canvi de contrasenya"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/profile.gohtml:55
2023-07-26 18:46:09 +00:00
msgctxt "input"
msgid "Password Confirmation"
msgstr "Confirmació de la contrasenya"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/profile.gohtml:65
2023-07-26 18:46:09 +00:00
msgctxt "input"
msgid "Language"
msgstr "Idioma"
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
#: web/templates/admin/profile.gohtml:75
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:144
2023-07-26 18:46:09 +00:00
msgctxt "action"
msgid "Save changes"
msgstr "Desa els canvis"
2023-08-15 20:35:21 +00:00
#: web/templates/admin/taxDetails.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:12
2023-08-15 20:35:21 +00:00
msgctxt "title"
msgid "Tax Details"
msgstr "Configuració fiscal"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:17
#: web/templates/admin/taxDetails.gohtml:58
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Business Name"
msgstr "Nom de l’ empresa"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:26
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "VAT Number"
msgstr "NIF"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:34
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Trade Name"
msgstr "Nom comercial"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:42
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Phone"
msgstr "Telèfon"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:66
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Address"
msgstr "Adreça"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:74
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "City"
msgstr "Població"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:82
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Province"
msgstr "Província"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:90
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Postal Code"
msgstr "Codi postal"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:98
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Country"
msgstr "País"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:108
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Currency"
msgstr "Moneda"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:118
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Default Language"
msgstr "Idioma per defecte"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:128
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Invoice Number Format"
msgstr "Format del número de factura"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/taxDetails.gohtml:136
2023-08-15 20:35:21 +00:00
msgctxt "input"
msgid "Legal Disclaimer"
msgstr "Nota legal"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/layout.gohtml:26
2023-07-26 18:46:09 +00:00
msgctxt "title"
msgid "User Menu"
msgstr "Menú d’ usuari"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/layout.gohtml:34
2023-08-15 20:35:21 +00:00
msgctxt "title"
msgid "Company Settings"
msgstr "Paràmetres de l’ empresa"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/layout.gohtml:46
#: web/templates/admin/media/index.gohtml:6
#: web/templates/admin/media/index.gohtml:11
msgctxt "title"
msgid "Media"
msgstr "Mèdia"
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
2023-09-25 18:10:33 +00:00
#: web/templates/admin/layout.gohtml:49 web/templates/admin/home/index.gohtml:6
Make home page’s carousel manageable via the database
I debated with myself whether to create the home_carousel relation or
rather if it would be better to have a single carousel relation for all
pages. However, i thought that it would be actually harder to maintain
a single relation because i would need an additional column to tell one
carrousel from another, and what would that column be? An enum? A
foreign key to another relation? home_carousel carries no such issues.
I was starting to duplicate logic all over the packages, such as the
way to encode media paths or “localization” (l10n) input fields.
Therefore, i refactorized them.
In the case of media path, i added a function that accepts rows of
media, because always need the same columns from the row, and it was
yet another repetition if i needed to pass them all the time. Plus,
these kind of functions can be called as `table.function`, that make
them look like columns from the table; if PostgreSQL implemented virtual
generated columns, i would have used that instead.
I am not sure whether that media_path function can be immutable. An
immutable function is “guaranteed to return the same results given the
same arguments forever”, which would be true if the inputs where the
hash and the original_filename columns, instead of the whole rows, but
i left it as static because i did not know whether PostgreSQL interprets
the “same row but with different values” as a different input. That is,
whether PostgreSQL’s concept of row is the actual tuple or the space
that has a rowid, irrespective of contents; in the latter case, the
function can not be immutable. Just to be in the safe side, i left it
stable.
The home page was starting to grow a bit too much inside the app
package, new that it has its own admin handler, and moved it all to a
separate package.
2023-09-14 23:05:38 +00:00
msgctxt "title"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Home Page"
msgstr "Pàgina d’ inici"
Make home page’s carousel manageable via the database
I debated with myself whether to create the home_carousel relation or
rather if it would be better to have a single carousel relation for all
pages. However, i thought that it would be actually harder to maintain
a single relation because i would need an additional column to tell one
carrousel from another, and what would that column be? An enum? A
foreign key to another relation? home_carousel carries no such issues.
I was starting to duplicate logic all over the packages, such as the
way to encode media paths or “localization” (l10n) input fields.
Therefore, i refactorized them.
In the case of media path, i added a function that accepts rows of
media, because always need the same columns from the row, and it was
yet another repetition if i needed to pass them all the time. Plus,
these kind of functions can be called as `table.function`, that make
them look like columns from the table; if PostgreSQL implemented virtual
generated columns, i would have used that instead.
I am not sure whether that media_path function can be immutable. An
immutable function is “guaranteed to return the same results given the
same arguments forever”, which would be true if the inputs where the
hash and the original_filename columns, instead of the whole rows, but
i left it as static because i did not know whether PostgreSQL interprets
the “same row but with different values” as a different input. That is,
whether PostgreSQL’s concept of row is the actual tuple or the space
that has a rowid, irrespective of contents; in the latter case, the
function can not be immutable. Just to be in the safe side, i left it
stable.
The home page was starting to grow a bit too much inside the app
package, new that it has its own admin handler, and moved it all to a
separate package.
2023-09-14 23:05:38 +00:00
2023-09-25 18:10:33 +00:00
#: web/templates/admin/layout.gohtml:57
msgctxt "action"
msgid "Logout"
msgstr "Surt"
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
#: web/templates/admin/media/picker.gohtml:8
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
msgid "Media Picker"
msgstr "Selector de mèdia"
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
#: web/templates/admin/media/picker.gohtml:19
msgctxt "title"
msgid "Upload New Media"
msgstr "Pujada de nou mèdia"
#: web/templates/admin/media/picker.gohtml:22
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/upload.gohtml:17
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgctxt "input"
msgid "File"
msgstr "Fitxer"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: web/templates/admin/media/picker.gohtml:26
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/form.gohtml:22
#: web/templates/admin/media/upload.gohtml:21
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgid "Maximum upload file size: %s"
msgstr "Mida màxima del fitxer a pujar: %s"
#: web/templates/admin/media/picker.gohtml:31
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/upload.gohtml:26
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgctxt "action"
msgid "Upload"
msgstr "Puja"
Add campsite map in SVG
I intend to use the same SVG file for customers and employees, so i had
to change Oriol’s design to add a class to layers that are supposed to
be only for customers, like trees. These are hidden in the admin area.
I understood that customers and employees have to click on a campsite to
select it, and then they can book or whatever they need to do to them.
Since customers and employees most certainly will need to have different
listeners on campsites, i decided to add the link with JavaScript. To
do so, i need a custom XML attribute with the campsite’s identifier.
Since i have seen that all campsites have a label, i changed the
“identifier” to the unique combination (company_id, label). The
company_id is there because different companies could have the same
label; i left the campsite_id primary key for foreign constraints.
In this case, as a test, i add an <a> element to the campsite with a
link to edit it; we’ll discuss with Oriol what exactly it needs to do.
However, the original design had the labels in a different layer, that
interfered with the link, as the numbers must be above the path and
the link must wrap the path in order to “inherit” its shape. I had no
other recourse than to move the labels in the same layer as the paths’.
2023-09-24 01:17:13 +00:00
#: web/templates/admin/media/picker.gohtml:47
Add the upload form to the media picker
It makes easier to upload new images from the place where we need it,
instead of having to go to the media section each time.
It was a little messy, this one.
First of all, I realized that POSTint to /admin/media/picker to get the
new media field was wrong: i was not asking the server to “accept an
entity”, but only requesting a new HTML value, just like a GET to
/admin/media/upload requests the form to upload a new media, thus here
i should do the same, except i needed the query parameters to change the
field, which is fine—it is actually a different resource, thus a
different URL.
Then, i thought that i could not POST the upload to /admin/media,
because i returned a different HTML —the media field—, so i reused the
recently unused POST to /admin/media/picker to upload that file and
return the HTML for the field. It was wrong, because i was not
requesting the server to put the file as a subordinate of
/admin/media/picker, only /admin/media, but i did not come up with any
other solution.
Since i had two different upload functions now, i created uploadForm’s
Handle method to refactorize the duplicated logic to a single place.
Unfortunately, i did not work as i expected because uploadForm’s and
mediaPicker’s MustRender methods are different, and mediaPicker has to
embed uploadForm to render the form in the picker. That made me change
Handle’s output to a boolean and error in order for the HTTP handler
function know when to render the form with the error messages with the
proper MustRender handler.
However, I saw the opportunity of reusing that Handler method for
editMedia, that was doing mostly the same job, but had to call a
different Validate than uploadForm’s, because editMedia does not require
the uploaded file. That’s when i realized that i could use an interface
and that this interface could be reused not only within media but
throughout the application, and added HandleMultipart in form.
Had to create a different interface for multipart forms because they
need different parameters in Parse that non-multipart form, when i add
that interface, hence had to also change Parse to ParseForm to account
for the difference in signature; not a big deal.
After all that, i realized that i **could** POST to /admin/media in both
cases, because i always return “an HTML entity”, it just happens that
for the media section it is empty with a redirect, and for the picker is
the field. That made the whole Handle method a bit redundant, but i
left it nevertheless, as i find it slightly easier to read the
uploadMedia function now.
2023-09-21 23:40:22 +00:00
msgctxt "title"
msgid "Choose Existing Media"
msgstr "Elecció d’ un mèdia existent"
Add campsite map in SVG
I intend to use the same SVG file for customers and employees, so i had
to change Oriol’s design to add a class to layers that are supposed to
be only for customers, like trees. These are hidden in the admin area.
I understood that customers and employees have to click on a campsite to
select it, and then they can book or whatever they need to do to them.
Since customers and employees most certainly will need to have different
listeners on campsites, i decided to add the link with JavaScript. To
do so, i need a custom XML attribute with the campsite’s identifier.
Since i have seen that all campsites have a label, i changed the
“identifier” to the unique combination (company_id, label). The
company_id is there because different companies could have the same
label; i left the campsite_id primary key for foreign constraints.
In this case, as a test, i add an <a> element to the campsite with a
link to edit it; we’ll discuss with Oriol what exactly it needs to do.
However, the original design had the labels in a different layer, that
interfered with the link, as the numbers must be above the path and
the link must wrap the path in order to “inherit” its shape. I had no
other recourse than to move the labels in the same layer as the paths’.
2023-09-24 01:17:13 +00:00
#: web/templates/admin/media/picker.gohtml:58
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/index.gohtml:20
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "No media uploaded yet."
msgstr "No s’ ha pujat cap mèdia encara."
Add campsite map in SVG
I intend to use the same SVG file for customers and employees, so i had
to change Oriol’s design to add a class to layers that are supposed to
be only for customers, like trees. These are hidden in the admin area.
I understood that customers and employees have to click on a campsite to
select it, and then they can book or whatever they need to do to them.
Since customers and employees most certainly will need to have different
listeners on campsites, i decided to add the link with JavaScript. To
do so, i need a custom XML attribute with the campsite’s identifier.
Since i have seen that all campsites have a label, i changed the
“identifier” to the unique combination (company_id, label). The
company_id is there because different companies could have the same
label; i left the campsite_id primary key for foreign constraints.
In this case, as a test, i add an <a> element to the campsite with a
link to edit it; we’ll discuss with Oriol what exactly it needs to do.
However, the original design had the labels in a different layer, that
interfered with the link, as the numbers must be above the path and
the link must wrap the path in order to “inherit” its shape. I had no
other recourse than to move the labels in the same layer as the paths’.
2023-09-24 01:17:13 +00:00
#: web/templates/admin/media/picker.gohtml:61
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Cancel"
msgstr "Canceŀla"
#: web/templates/admin/media/form.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/form.gohtml:12
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "title"
msgid "Edit Media"
msgstr "Edició de mèdia"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/form.gohtml:18
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
msgid "Updated file"
msgstr "Fitxer actualitzat"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/form.gohtml:27
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
msgid "Filename"
msgstr "Nom del fitxer"
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/index.gohtml:12
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "action"
msgid "Upload media"
msgstr "Puja mèdia"
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
#: web/templates/admin/media/upload.gohtml:6
2023-09-25 18:10:33 +00:00
#: web/templates/admin/media/upload.gohtml:12
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgctxt "title"
msgid "Upload Media"
msgstr "Pujada de mèdia"
2023-09-22 00:17:56 +00:00
#: pkg/carousel/admin.go:233
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgctxt "input"
2023-09-22 00:17:56 +00:00
msgid "Slide image"
msgstr "Imatge de la diapositiva"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: pkg/carousel/admin.go:234
msgctxt "action"
2023-09-22 00:17:56 +00:00
msgid "Set slide image"
msgstr "Estableix la imatge de la diapositiva"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: pkg/carousel/admin.go:286
msgid "Slide image can not be empty."
msgstr "No podeu deixar la imatge de la diapositiva en blanc."
2023-09-22 00:17:56 +00:00
#: pkg/carousel/admin.go:287
msgid "Slide image must be an image media type."
msgstr "La imatge de la diapositiva ha de ser un mèdia de tipus imatge."
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
2023-08-15 20:35:21 +00:00
#: pkg/app/login.go:56 pkg/app/user.go:246 pkg/company/admin.go:203
2023-07-24 15:17:15 +00:00
msgid "Email can not be empty."
2023-08-08 18:09:57 +00:00
msgstr "No podeu deixar el correu-e en blanc."
2023-07-24 15:17:15 +00:00
2023-08-15 20:35:21 +00:00
#: pkg/app/login.go:57 pkg/app/user.go:247 pkg/company/admin.go:204
2023-07-24 15:17:15 +00:00
msgid "This email is not valid. It should be like name@domain.com."
msgstr "Aquest correu-e no és vàlid. Hauria de ser similar a nom@domini.com."
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
#: pkg/app/login.go:59
2023-07-24 15:17:15 +00:00
msgid "Password can not be empty."
msgstr "No podeu deixar la contrasenya en blanc."
2023-07-26 18:46:09 +00:00
#: pkg/app/login.go:86
2023-07-24 15:17:15 +00:00
msgid "Invalid user or password."
msgstr "Nom d’ usuari o contrasenya incorrectes."
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
2023-08-08 00:29:14 +00:00
#: pkg/app/user.go:197
2023-07-26 18:46:09 +00:00
msgctxt "language option"
msgid "Automatic"
msgstr "Automàtic"
2023-09-14 23:23:51 +00:00
#: pkg/app/user.go:249 pkg/campsite/types/l10n.go:82
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: pkg/campsite/types/admin.go:274 pkg/season/admin.go:203
2023-09-25 18:10:33 +00:00
#: pkg/services/l10n.go:73 pkg/services/admin.go:232
2023-07-26 18:46:09 +00:00
msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc."
2023-08-08 00:29:14 +00:00
#: pkg/app/user.go:250
2023-07-26 18:46:09 +00:00
msgid "Confirmation does not match password."
msgstr "La confirmació no es correspon amb la contrasenya."
2023-08-15 20:35:21 +00:00
#: pkg/app/user.go:251 pkg/company/admin.go:218
2023-07-26 18:46:09 +00:00
msgid "Selected language is not valid."
msgstr "L’ idioma escollit no és vàlid."
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: pkg/app/user.go:253
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
msgid "File must be a valid PNG or JPEG image."
msgstr "El fitxer has de ser una imatge PNG o JPEG vàlida."
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: pkg/app/admin.go:53
Split templates and handlers into admin and public
I need to check that the user is an employee (or admin) in
administration handlers, but i do not want to do it for each handler,
because i am bound to forget it. Thus, i added the /admin sub-path for
these resources.
The public-facing web is the rest of the resources outside /admin, but
for now there is only home, to test whether it works as expected or not.
The public-facing web can not relay on the user’s language settings, as
the guest user has no way to set that. I would be happy to just use the
Accept-Language header for that, but apparently Google does not use that
header[0], and they give four alternatives: a country-specific domain,
a subdomain with a generic top-level domain (gTLD), subdirectories with
a gTLD, or URL parameters (e.g., site.com?loc=de).
Of the four, Google does not recommend URL parameters, and the customer
is already using subdirectories with the current site, therefor that’s
what i have chosen.
Google also tells me that it is a very good idea to have links between
localized version of the same resources, either with <link> elements,
Link HTTP response headers, or a sitemap file[1]; they are all
equivalent in the eyes of Google.
I have choosen the Link response headers way, because for that i can
simply “augment” ResponseHeader to automatically add these headers when
the response status is 2xx, otherwise i would need to pass down the
original URL path until it reaches the template.
Even though Camper is supposed to be a “generic”, multi-company
application, i think i will stick to the easiest route and write the
templates for just the “first” customer.
[0]: https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites
[1]: https://developers.google.com/search/docs/specialty/international/localized-versions
2023-08-05 01:42:37 +00:00
msgid "Access forbidden"
msgstr "Accés prohibit"
2023-09-22 00:17:56 +00:00
#: pkg/campsite/types/admin.go:236
msgctxt "input"
msgid "Cover image"
msgstr "Imatge de portada"
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
#: pkg/campsite/types/admin.go:237
msgctxt "action"
msgid "Set campsite type cover"
msgstr "Estableix la portada del tipus d’ allotjament"
#: pkg/campsite/types/admin.go:275
Add the sample campsite types to the demo file
Since campsite types need a media, i have to insert also images to the
media relation. The best would be to use PostgreSQL’s
pg_read_binary_file to read the media content from actual files when
inserting the new rows, but the files need to be within the database
cluster directory, or have to use an absolute path when running as a
superuser to read from files outside the cluster directory, which means
that it would depend on the path where i leave the files, that is
different in development that in staging.
To avoid that problem i can simply insert the rows using their base64
strings, with PostgreSQL’s decode. The images are kind of small, but
i was worried that each change in demo.sql would duplicate that data in
git, even if the change is not related to the images, because git stores
the whole file; even if small, soon everything adds up.
I do not care if the _final_ demo.sql is big, as this file is packaged
in a different deb and is only installed in staging, so i’ve chosen to
use m4 to build a single “amalgamated” SQL file from the base .sql
file and the individual image files converted to base64 strings. That
way, each image is individually managed by git and the base .sql file
does not balloon up for each little change.
Changed m4’s quotes to [[ ]] because the default ` ' was interfering
with Intellij’s syntax highlighting.
2023-09-10 01:57:46 +00:00
msgid "Cover image can not be empty."
msgstr "No podeu deixar la imatge de portada en blanc."
2023-09-22 00:17:56 +00:00
#: pkg/campsite/types/admin.go:276
msgid "Cover image must be an image media type."
msgstr "La imatge de portada ha de ser un mèdia de tipus imatge."
Add campsite map in SVG
I intend to use the same SVG file for customers and employees, so i had
to change Oriol’s design to add a class to layers that are supposed to
be only for customers, like trees. These are hidden in the admin area.
I understood that customers and employees have to click on a campsite to
select it, and then they can book or whatever they need to do to them.
Since customers and employees most certainly will need to have different
listeners on campsites, i decided to add the link with JavaScript. To
do so, i need a custom XML attribute with the campsite’s identifier.
Since i have seen that all campsites have a label, i changed the
“identifier” to the unique combination (company_id, label). The
company_id is there because different companies could have the same
label; i left the campsite_id primary key for foreign constraints.
In this case, as a test, i add an <a> element to the campsite with a
link to edit it; we’ll discuss with Oriol what exactly it needs to do.
However, the original design had the labels in a different layer, that
interfered with the link, as the numbers must be above the path and
the link must wrap the path in order to “inherit” its shape. I had no
other recourse than to move the labels in the same layer as the paths’.
2023-09-24 01:17:13 +00:00
#: pkg/campsite/admin.go:226
2023-08-14 18:18:26 +00:00
msgid "Selected campsite type is not valid."
msgstr "El tipus d’ allotjament escollit no és vàlid."
Add campsite map in SVG
I intend to use the same SVG file for customers and employees, so i had
to change Oriol’s design to add a class to layers that are supposed to
be only for customers, like trees. These are hidden in the admin area.
I understood that customers and employees have to click on a campsite to
select it, and then they can book or whatever they need to do to them.
Since customers and employees most certainly will need to have different
listeners on campsites, i decided to add the link with JavaScript. To
do so, i need a custom XML attribute with the campsite’s identifier.
Since i have seen that all campsites have a label, i changed the
“identifier” to the unique combination (company_id, label). The
company_id is there because different companies could have the same
label; i left the campsite_id primary key for foreign constraints.
In this case, as a test, i add an <a> element to the campsite with a
link to edit it; we’ll discuss with Oriol what exactly it needs to do.
However, the original design had the labels in a different layer, that
interfered with the link, as the numbers must be above the path and
the link must wrap the path in order to “inherit” its shape. I had no
other recourse than to move the labels in the same layer as the paths’.
2023-09-24 01:17:13 +00:00
#: pkg/campsite/admin.go:227
2023-08-14 18:18:26 +00:00
msgid "Label can not be empty."
msgstr "No podeu deixar l’ etiqueta en blanc."
Add seasons’ relation, functions, and admin section
Seasons have a color to show on the calendar. I need them in HTML format
(e.g., #123abc) in order to set as value to `<input type="color">`, but
i did not want to save them as text in the database, as integers are
better representations of colors—in fact, that’s what the HTML syntax
also is: an integer.
I think the best would be to create an extension that adds an HTML color
type, with functions to convert from many representations (e.g., CSS’
rgb or even color names) to integer and back. However, that’s a lot of
work and i can satisfy Camper’s needs with just a couple of functions
and a domain.
To show the color on the index, at first tried to use a read-only
`<input type="color">`, but seems that this type of input can not be
read-only and must be disabled instead. However, i do not know whether
it makes sense to have a disabled input outside a form “just” to show
a color; i suspect it does not. Thus, at the end i use SVG with a
single circle, which is better that a 50%-rounded div with a background
color, even if the result is the same—SVG **is** intended for showing
pictures, which is this case.
2023-08-16 18:15:57 +00:00
#: pkg/season/admin.go:204
msgid "Color can not be empty."
msgstr "No podeu deixar el color en blanc."
#: pkg/season/admin.go:205
msgid "This color is not valid. It must be like #123abc."
msgstr "Aquest color no és vàlid. Hauria de ser similar a #123abc."
2023-09-25 18:10:33 +00:00
#: pkg/services/admin.go:231
msgid "Selected icon is not valid."
msgstr "La icona escollida no és vàlida."
2023-08-15 20:35:21 +00:00
#: pkg/company/admin.go:186
msgid "Selected country is not valid."
msgstr "El país escollit no és vàlid."
#: pkg/company/admin.go:190
msgid "Business name can not be empty."
msgstr "No podeu deixar el nom d’ empresa en blanc."
#: pkg/company/admin.go:191
msgid "Business name must have at least two letters."
msgstr "El nom d’ empresa ha de tenir com a mínim dues lletres."
#: pkg/company/admin.go:193
msgid "VAT number can not be empty."
msgstr "No podeu deixar el NIF en blanc."
#: pkg/company/admin.go:194
msgid "This VAT number is not valid."
msgstr "Aquest NIF no és vàlid."
#: pkg/company/admin.go:198
msgid "Phone can not be empty."
msgstr "No podeu deixar el telèfon en blanc."
#: pkg/company/admin.go:199
msgid "This phone number is not valid."
msgstr "Aquest número de telèfon no és vàlid."
#: pkg/company/admin.go:207
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:209
msgid "Address can not be empty."
msgstr "No podeu deixar l’ adreça en blanc."
#: pkg/company/admin.go:210
msgid "City can not be empty."
msgstr "No podeu deixar la població en blanc."
#: pkg/company/admin.go:211
msgid "Province can not be empty."
msgstr "No podeu deixar la província en blanc."
#: pkg/company/admin.go:212
msgid "Postal code can not be empty."
msgstr "No podeu deixar el codi postal en blanc."
#: pkg/company/admin.go:213
msgid "This postal code is not valid."
msgstr "Aquest codi postal no és vàlid."
#: pkg/company/admin.go:217
msgid "Selected currency is not valid."
msgstr "La moneda escollida no és vàlida."
#: pkg/company/admin.go:219
msgid "Invoice number format can not be empty."
msgstr "No podeu deixar el format del número de factura en blanc."
Allow users to update their profile images
I do not see the profile image as an “integral part” of the user (i.e.,
no need for constraints), hence i do not want to store it in the
database, as would do for the identification image during check-in.
By default, i store the avatars in /var/lib/camper/avatars, but it is a
variable to allow packagers change this value using the linker.
This is also served as a test bed for uploading files to the server,
that now has a better interface and uses less resources that what i did
to Numerus.
Now the profile handler needs to keep a variable to know the path to the
avatars’ directory, thus i had to change it to a struct nested in app,
much like the fileHandler does. It still has to return the HandlerFunc,
however, as this function needs to close over the user and connection
variables.
Part of #7.
2023-07-28 18:15:09 +00:00
#: pkg/auth/user.go:40
Add the logout button
Conceptually, to logout we have to “delete the session”, thus the best
HTTP verb would be `DELETE`. However, there is no way to send a
`DELETE` request with a regular HTML form, and it seems that never will
be[0].
I could use a POST, optionally with a “method override” technique, but
i was planing to use HTMx anyway, so this was as good an opportunity to
include it as any.
In this application i am not concerned with people not having JavaScript
enabled, because it is for a customer that has a known environment, and
we do not have much time anyway. Therefore, i opted to forgo
progressive enhancement in cases like this: if `DELETE` is needed, use
`hx-delete`.
Unfortunately, i can not use a <form> with a hidden <input> for the
CSRF token, because `DELETE` requests do not have body and the value
should be added as query parameters, like a form with GET method, but
HTMx does the incorrect thing here: sends the values in the request’s
body. That’s why i have to use a custom header and the `hx-header`
directive to include the CSRF token.
Then, by default HTMx targets the triggered element for swap with the
response from the server, but after a logout i want to redirect the
user to the login form again. I could set the hx-target to button to
replace the whole body, or tell the client to redirect to the new
location. I actually do not know which one is “better”. Maybe the
hx-target is best because then everything is handled by the client, but
in the case of logout, since it is possible that i might want to load
scripts only for logged-in users in the future, i opted for the full
page reload.
However, HTMx does not want to reload a page that return HTTP 401,
hence i had to include the GET method to /login in order to return the
login form with a response of HTTP 200, which also helps when
reloading in the browser after a failed login attempt. I am not worried
with the HTTP 401 when attempting to load a page as guest, because
this request most probably comes from the browser, not HTMx, and it will
show the login form as intended—even though it is not compliant, since
it does not return the WWW-Authenticate header, but this is the best i
can do given that no cookie-based authentication method has been
accepted[1].
[0]: https://www.w3.org/Bugs/Public/show_bug.cgi?id=10671#c16
[1]: https://datatracker.ietf.org/doc/id/draft-broyer-http-cookie-auth-00.html
2023-07-26 11:49:47 +00:00
msgid "Cross-site request forgery detected."
msgstr "S’ ha detectat un intent de falsificació de petició a llocs creuats."
2023-08-14 09:43:58 +00:00
Change media picker from <div> to <dialog> and make it modal
Have to call Dialog.showModal when HTMx loaded the dialog in the DOM,
so had to add a onLoad event listened that checks whether the loaded
element is actually a DIALOG.
Had to restrict the margin: 0 for all elements (*) to exclude dialog,
because the browser sets it to auto, and i did not want to set it again
just because i was too overzealous with my “reset”.
The rest of the CSS is just to have a sticky header and footer, and see
the cancel button, that works as a “close”, all the time.
Finally, i realized that if i add the dialog at the end of the fieldset
and let HTMx inherit its hx-target and hx-swap, i no longer need to set
them in the dialog, as HTMx will always replace the fieldset, and i can
have the dialog side by side the current content of the fieldset, that
it was very confusing seeing it disappear when trying to select a new
media.
The cancel button could now just remove the dialog instead of making the
POST, but in local it makes no difference; we’lls see what happens on
production.
2023-09-22 00:11:03 +00:00
#: pkg/media/admin.go:265
Add the surroundings static page
This page is “highly stylized”, with a masonry-like grid, that i did not
know how to generate automatically from data defined in PostgreSQL,
therefore with Oriol we agreed to have this one as a static page and
we will see what we can do if the customer asks to be able to change
it.
I was a bit undecided on whether the icons in the bottom part of the
page should be defined in the CSS or with style="" and CSS variables,
like i do for the campsite type in the home page.
At first i thought that it should use CSS variables, mostly for
coherence: if another section of the web does it for its background
image, why no this one. The difference is that the home page is
dynamically created from the database, while this page is static and we
know what icons we need, thus it makes more sense to move it to the
stylesheet file, because then it will be downloaded by user agents that
actually want to use it (e.g., browsers, but not Braille terminals).
2023-09-16 22:11:39 +00:00
msgid "Uploaded file can not be empty."
msgstr "No podeu deixar el fitxer del mèdia en blanc."
Change media picker from <div> to <dialog> and make it modal
Have to call Dialog.showModal when HTMx loaded the dialog in the DOM,
so had to add a onLoad event listened that checks whether the loaded
element is actually a DIALOG.
Had to restrict the margin: 0 for all elements (*) to exclude dialog,
because the browser sets it to auto, and i did not want to set it again
just because i was too overzealous with my “reset”.
The rest of the CSS is just to have a sticky header and footer, and see
the cancel button, that works as a “close”, all the time.
Finally, i realized that if i add the dialog at the end of the fieldset
and let HTMx inherit its hx-target and hx-swap, i no longer need to set
them in the dialog, as HTMx will always replace the fieldset, and i can
have the dialog side by side the current content of the fieldset, that
it was very confusing seeing it disappear when trying to select a new
media.
The cancel button could now just remove the dialog instead of making the
POST, but in local it makes no difference; we’lls see what happens on
production.
2023-09-22 00:11:03 +00:00
#: pkg/media/admin.go:324
Manage all media uploads in a single place
It made no sense to have a file upload in each form that needs a media,
because to reuse an existing media users would need to upload the exact
same file again; this is very unusual and unfriendly.
A better option is to have a “centralized” media section, where people
can upload files there, and then have a picker to select from there.
Ideally, there would be an upload option in the picker, but i did not
add it yet.
I’ve split the content from the media because i want users to have the
option to update a media, for instance when they need to upload a
reduced or cropped version of the same photo, without an edit they would
need to upload the file as a new media and then update all places where
the old version was used. And i did not want to trouble people that
uploads the same photo twice: without the separate relation, doing so
would throw a constraint error.
I do not believe there is any security problem to have all companies
link their media to the same file, as they were already readable by
everyone and could upload the data from a different company to their
own; in other words, it is not worse than it was now.
2023-09-20 23:56:44 +00:00
msgid "Filename can not be empty."
msgstr "No podeu deixar el nom del fitxer."
Add the services page
This page is more or less similar to home, in terms of database: it
has a carousel and a list of items; in this case, the definition of
campsite services.
As i said early, when adding the home carousel, this carousel has its
own relation and set of functions to manage slides. They are also
duplicated in Go code, but i think i will need to refactor it later to
a carousel package or something like that, because both relations have
the exact same fields and types, so it makes no sense to have twice the
same code.
I already did it with the CSS and JavaScript code, mostly because it was
easier to replace the `.surroundings div` selector with `.carousel`, and
because that way i can have a single template that loads and initializes
Slick.
There is no UI to create or edit service definitions, although there are
the SQL functions, because i have no more time now, and Oriol needs to
check that the style is correct for that page.
2023-09-17 01:42:16 +00:00
#~ msgid "Surroundings"
#~ msgstr "Entorn"
Make home page’s carousel manageable via the database
I debated with myself whether to create the home_carousel relation or
rather if it would be better to have a single carousel relation for all
pages. However, i thought that it would be actually harder to maintain
a single relation because i would need an additional column to tell one
carrousel from another, and what would that column be? An enum? A
foreign key to another relation? home_carousel carries no such issues.
I was starting to duplicate logic all over the packages, such as the
way to encode media paths or “localization” (l10n) input fields.
Therefore, i refactorized them.
In the case of media path, i added a function that accepts rows of
media, because always need the same columns from the row, and it was
yet another repetition if i needed to pass them all the time. Plus,
these kind of functions can be called as `table.function`, that make
them look like columns from the table; if PostgreSQL implemented virtual
generated columns, i would have used that instead.
I am not sure whether that media_path function can be immutable. An
immutable function is “guaranteed to return the same results given the
same arguments forever”, which would be true if the inputs where the
hash and the original_filename columns, instead of the whole rows, but
i left it as static because i did not know whether PostgreSQL interprets
the “same row but with different values” as a different input. That is,
whether PostgreSQL’s concept of row is the actual tuple or the space
that has a rowid, irrespective of contents; in the latter case, the
function can not be immutable. Just to be in the safe side, i left it
stable.
The home page was starting to grow a bit too much inside the app
package, new that it has its own admin handler, and moved it all to a
separate package.
2023-09-14 23:05:38 +00:00
#~ msgid "Legend"
#~ msgstr "Llegenda"
2023-09-11 02:20:21 +00:00
#~ msgid "Environment"
#~ msgstr "Entorn"
2023-08-14 09:43:58 +00:00
#~ msgctxt "input"
#~ msgid "Title"
#~ msgstr "Títol"
#~ msgctxt "input"
#~ msgid "Content"
#~ msgstr "Contingut"
#~ msgctxt "title"
#~ msgid "Pages"
#~ msgstr "Pàgines"
#~ msgctxt "action"
#~ msgid "Add Page"
#~ msgstr "Afegeix pàgina"
#~ msgctxt "header"
#~ msgid "Title"
#~ msgstr "Títol"