This is the image that is shown at the home page, and maybe other pages
in the future. We can not use a static file because this image can be
changed by the customer, not us; just like name and description.
I decided to keep the actual media content in the database, but to copy
this file out to the file system the first time it is accessed. This is
because we are going to replicate the database to a public instance that
must show exactly the same image, but the customer will update the image
from the private instance, behind a firewall. We could also synchronize
the folder where they upload the images, the same way we will replicate,
but i thought that i would make the whole thing a little more brittle:
this way if it can replicate the update of the media, it is impossible
to not have its contents; dumping it to a file is to improve subsequent
requests to the same media.
I use the hex representation of the media’s hash as the URL to the
resource, because PostgreSQL’s base64 is not URL save (i.e., it uses
RFC2045’s charset that includes the forward slash[0]), and i did not
feel necessary write a new function just to slightly reduce the URLs’
length.
Before checking if the file exists, i make sure that the given hash is
an hex string, like i do for UUID, otherwise any other check is going
to fail for sure. I moved out hex.Valid function from UUID to check for
valid hex values, but the actual hash check is inside app/media because
i doubt it will be used outside that module.
[0]: https://datatracker.ietf.org/doc/html/rfc2045#section-6.8
As previously stated, web made the design with an external tool and
had to “convert” it to proper CSS and HTML markup.
Unfortunately, the original design uses slick, that requires jQuery;
i can’t do anything about it now.
Disabled most of the menu and language switcher because it is not in the
design yet.
For now, this is almost identical to the campsite types, but this
section is for purely informational pages that have no other relation
to the database than “belongs to the same company”.
Part of #33.
Had to export and move PublicPage struct to template because i can not
import app from campsites/types: app already imports campsite for the
http handler, and it, in turn, imports the types package for its own
http handler; an import loop.
Also had to replace PublicPage.MustRender with a Setup function because
the page passed down to html/template was the PublicPage struct, not
whatever struct embeds it. I was thinking more of Java inheritance here
rather than struct embedding.
The language switcher needs the same information as languageLinks
needed, namely the list of locales and the current Path, to construct
the URI to all alternate versions. However, in this case i need access
to this data in the template context, to build the list of links.
At first i use request’s context to hold the list of available locales
from application, and it worked, possibly without ill-effects, but i
realized that i was doing it just to avoid a new parameter. Or, more
precise, an _explicit_ parameter; the context was used to skip the
inner functions between app and template.MustRenderPublic, but the
parameter was there all the same.
Finally, i thought that some handler might want to filter the list of
locales to show only the ones that it has a translation of. In that
case, i would need to extract the locales from the context, filter it,
and create a new request with the updated context. That made little
sense, and made me add the explicit locales parameter.
Since now the template has the same data as languageLinks, there is
little point of having the link in the HTTP response headers, and added
the <link> elements to <head>.
I thought that maybe i could avoid these <links> as they give the exact
same data as the language switch, but Google says nothing of using
regular anchors to gather information about localized versions of the
document[0], thus i opted to be conservative. One can reason that the
<head> has more weight for Google, as most sites with user-generated
content, which could contain these anchors, rarely allow users to edit
the <head>.
[0]: https://developers.google.com/search/docs/specialty/international/localized-versions
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