Commit Graph

10 Commits

Author SHA1 Message Date
jordi fita mas ef6a8f5aee Add the campsite type cost per season 2023-10-01 21:14:39 +02:00
jordi fita mas 680d51e704 Add max campers and dogs allowed fields to campsite types 2023-09-29 20:17:39 +02:00
jordi fita mas e584e29f46 Make seasons’ calendar dynamic and allow to set/unset ranges
The CSS is not very good, but for testing purposes it will work.
2023-09-27 14:21:27 +02:00
jordi fita mas 97cf117da3 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-21 01:56:44 +02:00
jordi fita mas da127124a1 Add cover media to campsite types
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
2023-09-10 03:04:18 +02:00
jordi fita mas b4919db6c4 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 20:15:57 +02:00
jordi fita mas 50fbfce9ee Add the form to update company’s tax details
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.
2023-08-15 22:35:21 +02:00
jordi fita mas b03ef35a95 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 20:15:09 +02:00
jordi fita mas f963f54839 Add profile form, inside a user menu
This is the first form that uses HTMx, and can not return a 400 error
code because otherwise HTMx does not render the content.

Since now there are pages that do not render the whole html, with header
and body, i need a different layout for these, and moved the common code
to handle forms and such a new template file that both layouts can use.
I also need the request in template.MustRender to check which layout i
should use.

Closes #7.
2023-07-26 20:46:09 +02:00
jordi fita mas 01526bff1a Convert the login variables to a struct with parsing and validation
It is a lot of code having to check the login variables inside the POST
handler, and i could not mark each input field individually as invalid
because the generic errors array i was using did no identify which field
had the error.

Thus, i use more or less the same technique as with Numerus: a struct
with the value and the error message.  This time the input field does
not have the label and extra attributes because i believe this belongs
to the template: if i want do reuse the same form template, i should
create a common template rather than defining everything in Go.

The name is a bit different, however, because it has meaning both to the
front and back ends, as it needs to be exactly the same.  Writing it
twice is error-prone, as with a rename i could easily forget to change
one or the other, and here i see value in having that in Go, because
it is also used in code.
2023-07-24 17:17:15 +02:00