Commit Graph

23 Commits

Author SHA1 Message Date
jordi fita mas 0b74c7a91c Instruct htmx that HTTP 422 is not a “fatal error”
I use HTTP 422 to signal that a form was submitted with bad data,
which i believe is the correct status code: “indicates that the server
understands the content type of the request content […], and the syntax
of the request content is correct, but it was unable to process the
contained instructions.”[0]

htmx, however, treats all 4xx status codes as error and, by default,
does not swap the target with the response’s content.  Until i found out
that i could change that behaviour, i worked around this limitation by
returning HTTP 200 for htmx requests, but it is a waste of time given
that htmx _can_ accept HTTP 422 as a non-error.

[0]: https://www.rfc-editor.org/rfc/rfc9110#name-422-unprocessable-content
2024-08-27 11:07:39 +02:00
jordi fita mas 2df6947577 Create constants for the HTMX request and response headers used
It works better with an IDE, and less chance of mistyping something
without notice.
2023-04-06 12:07:20 +02:00
jordi fita mas 9e757cb9f4 Show the profile form in a dialog using HTMx
Had to split the actual page content and the breadcrumbs because they
do not belong in a dialog.  However, i had to change all templates to
do that.
2023-03-20 13:09:52 +01:00
jordi fita mas 4be2597a86 Allow multiple taxes, and even not tax, for products
It seems that we do not agree en whether the IRPF tax should be
something of the product or the contact, so we decided to make the
product have multiple taxes, just in case, and if only one is needed,
then users can just select one; no need to limit to one.
2023-02-08 13:47:36 +01:00
jordi fita mas ae1949024b Allow optional select with empty label
This is not yet necessary, but the empty label is because i do not want
to select a default tax for products—at least, not without a setting for
it.

Since i need to add the required attribute now to select, because
otherwise the browser would allow sending that empty value, i did not
want to do it unconditionally, just in case.
2023-02-05 14:06:33 +01:00
jordi fita mas 2799fdb8db Add companyURI for Go code too, not just templates 2023-02-04 10:43:42 +01:00
jordi fita mas 1ab48cfcbc Replace default router with github.com/julienschmidt/httprouter
I would fuck up handling URL parameters and this router has per-method
handlers, that are easier to work with, in some cases.
2023-02-03 12:30:56 +01:00
jordi fita mas 917db31227 Add cross-request forgery detection
I use the ten first digits of the cookie’s hash, that i believe it is
not a problem, has the advantage of not expiring until the user logs
out, and using a per user session token is explicitly allowed by
OWASP[0].

[0]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern
2023-02-02 11:39:34 +01:00
jordi fita mas 2883438157 Handle tax details and new tax forms with structs and validation
I implemented the Valuer and Scanner interfaces to InputField and
SelectField for better passing values between the database and Go.  I
had a conflict with the Value name and renamed the struct member to Val.

I also had to change the attributes array to be of type
template.HTMLAttr or html/template would replace `form="newtax"`
attribute to `zgotmplz="newtax"` because it deems it “unsafe”.  I do
not like having to use template.HTMLAttr when assigning values, but
i do not know what else i can do now.
2023-02-01 14:15:02 +01:00
jordi fita mas 4f13fa58dc Add autocomplete attributes to profile fields 2023-02-01 11:37:13 +01:00
jordi fita mas b8b3d73e95 Refactor form validation into a new type
I was worried that i was repeating the AddInputErrors function for each
form, because they were basically the same.  I could create a Form type
and make all forms embed it, but i realized that with a separate
validator i would have cleaner validation functions and would not need
the Valid field in the form that i am using only for that method.
2023-02-01 11:30:30 +01:00
jordi fita mas ff5b76b4f5 Use a “proper” struct for the login form
Similar to the profile form, the login form now parses and validates
itself, with the InputField structs that the templates expect.

I realized that i was doing more work than necessary when parsing fields
fro the profile form because i was repeating the operation and the field
name, so now it is a function of InputField.

This time i needed extra attributes for the login form.  I am not sure
that the Go source code needs to know about HTML attributes, but it was
the easiest way to pass them to the template.
2023-02-01 11:02:32 +01:00
jordi fita mas e56e08a68f Tell IDE to shut up about an update without where of a single record 2023-01-31 15:41:05 +01:00
jordi fita mas 9f17f55547 Validate profile form and use templates for fields
Let’s start first with a non-fancy validation method with just if
conditionals instead of bringing yet another complicated library.  I
hope i do not regret it.

I wanted to move all the input field to a template because all that
gobbledygook with the .input div and repeating the label in the
placeholder was starting to annoy me.  Now with error messages was even
more concerning.

I did not know whether the label should be a part of the input fields
or something that the template should do.  At the end i decided that
it makes more sense to be part of the input field because in the error
messages i use that same label, thus the template does not have a say
in that, and, besides, it was just easier to write the template.

The same with the error messages: i’ve seen frameworks that have a map
with the field’s id/name to the error slice, but then it would be
a bit harder to write the template.

I added AddError functions instead of just using append inside the
validator function, and have a local variable for whether it all went
OK, because i was worried that i would leave out the `ok = false`
in some conditions.

I had started writing “constructors” functions for InputField and
SelectField, but then had to add other methods to change the required
field and who knows what else, and in the end it was easier to just
construct the field inline.
2023-01-31 15:40:12 +01:00
jordi fita mas 9aee33511a Move page titles to their respective templates
I have been thinking about that, and it does not make that much sense to
have the titles in the Go source anymore: most of them are static text
that i have to remember to set in the controller each time, and when
the time come i have to face a dynamic title i am sure i will manage
with only the template capabilities—worst comes worst, i can always
define a function.

On the other hand, there is no way i can define a template without its
title and i know that everytime that template is used, no matter what
controller rendered it, it will always have that title.
2023-01-31 13:07:17 +01:00
jordi fita mas 1a7b9f6bdd Rename extension of templates to .gohtml
Apparently, there are tools that only know how to use that extensions
when referring to Go templates.
2023-01-30 16:48:21 +01:00
jordi fita mas c037f671f8 Refactor authenticated redirection to a common handler 2023-01-24 21:44:23 +01:00
jordi fita mas d9c93b8797 Add function to change the current user’s password
This function does not ask for the confirmation because this is an
user-facing issue, not for the database.

Still missing: validation and proper error messages.
2023-01-23 21:41:14 +01:00
jordi fita mas 5eeaab2013 Use user’ß email for auth funcs and return cookie on email change
This is for security, just in case two users have the same cookie,
althought it is unlikely, but nevertheless less guessable.

I also need to refresh the cookie when the user changes their email
address, because it is liked toghether.  It does mean that it will
logout from everywhere else, but i can not do anything about that.
2023-01-23 21:18:55 +01:00
jordi fita mas c84f3f9e80 Allow guest access to user_profile with an empty profile
I want this so that the Go application does not need to know the exact
details of the settings that the database sets when applying the cookie;
it just needs to select from the user_profile that already knows this.

Also, that way i can get the user’s language from its profile with a
single select, without having to check whether we are guest or
authenticated.

With that, i can skip the content negotiation if the user already told
us what language they want.
2023-01-23 01:18:47 +01:00
jordi fita mas 5505fa41c3 Use “layouts” for the common HTML between pages
Had to call xgettext on Go source files because now the title comes from
there, as i assume i will have titles like "Invoice #INVxxxx" that have
to come from the database that the template does not know.
2023-01-22 21:41:50 +01:00
jordi fita mas fa6ddc70b3 Prefix with “Must” all functions that panic
Just following what the standard library does.
2023-01-22 20:37:43 +01:00
jordi fita mas ea9e830a75 Add user_profile view to update the profile with form
Since users do not have access to the auth scheme, i had to add a view
that selects only the data that they can see of themselves (i.e., no
password or cookie).

I wanted to use the `request.user.id` setting that i set in
check_cookie, but this would be bad because anyone can change that
parameter and, since the view is created by the owner, could see and
*change* the values of everyone just by knowing their id.  Thus, now i
use the cookie instead, because it is way harder to figure out, and if
you already have it you can just set to your browser and the user is
fucked anyway; the database can not help here.

I **am** going to use the user id in row level security policies, but
not the value coming for the setting but instaed the one in the
`user_profile`, since it already is “derived” from the cookie, that’s
why i added that column to the view.

The profile includes the language, that i do not use it yet to switch
the locale, so i had to add a relation of the available languages, for
constraint purposes.  There is no NULL language, and instead i added the
“Undefined” language, with ‘und’ tag’, to represent “do not know/use
content negotiation”.

The languages in that relation are the same i used to have inside
locale.go, because there is no point on having options for languages i
do not have the translation for, so i now configure the list of
available languages user in content negotiation from that relation.

Finally, i have added all font from RemixIcon because that’s what we
used in the design and i am going to use quite a lot of them.

There is duplication in the views; i will address that in a different
commit.
2023-01-22 02:23:09 +01:00