Commit Graph
456 Commits
Author SHA1 Message Date
Manuel Raynaud 7372c4610f ️(backend) optimize media_auth sql queries
On the media_auth endpoint the first bottleneck we have is with
postgresql. We are looking for too much data and no index is used on the
attachments colum. When the lookup filter on the attachement columns, a
full scan is made on all the document table looking for each element in
the array, this operation is really expensive. To fix this we created a
GIN index on the attachments column. Also the readable_per_se lookup was
selecting too much data combined with the filter_descendants function.
We remove the usage of the filter_descendants, we choose to first fetch
all the paths where the attachment is found, this operation is fast
thanks to the new index, split all the paths in candidate paths and then
filter readable_per_se queryset with these paths. All these
modifications make the endpoint faster.
2026-08-20 16:28:31 +02:00
Manuel Raynaud f714c7fae3 (backend) profile api using django-silk
We have performance issue with the media_auth endpoint. We need to
monitor and profile this endpoint to understand what is happening. We
decided to install and configure django-silk. By default django-silk is
not enabled and not accessible, once enabled migration must be run and
the /silk/ endpoint will be accessible only using a super user.
To have relecant profiles and monitor we must have a database comparable
to a production one because we are facing a scaling issue. Unless a
million documents probably nothing is happening, for this we added
several management commands to help us. A first one to anonymize a
database than can be reused without any risk to leak PII data, can be
called using python manage.py anonymize_database with some mandatory
options. An other command to generate a database profile, this command
should be run on a production database, this profile can then be used by
the generate_volumetry to populate a development database with same
volumetry than describe in the profile.
2026-08-20 16:21:36 +02:00
risk-altandAnthony LC fb984abab3 🐛(backend) handle object storage metadata keys case-insensitively
Object storage metadata keys are case insensitive per the S3
specification, but implementations don't agree on the case they give
back. When head_object returns a capitalized "Status", updating the
attachment status added a second, lowercase entry instead of replacing
it, and the copy request ended up carrying two x-amz-meta-status
headers. Ceph RadosGW loses one of them behind a proxy, which
invalidates the request signature.

The same assumption was made when reading the status back in media-auth
and media-check, where an attachment stored on such a backend stayed in
"processing" forever.

Metadata read from the storage is now normalized to lowercase keys
before being consumed or copied over.

Signed-off-by: risk-alt <aldu6974@gmail.com>
2026-08-14 11:30:52 +02:00
Manuel Raynaud f7d06e45e5 🚨(backend) lint code with new ruff 0.16
New ruff version need to lint the code again and adapt exceptions
2026-08-04 10:16:51 +02:00
Manuel Raynaud a57fb7cbde ♻️(backend) remove deprecation warning from pydantic-ai library
Since pydantic-ai has ben upgraded deprecation warning were present in
the logs. This commint change how the instrumentation is enabled to be
compatible with hoe pydantic-ai manage it. Also prompt system are
ignored when they come from the front, like we are doing and dropped. To
maintain the system prompt we use the instruction parameter instead.
2026-08-04 10:16:51 +02:00
Manuel Raynaud 050591e2ee ⬆️(backend) upgrade pydantic-ai-slim and remove mistralai
We upgraded pydantic-ai-slim to the latest version and add mistral has
extra dependency. Doing this, the direct dependance to mistral can be
removed and will be managed with pidantic-ai-slim package. The import of
mistralai has changed, we have to updagre them from mistralai to
mistralai.client
2026-08-04 10:16:50 +02:00
Florent Chehab edf26d6321 (backend) conditional email notification in server to server api
Add send_notification_email flag (defaults to True) on
the ServerCreateDocumentSerializer so that we can bypass
sending the email notification when creating a document
with the server to server API.

Signed-off-by: Florent Chehab <flo@nextmile.fr>
2026-08-03 10:54:31 +02:00
Manuel Raynaud d35b81a6ed ♻️(backend) reset collaboration connection in cascade for all children
When an access is updated or deleted, or a link_configuration is
changed, the collaration_service is used to reset the connection in the
collaboration server. As accesses and link_configuration are inherited
in a Docs tree, if the user is connected to a child, the connection is
not reset. This commit fix this issue by calling the reset on every
children in the tree.
2026-07-09 14:46:11 +02:00
Manuel Raynaud 9ef4a15f5e ♻️(backend) scope document search by document id instead of path
The search in a document tree was triggered by the usage of the document
path. The path is something guessable by incrementing it you can
discover public documents. We decided to change this to use the document
id which is not guessable and prevent discovering public documents.
Thanks to @maboukerfa for discovering it.
2026-07-07 11:21:47 +02:00
Manuel Raynaud b01e6d58fd ♻️(core) fix typo in settings COLLABORATION_WS_NOT_CONNECTED_READY_ONLY
The settings COLLABORATION_WS_NOT_CONNECTED_READY_ONLY contains a typo.
We don't want to see READY_ONLY but READ_ONLY. This commit fix the typo
and change everywhere in the codebase the settings name.
2026-07-06 08:55:21 +02:00
Manuel RaynaudandGitHub debb253fa5 (backend) add management command to reset a Document
We need a management command to reset a Document to an initial state and
deletes everything related to it. This command can be usefull to reset a
demo for example.
2026-07-03 15:10:04 +00:00
Manuel RaynaudandGitHub 336d530014 🛂(backend) remove unused default authentication backend
The authentication backend
mozilla_django_oidc.contrib.drf.OIDCAuthentication
is present in the default authentication classes for the REST_FRAMEWORK
settings. This backend should not be used by our application and can
lead to the usage of our main api with an access_token instead of the
cookie session.
We need to override the drf SessionAuthentication backend to implement
the authenticate_header method. Without this, a 403 status code is
returned, but it is not valid. It must a be 401
2026-07-03 13:18:51 +00:00
Dakshesh JainandGitHub 6ec541f5cb 🐛(backend) update restore ability for inherited deletion
Updated the restore ability so that only directly deleted documents can
be restored. This prevents the restore action from being exposed for
child documents whose parent is deleted. This PR addresses #2127.
2026-06-30 10:01:07 +00:00
Amine BOUKERFAandGitHub 36dced1e56 🐛(backend) prevent owner from leaving a soft-deleted document
Owners could leave trashed documents via the leave endpoint, deleting
their `DocumentAccess` and all subtree access. When the last owner
leaves a document it creates an orphan as no owners remains in the doc.

Signed-off-by: BOUKERFA Mohamed El Amine <boukerfa.ma@gmail.com>
2026-06-29 13:04:04 +00:00
Cyril b9e4df7bd6 🔥(frontend) remove Crisp from the project
Remove Crisp chat SDK, provider, analytics, session management
and all related references across the codebase.
2026-06-23 13:37:50 +02:00
Manuel Raynaud 82013a84b6 ♻️(backend) change how a user is deleted in the admin
In the admin there were 2 ways to delete a user : by the actions select
box and the button on its change view. Both are leading to a failure. To
fix it, both way are removed and we implemented a custom action calling
the user.delete method with all the specific workflow we implemented.
2026-06-19 11:53:32 +02:00
Manuel Raynaud ed0dce66c5 (backend) specific user delete method to delete its relations
Deleting a user is not possible when it has created docs because the
on_delete on the Document class id RESTRICT and we don't want to change
it. We decided to have a specific workflow for correctly delete a user.
The document where the user is the sole owner must be deleted, the other
only the owner access must be deleted. For the remaining Documents where
the user is the creator, we set it to `null`, then the user can be
delete, remaining relations are deleted in cascade.
2026-06-19 11:53:32 +02:00
Manuel Raynaud b417a57418 ♻️(backend) use user_id instead of user relation in sharing module
In the sharing module, the user model was used instead of working with
the user id. Only the user id is used in this module, forcing in the
module calling this functions to load the user model for nothing and
doing a N+1 query.
2026-06-19 11:53:30 +02:00
Mohamed El Amine BOUKERFAandManuel Raynaud 51364e3d3c (frontend) add UI support for reaction limit on comments
Prevent users from adding more reactions once the per-message
limit has been exceeded. It Disables reaction buttons
when limit is reached

Signed-off-by: Mohamed El Amine BOUKERFA <boukerfa.ma@gmail.com>
2026-06-15 08:56:45 +02:00
Mohamed El Amine BOUKERFAandManuel Raynaud 867583a52a (backend) add limit on distinct reactions per comment
Implement a configurable limit (default: 15) on the number of distinct
emoji reactions per comment.

  - Backend validation ensures the limit cannot be exceeded via API

Signed-off-by: Mohamed El Amine BOUKERFA <boukerfa.ma@gmail.com>
2026-06-15 08:56:45 +02:00
Amine BOUKERFAandGitHub 5aa1402aa3 ️(backend) prefetch thread comments tree to fix N+1 queries
Retrieving a thread serialized its nested comments, reactions and
reaction users without prefetching, issuing one query per comment for
its author and reactions and one query per reaction for its users.
    
Signed-off-by: Mohamed El Amine BOUKERFA <boukerfa.ma@gmail.com>
2026-06-11 13:25:12 +00:00
Manuel RaynaudandAnthony LC da6e65b204 ♻️(backend) return only the top parent in the search endpoint
In the search endpoint, we were returning all the parents for a document
mathing the search. We want instead to return only the top parent the
user has access to.
2026-06-10 16:44:48 +02:00
Manuel RaynaudandGitHub 021f53092e 🐛(backend) stream empty string with an async iterator under ASGI
In the content_retrieve action, if the document is not existing on the
object storage, we return an empty binary string. In the case the app is
ran as an ASGI application we still have a warning explaining it must
consume the iterator before sending it.
2026-06-10 06:36:03 +00:00
Manuel RaynaudandGitHub 26670eb588 🐛(backend) stream document content with an async iterator under ASGI
When docs is ran using an ASGI server, the django StreamingHttpResponse
expect to consume an async generator. If a sync generator is used, it
fully consumes it and then return all the content and we loose the
benefits of using a StreamingHttpResponse.
2026-06-04 15:43:41 +00:00
Manuel RaynaudandGitHub 3b9a0f0f2d 🐛(backend) order trashbin reponse by most recently deleted
The trashbin response wasn't ordered at all. We want to order by default
by -deleted_at.
2026-06-04 12:29:52 +00:00
Manuel RaynaudandGitHub ccb44aec6c 🐛(backend) close thread DB connections to fix test teardown OperationalError
When all the tests are ran, there is a PytestWarning log present to warn
us that there is remaining database connection open and can not be
closed. It appears that the tests about concurrence are responsible of
leaving connection open. We need to manually close them in these tests.
2026-06-03 14:43:46 +00:00
Manuel Raynaud dc692a1594 🔥(backend) remove unused order parameter in Paginator class
In the custom Paginator present in the viewset, an ordering parameter
was set. This parameter is never used by the DRF paginator and can be
removed.
2026-06-02 19:47:38 +02:00
Manuel Raynaud 9bdf36a323 🐛(backend) fix UnorderedObjectListWarning for DocumentAskForAccess
In the tests there is a UnorderedObjectListWarning, we also find this same
warning in the logs in production. This warning appears because the
queryset used by the DocumentAskForAccess paginator is not ordered and
can lead to inconsistent result. Ordering the queryset fix this warning.
2026-06-02 19:47:31 +02:00
Manuel Raynaud 5b70c5aecb 🔧(backend) new setting DOCUMENT_ALL_ENDPOINT_ENABLED
We want to allow or not the usage of the /documents/all/ endpoint. It has
been created to be used for an other purpose than the js client. For
those who don't use it this new settings allow to disable it. By default
it is set to True to keep the same behavior.
2026-06-02 17:28:04 +02:00
Manuel Raynaud 1ebc8d52a0 📈(backend) capture an event when a document is left
When a user leave a document, we want to capture an event.
2026-06-01 17:47:28 +02:00
Manuel Raynaud c91c443b08 📈(backend) capture an event when a document is moved
When a document is moved we want to capture an event. The position and
target_document_id is added to the sent properties.
2026-06-01 17:47:28 +02:00
Manuel Raynaud 0df2d753c4 📈(backend) capture an event when a comment is created
When a new comment is created, we capture an event related to this comment
creation.
2026-06-01 17:47:28 +02:00
Manuel Raynaud ba1a1d469e 📈(backend) capture an event when a thread is created
When a new thread is created, we capture an event related to this thread
creation.
2026-06-01 17:47:27 +02:00
Manuel Raynaud ab1708f6df 📈(backend) capture an event when an access document is deleted
When an access is deleted we want to capture an event.
2026-06-01 17:43:56 +02:00
Manuel Raynaud 0aac4b662b 📈(backend) capture an event when an access document is created
When an access is created we want to capture an event.
2026-06-01 17:41:57 +02:00
Manuel Raynaud 7f4226452f 📈(backend) capture an event when an AI action is used
When an AI action is called from ai_translate, ai_transform and
ai_proxy, an event doc_ai_action is captured with a method property
giving the information from where it is called.
2026-06-01 17:41:57 +02:00
Manuel Raynaud a55b1c61eb 📈(backend) capture an event when a document is mark as a favorite
We want to capture an event when a user flag a document as a favorite.
2026-06-01 17:41:57 +02:00
Manuel Raynaud a05de21d14 📈(backend) capture an event when a document is imported
We want to capture an event when a file is imported. We add in the
properties the type of file imported and if it is in the
create-for-owner api call.
2026-06-01 17:41:56 +02:00
Manuel Raynaud d1476024a7 📈(backend) capture an event when a document is duplicated
We want to capture an event when a document is duplicated. The document
from where come from the duplication is added in the properties.
2026-06-01 17:41:56 +02:00
Manuel Raynaud f4139e3ab0 📈(backend) capture an event when a user logs in
We want to capture an event every time a user logs in.
2026-06-01 17:41:55 +02:00
Manuel Raynaud d495b158c1 📈(backend) capture an event when a document is created and deleted
When a document is created and deleted, we capture an event and we send
it to posthog.
2026-06-01 17:41:55 +02:00
Manuel Raynaud 5eb9c4edd6 📈(backend) create a utils to capture event with posthog
We want to capture event with posthog. We created a utils for this
reposible to send the event or not if posthog is configured.
2026-06-01 17:41:55 +02:00
Manuel Raynaud 76544ab64a ♻️(backend) split posthog configuration
The posthog information were only available using the POSTHOG_KEY
settings. We split it in POSTHOG_KEY and POSTHOG_HOST to use them with
the pyhton posthog sdk
2026-06-01 17:02:43 +02:00
Manuel Raynaud 9f98af1387 (backend) allow to leave a document
We want to allow users to leave a document where they have an access or
they have visited creating a link_trace. All subdocuments should also be
leaved at the same time.
To know if the user can leave a doc we have to check when computing the
abilities if a record is existing in the LinkTrace table. This is a N+1
query situation. To avoid it, we added an annotation in the
DocumentQueryset like we already do to annotate the user role.
There is one edge case where the annotation is made to soon, it is when the
user is visiting a document for the first time, the `get_object` add the
annotation and in the permission, we compute the abilities. The `leave`
property is False because the entry in the LinkTrace table is not made,
when the serializer ask for the abilities again, it is still False. So
in the `retrieve` method in the viewset we force the
`user_has_link_trace` to the correct value.
2026-06-01 16:25:50 +02:00
Manuel Raynaud 7773a5b9bf 🔥(backend) remove masking document code
The mask feature has never been implemented by the frontend application
and it is not what we want to do. We want to implement a feature to
leave a document.
2026-06-01 16:25:50 +02:00
Manuel RaynaudandGitHub a20ba1a78e 🐛(backend) use computed_link_reach in handle_onboarding_document
In the model method User::_handle_onboarding_documents_access we do not
allow using documents with restricted link_reach to be added as
onboarding documents. To check the real link_reach of the document, we
must use instead the computed_link_reach to be sure that a sub document
can also be used and compute its correct link_reach.
2026-05-28 06:50:40 +00:00
Manuel Raynaud fdc99adc78 (backend) add a breadcrumb in the search response
In the search response, we want to display a breadcrumb for every
document returned. For this we added a "parents" property containing a list
documents, all are the parents of the current document (ordered by their
depth). With this we can easily create a breadcrumb.
2026-05-27 17:41:39 +02:00
Manuel Raynaud 31b088c307 ♻️(backend) rename SearchDocumentSerializer in SearchQueryParam
The SearchDocumentSerializer name will be used for a dedicated
serializer for the search endpoint.
2026-05-27 17:41:39 +02:00
Manuel Raynaud d00b3222cf ♻️(backend) allow global search in sub documents
The global search endpoint filtering by title in the database was not
searching for accessible sub documents. We change the how global search
is made: it is now returning accessible sub documents matching the
title query.
2026-05-27 17:41:38 +02:00
Manuel Raynaud b77f7ab6f4 ♻️(backend) rename DocumentViewset::_title_search in _search_title
We rename the private method _title_search in _search_title in the
DocumentViewset for having the search methods prefixed with _search
2026-05-27 17:41:38 +02:00