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
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.
It is inside the “user menu” only because this is where Numerus has the
same option, although it makes less sense in this case, because Numerus
is geared toward individual freelancers while Camper is for companies.
But, since it is easy to change afterward, this will do for now.
However, it should be only shown to admin users, because regular
employees have no UPDATE privilege on the company relation. Thus, the
need for a new template function to check if the user is admin.
Part of #17.
For now, there is only the label, type, and active fields. We will need
some field to hold the area on the map, but this requires #4, and
possibly #6, to be finished.
Part of #27.
GrapesJS was not working: too complex for users and not enough for
designers.
Therefore, we decided to use a simple WYSIWYG widget for the campsite
types’ description, while we will do the actual HTML template with an
external editor. Once that is done, we will convert that HTML to Go
templates and get the description’s content from the database.
Now the pages section has no sense: all the pages will be straight Go
templates. Only the pages for “special things”, like campsite types,
will use the database, and only for some fields, not the whole page.
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.
I was starting to add the public page for campsite types, creating more
granular row-level security policies for select, insert, update, and
delete, because now the guest users needed to SELECT them and they have
no related company to filter the rows with. Suddenly, i realized that
the role was wrong in the user relation: a user can be an admin to one
company, and employee to another, and guess to yet another company;
the role should be in the company_user relation instead.
That means that to know the role to set to, the user alone is not enough
and have to know the company as well. Had to change all the
cookie-related function to accept also the company’s host name, as this
is the information that the Go application has.
This form has an “HTML field”, which is just a <textarea> but “improved”
with the use of Automattic’s isolated block editor[0], a repackaged
Gutenberg’s editor playground as full-featured multi-instance editor
that does not require WordPress.
I do not want to use Node to build this huge, over-engineered piece of …
software. Therefore, i downloaded the released “browser” package, and
added the required React bundle, like i do with HTMx. This will hold
until i need a new custom block type; let’s hope i will not need it.
[0]: https://github.com/Automattic/isolated-block-editor
We made the decision that this application will also serve the public
pages to guests and customers, to avoid the overhead of having to
synchronize all data between this application and a bespoke WordPress
plugin.
That means that i no longer can have a /company/slug in the URL to know
which company the request is for, not only because it looks ugly but
because guest users do not have a “main company”—or any company
whatsoever.
Since the public-facing web is going to be served through a valid DNS
domain, and all companies are going to have a different domain, i
realized this is enough: i only had to add a relation of company and
their hosts. The same company can have many hosts for staging servers
or to separate the administration and public parts, for instance.
With change, the company is already known from the first handler, and
can pass it down to all the others, not only the handlers under
/company/slug/whatever. And i no longer need the companyURL function,
as there is no more explicit company in the URL.
Even though template technically does not need the template, as it only
contains the ID —the rest of the data is in a relation inaccessible to
guests for now—, but i left the parameter just in case later on i need
the decimal digits or currency symbol for whatever reason.