Invite the selected members to the team.
To have a successful invitation:
- none user has this email
- an invitation is not pending for this email and
this team
Part of the team logic was in the create team page,
we moved it to the CardCreateTeam component in
the teams feature.
It will be easier to maintain and reuse the logic.
With the recent addition of mails' templates, Django traduction files
needed to be updated.
It seems that recents backend changes were not reflected into the
Django traduction file. Fixed them, and add traductions related to
the invitation email.
Last revision was made on 2024-01-01
build-mails job builds mails Django templates but was not persisting its
output. This steps was present in Joanie CI. It might have been removed,
when converting Circle CI worflows to Github Actions.
Artifacts are passed between build-mails and test-back jobs. test-back
job has now a dependency to build-mails.
When generating an Invitation object within the database, our intention
is to promptly notify the user via email. We send them an invitation
to join Desk.
This code is inspired by Joanie successful order flow.
Johann's design was missing a link to Desk, I simply added a button which
redirect to the staging url. This url is hardcoded, we should refactor it
when we will deploy Desk in pre-prod or prod environments.
Johann's design relied on Marianne font. I implemented a simpler version,
which uses a google font. That's not important for MVP.
Look and feel of this first invitation template is enough to make our PoC
functionnal, which is the more important.
THis feature is inspired by Joanie. Add two new urls to render Emails
HTML and Text templates.
Developpers can render the email template they are working on. When necessary,
run make mails-build, and reload `_debug__/mail/hello_html`, it will re-render
the updated email template.
Also, I have copy/pasted one template extra tags from Joanie, which loads
bas64 string from static images. This code is necessary to render the dummy
template `hello.html`.
Improved code readability, by extracting this well-scoped unit of
logic in a dedicated method. Also, rename active_invitations to match
'valid' vocabulary used elsewhere in the doc. If no valid invitation
exists, early return to avoid nesting.
Integrate multiselect search users in the
modal add members.
We are using react-select to implement the
multiselect search users. We are using this
library in waiting for Cunningham to implement
the multiselect asynch component.
The CI was controlling if the traduction was made
in every PR. It makes the workflow quite grueling
when we have to change the literal, plus the synch
is complicating when we have multiple PR opened.
We remove the CI control on the traduction, we
will do dedicated PR to update the traduction.
We will add the CI control on the traduction in
the future, before a release by example.
When generating a batch of users using Faker, there's a possibility of
generating multiple users with the same email address. This breaches
the uniqueness constraint set on the email field, leading to flaky
tests that may fail when random behavior coincides unfavorably.
Implemented a method inspired by Identity's model to ensure unique
email addresses when creating user batches with Faker.
Updated relevant tests for improved stability.
Important ordering fields for TeamAccess depend on user's
identities data. User and identities has a one-to-many relationship,
which forced us to prefetch the user-related data when listing
team's accesses.
Prefetch get data from the database using two SQL queries, and
join data in Python. User's data were not available in the first
SQL query.
Without annotating the query set with user main identities data,
we could not use default OrderingFilter backend code, which order_by()
the queryset.
Enhance list capabilities, by adding the OrderingFilter as filter backend,
to the TeamAccess viewset.
API response can be ordered by TeamAccess role. More supported ordering
fields will be supported later on.
We created a custom Pagination class, were max_page_size is overriden.
I decided to add bare minimum tests to make sure we can set the maximum
page size using the 'page_size' query parameter.
Our Pagination class inherits from the PageNumberPagination Django class.
However, this base class as not ordering attribute. Thus, setting a
default value wont have any effect on the code.
Why did we end up passing a value to this non-existing attribute? Becasue
we copy/pasted some code sources from Joanie, and Joanie also has this
attribute set to a default value.
If you take a look at DRF pagination style documentation, the only three
attributes they set on the child class are 'page_size', 'max_page_size'
'page_size_query_param'. 'ordering' is not mentionned in the attributes
you may override. However, the CursorPagination class offers the latter
attribute, which may explain why we did end up setting this non-existing
attribute in Joanie.
djangorestframework released version 3.15.0, which includes modifications of
details upon returning 404 errors (see related issue
https://github.com/encode/django-rest-framework/pull/8051).
This commit changes the expected details of 404 responses in our tests,
to match DRF 3.15.0.
Based on @rouja reco, I added a dedicated ingress to serve Django Admin
pages and Django statics. The admin route will be secured by the oauth proxy.
I simply copy/pasted the first ingress template, and adapted it.
This commit is working in progress. I have added an extra chart to take
benefits of the Redis operator developed by Indie hoster.
When using the dev environment, I used bitnami redis chart to deploy
a Redis service with authentication disable.
CSRF trusted origins are set using an environment variable. The env
value was wrongly name to CORS_ALLOWED_ORIGINS, which doesn't exist
in our Django configurations. I fixed this minor issue.
Set OIDC secrets for the dev environment. Please note that we use different
secrets between dev and staging. Why? Benoit created two client id, thus we
could easily tests Agent Connect feature from the local host and the staging
one.
The local host is desk.127.0.0.1.nip.io. If this value change at any time,
please consider asking Benoit to update the host value linked to the dev
client id.
Thx @rouja for your help on deploying Desk. This commit slightly modifies
helm charts and helmfile to prepare the initial project deployment in a
staging environment.
@rouja updates:
- added secrets files for dev and staging environments (dev's one is empty)
- disable ingress by default, to avoid any security issue
- added an extra chart to benefit from Indie hoster Postgres operator
Thx to this commit we deployed a first draft version figured out
that the Django session were broken. We are using a cache session engine,
and wrongly configure cache backend to local memory. Thus, Django server
is not able to resolve the session, and enters in an infinite loop to
log-in the user.
Please note that this Helmfile is uncomplete, it lacks services as
redis, celery, mail ... which are declared in the Docker Compose file
but not yet used in development and production images.
Thus, to run the Desk Helm chart, we only add a postgres database to run the
Django backend server, and apply migrations.
For now, this Helmfile is quite hard to test in dev environment, because the
frontend redirects automatically to the SSO login page. We cannot really
assess if backend and frontend are working properly. We might adjust some
configurations after the first deployment in stagging.
(We are a bit in rush, to respect the current sprint deadline.)
Development values points https://desk.127.0.0.1.nip.io URL. Please note that
the frontend image for now has been built with this URL for the backend address.
Meaning that we either need to rebuild and publish a frontend image with the
staging URL when deploying the project, or enhance our frontend image, to pass
the backend URL at runtime.
First, thanks a LOT @rouja for your help along the way.
This commit propose a first draft of Helm chart to prepare deployment.
It follows Plane's Helm Chart, hosted on the shared team repo,
please https://github.com/numerique-gouv/helm-charts, PR #11
It offers advanced templating function under _helpers.tpl, an auto-generated
README file when running ./generate-readme.sh, and a clear files structure.
The chart itself is quite simple. We have two deployments, one for the
frontend and one for the backend. Both need a dedicated service, which are
exposed using a common ingress. Frontend is accessible from the / path and
backend's from /api path.
Please note, we added a backend job to migrate the database when deploying
backend's pods. This job should be auto-cleaning itself 100s after it completes
to avoid any error when syncing helm.
values.yaml file is quite pristine, all common env variables will be set
in helmfile configuration.
Deploying frontend static files through kubernetes is temporary, we plan to
either remplace it by an external CDN or use minio to host static output in
a S3 bucket within the cluster.
When we pull the translations from crowdin we
get lot of git diff noise with the json file.
We order the keys in the json file to make the
diffs more readable.
`backend-development` and `backend-production` CMD syntaxes were
using a Shell Form. Shell form prevented Unix signals from reaching
our container correctly, such as SIGTERM. Also, the shell process
ends up being the PID 1, instead of our Python scripts.
Docker recommends to use the exec form whenever possible.
In development, sessions are saved in local memory. It's working well,
however it doesn't adapt to a kubernetized setup. Several pods need
to access the current sessions, which need to be stored in a single
source of truth.
With a local memory cache, pods cannot read session saved in other pods.
We end up returning 401 errors, because we cannot authenticate the user.
I preferred setting up a proper cache than storing sessions in database,
because in the long run it would be a performance bottleneck. Cache will
decrease data access latency when reading current sessions.
I added a Redis cache backend to the production settings. Sessions would
be persisted to Redis. In K8s, a Redis operator will make sure the cached
data are not lost.
Two new dependencies were added, redis and django-redis.
I followed the installation guide of django-redis dependency. These
setting were tested deploying the app to a local K8s cluster.