From 1531846115be54ce9c3ab01880777080661726cd Mon Sep 17 00:00:00 2001 From: rvveber Date: Tue, 4 Mar 2025 13:46:40 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8(backend)=20email=20invitation=20in?= =?UTF-8?q?=20invited=20user's=20language?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - language for invitation emails => language saved on the invited user - if invited user does not exist yet => language of the sending user - if for some reason no sending user => system default language --- src/backend/core/api/viewsets.py | 12 +-- .../test_api_document_accesses_create.py | 77 ++++++++++++++++++- .../test_api_document_invitations.py | 50 ++---------- 3 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 596d26dc..de9b8401 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -1167,13 +1167,14 @@ class DocumentAccessViewSet( def perform_create(self, serializer): """Add a new access to the document and send an email to the new added user.""" access = serializer.save() - language = self.request.headers.get("Content-Language", "en-us") access.document.send_invitation_email( access.user.email, access.role, self.request.user, - language, + access.user.language + or self.request.user.language + or settings.LANGUAGE_CODE, ) def perform_update(self, serializer): @@ -1399,10 +1400,11 @@ class InvitationViewset( """Save invitation to a document then send an email to the invited user.""" invitation = serializer.save() - language = self.request.headers.get("Content-Language", "en-us") - invitation.document.send_invitation_email( - invitation.email, invitation.role, self.request.user, language + invitation.email, + invitation.role, + self.request.user, + self.request.user.language or settings.LANGUAGE_CODE, ) diff --git a/src/backend/core/tests/documents/test_api_document_accesses_create.py b/src/backend/core/tests/documents/test_api_document_accesses_create.py index 3d95bd62..db67ece1 100644 --- a/src/backend/core/tests/documents/test_api_document_accesses_create.py +++ b/src/backend/core/tests/documents/test_api_document_accesses_create.py @@ -16,6 +16,9 @@ from core.tests.conftest import TEAM, USER, VIA pytestmark = pytest.mark.django_db +# Create + + def test_api_document_accesses_create_anonymous(): """Anonymous users should not be allowed to create document accesses.""" document = factories.DocumentFactory() @@ -123,7 +126,7 @@ def test_api_document_accesses_create_authenticated_administrator(via, mock_user document=document, team="lasuite", role="administrator" ) - other_user = factories.UserFactory() + other_user = factories.UserFactory(language="en-us") # It should not be allowed to create an owner access response = client.post( @@ -199,7 +202,7 @@ def test_api_document_accesses_create_authenticated_owner(via, mock_user_teams): document=document, team="lasuite", role="owner" ) - other_user = factories.UserFactory() + other_user = factories.UserFactory(language="en-us") role = random.choice([role[0] for role in models.RoleChoices.choices]) @@ -235,3 +238,73 @@ def test_api_document_accesses_create_authenticated_owner(via, mock_user_teams): f"on the following document: {document.title}" ) in email_content assert "docs/" + str(document.id) + "/" in email_content + + +@pytest.mark.parametrize("via", VIA) +def test_api_document_accesses_create_email_in_receivers_language(via, mock_user_teams): + """ + The email sent to the accesses to notify them of the adding, should be in their language. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + document = factories.DocumentFactory() + if via == USER: + factories.UserDocumentAccessFactory(document=document, user=user, role="owner") + elif via == TEAM: + mock_user_teams.return_value = ["lasuite", "unknown"] + factories.TeamDocumentAccessFactory( + document=document, team="lasuite", role="owner" + ) + + role = random.choice([role[0] for role in models.RoleChoices.choices]) + + assert len(mail.outbox) == 0 + + other_users = ( + factories.UserFactory(language="en-us"), + factories.UserFactory(language="fr-fr"), + ) + + for index, other_user in enumerate(other_users): + expected_language = other_user.language + response = client.post( + f"/api/v1.0/documents/{document.id!s}/accesses/", + { + "user_id": str(other_user.id), + "role": role, + }, + format="json", + ) + + assert response.status_code == 201 + assert models.DocumentAccess.objects.filter(user=other_user).count() == 1 + new_document_access = models.DocumentAccess.objects.filter( + user=other_user + ).get() + other_user_data = serializers.UserSerializer(instance=other_user).data + assert response.json() == { + "id": str(new_document_access.id), + "user": other_user_data, + "team": "", + "role": role, + "abilities": new_document_access.get_abilities(user), + } + assert len(mail.outbox) == index + 1 + email = mail.outbox[index] + assert email.to == [other_user_data["email"]] + email_content = " ".join(email.body.split()) + email_subject = " ".join(email.subject.split()) + if expected_language == "en-us": + assert ( + f"{user.full_name} shared a document with you: {document.title}".lower() + in email_subject.lower() + ) + elif expected_language == "fr-fr": + assert ( + f"{user.full_name} a partagé un document avec vous: {document.title}".lower() + in email_subject.lower() + ) + assert "docs/" + str(document.id) + "/" in email_content.lower() diff --git a/src/backend/core/tests/documents/test_api_document_invitations.py b/src/backend/core/tests/documents/test_api_document_invitations.py index c901f276..92e17794 100644 --- a/src/backend/core/tests/documents/test_api_document_invitations.py +++ b/src/backend/core/tests/documents/test_api_document_invitations.py @@ -370,7 +370,7 @@ def test_api_document_invitations_create_privileged_members( Only owners and administrators should be able to invite new users. Only owners can invite owners. """ - user = factories.UserFactory() + user = factories.UserFactory(language="en-us") document = factories.DocumentFactory() if via == USER: factories.UserDocumentAccessFactory(document=document, user=user, role=inviting) @@ -422,11 +422,11 @@ def test_api_document_invitations_create_privileged_members( } -def test_api_document_invitations_create_email_from_content_language(): +def test_api_document_invitations_create_email_from_senders_language(): """ - The email generated is from the language set in the Content-Language header + When inviting on a document a user who does not exist yet in our database, the invitation email should be sent in the language of the sending user. """ - user = factories.UserFactory() + user = factories.UserFactory(language="fr-fr") document = factories.DocumentFactory() factories.UserDocumentAccessFactory(document=document, user=user, role="owner") @@ -444,7 +444,6 @@ def test_api_document_invitations_create_email_from_content_language(): f"/api/v1.0/documents/{document.id!s}/invitations/", invitation_values, format="json", - headers={"Content-Language": "fr-fr"}, ) assert response.status_code == 201 @@ -464,50 +463,11 @@ def test_api_document_invitations_create_email_from_content_language(): ) -def test_api_document_invitations_create_email_from_content_language_not_supported(): - """ - If the language from the Content-Language is not supported - it will display the default language, English. - """ - user = factories.UserFactory() - document = factories.DocumentFactory() - factories.UserDocumentAccessFactory(document=document, user=user, role="owner") - - invitation_values = { - "email": "guest@example.com", - "role": "reader", - } - - assert len(mail.outbox) == 0 - - client = APIClient() - client.force_login(user) - - response = client.post( - f"/api/v1.0/documents/{document.id!s}/invitations/", - invitation_values, - format="json", - headers={"Content-Language": "not-supported"}, - ) - - assert response.status_code == 201 - assert response.json()["email"] == "guest@example.com" - assert models.Invitation.objects.count() == 1 - assert len(mail.outbox) == 1 - - email = mail.outbox[0] - - assert email.to == ["guest@example.com"] - - email_content = " ".join(email.body.split()) - assert f"{user.full_name} shared a document with you!" in email_content - - def test_api_document_invitations_create_email_full_name_empty(): """ If the full name of the user is empty, it will display the email address. """ - user = factories.UserFactory(full_name="") + user = factories.UserFactory(full_name="", language="en-us") document = factories.DocumentFactory() factories.UserDocumentAccessFactory(document=document, user=user, role="owner")