🔨(backend) email invitation in invited user's language

- 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
This commit is contained in:
rvveber
2025-03-04 13:46:40 +01:00
committed by Samuel Paccoud
parent ebf6d46e37
commit 1531846115
3 changed files with 87 additions and 52 deletions

View File

@@ -1167,13 +1167,14 @@ class DocumentAccessViewSet(
def perform_create(self, serializer): def perform_create(self, serializer):
"""Add a new access to the document and send an email to the new added user.""" """Add a new access to the document and send an email to the new added user."""
access = serializer.save() access = serializer.save()
language = self.request.headers.get("Content-Language", "en-us")
access.document.send_invitation_email( access.document.send_invitation_email(
access.user.email, access.user.email,
access.role, access.role,
self.request.user, self.request.user,
language, access.user.language
or self.request.user.language
or settings.LANGUAGE_CODE,
) )
def perform_update(self, serializer): def perform_update(self, serializer):
@@ -1399,10 +1400,11 @@ class InvitationViewset(
"""Save invitation to a document then send an email to the invited user.""" """Save invitation to a document then send an email to the invited user."""
invitation = serializer.save() invitation = serializer.save()
language = self.request.headers.get("Content-Language", "en-us")
invitation.document.send_invitation_email( 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,
) )

View File

@@ -16,6 +16,9 @@ from core.tests.conftest import TEAM, USER, VIA
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
# Create
def test_api_document_accesses_create_anonymous(): def test_api_document_accesses_create_anonymous():
"""Anonymous users should not be allowed to create document accesses.""" """Anonymous users should not be allowed to create document accesses."""
document = factories.DocumentFactory() document = factories.DocumentFactory()
@@ -123,7 +126,7 @@ def test_api_document_accesses_create_authenticated_administrator(via, mock_user
document=document, team="lasuite", role="administrator" 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 # It should not be allowed to create an owner access
response = client.post( 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" 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]) 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}" f"on the following document: {document.title}"
) in email_content ) in email_content
assert "docs/" + str(document.id) + "/" 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()

View File

@@ -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 and administrators should be able to invite new users.
Only owners can invite owners. Only owners can invite owners.
""" """
user = factories.UserFactory() user = factories.UserFactory(language="en-us")
document = factories.DocumentFactory() document = factories.DocumentFactory()
if via == USER: if via == USER:
factories.UserDocumentAccessFactory(document=document, user=user, role=inviting) 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() document = factories.DocumentFactory()
factories.UserDocumentAccessFactory(document=document, user=user, role="owner") 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/", f"/api/v1.0/documents/{document.id!s}/invitations/",
invitation_values, invitation_values,
format="json", format="json",
headers={"Content-Language": "fr-fr"},
) )
assert response.status_code == 201 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(): 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. 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() document = factories.DocumentFactory()
factories.UserDocumentAccessFactory(document=document, user=user, role="owner") factories.UserDocumentAccessFactory(document=document, user=user, role="owner")