From 515b6867956890893d457933d94601966e87b9a3 Mon Sep 17 00:00:00 2001 From: Samuel Paccoud - DINUM Date: Mon, 13 May 2024 23:31:00 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(models/api)=20allow=20inviting=20exte?= =?UTF-8?q?rnal=20users=20to=20a=20document=20by=20their=20email?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to be able to share a document with a person even if this person does not have an account in impress yet. This code is ported from https://github.com/numerique-gouv/people. --- .github/workflows/impress.yml | 12 + src/backend/core/admin.py | 32 +- src/backend/core/api/serializers.py | 81 ++- src/backend/core/api/viewsets.py | 75 +++ src/backend/core/factories.py | 12 + ...alter_user_language_invitation_and_more.py | 42 ++ src/backend/core/models.py | 157 +++++- .../static/images/logo-suite-numerique.png | Bin 0 -> 13584 bytes src/backend/core/static/images/logo.png | Bin 0 -> 1269 bytes .../static/images/mail-header-background.png | Bin 0 -> 41074 bytes src/backend/core/templatetags/__init__.py | 0 src/backend/core/templatetags/extra_tags.py | 58 ++ .../tests/test_api_document_invitations.py | 494 ++++++++++++++++++ .../core/tests/test_models_invitations.py | 312 +++++++++++ src/backend/core/urls.py | 6 + src/backend/impress/settings.py | 1 + src/backend/pyproject.toml | 1 + src/mail/mjml/hello.mjml | 28 - src/mail/mjml/invitation.mjml | 54 ++ src/mail/mjml/partial/header.mjml | 6 +- 20 files changed, 1334 insertions(+), 37 deletions(-) create mode 100644 src/backend/core/migrations/0002_alter_user_language_invitation_and_more.py create mode 100644 src/backend/core/static/images/logo-suite-numerique.png create mode 100644 src/backend/core/static/images/logo.png create mode 100644 src/backend/core/static/images/mail-header-background.png create mode 100644 src/backend/core/templatetags/__init__.py create mode 100644 src/backend/core/templatetags/extra_tags.py create mode 100644 src/backend/core/tests/test_api_document_invitations.py create mode 100644 src/backend/core/tests/test_models_invitations.py delete mode 100644 src/mail/mjml/hello.mjml create mode 100644 src/mail/mjml/invitation.mjml diff --git a/.github/workflows/impress.yml b/.github/workflows/impress.yml index ec1b1889..164cb456 100644 --- a/.github/workflows/impress.yml +++ b/.github/workflows/impress.yml @@ -71,6 +71,11 @@ jobs: run: yarn install --frozen-lockfile - name: Build mails run: yarn build + - name: Persist mails' templates + uses: actions/upload-artifact@v4 + with: + name: mails-templates + path: src/backend/core/templates/mail lint-back: runs-on: ubuntu-latest @@ -96,6 +101,7 @@ jobs: test-back: runs-on: ubuntu-latest + needs: build-mails defaults: run: @@ -137,6 +143,12 @@ jobs: sudo mkdir -p /data/media && \ sudo mkdir -p /data/static + - name: Download mails' templates + uses: actions/download-artifact@v4 + with: + name: mails-templates + path: src/backend/core/templates/mail + - name: Start Minio run: | docker pull minio/minio diff --git a/src/backend/core/admin.py b/src/backend/core/admin.py index 32f80559..4e95d933 100644 --- a/src/backend/core/admin.py +++ b/src/backend/core/admin.py @@ -78,15 +78,45 @@ class TemplateAdmin(admin.ModelAdmin): inlines = (TemplateAccessInline,) + class DocumentAccessInline(admin.TabularInline): """Inline admin class for template accesses.""" model = models.DocumentAccess extra = 0 + @admin.register(models.Document) class DocumentAdmin(admin.ModelAdmin): """Document admin interface declaration.""" inlines = (DocumentAccessInline,) - \ No newline at end of file + + +@admin.register(models.Invitation) +class InvitationAdmin(admin.ModelAdmin): + """Admin interface to handle invitations.""" + + fields = ( + "email", + "document", + "role", + "created_at", + "issuer", + ) + readonly_fields = ( + "created_at", + "is_expired", + "issuer", + ) + list_display = ( + "email", + "document", + "created_at", + "is_expired", + ) + + def save_model(self, request, obj, form, change): + obj.issuer = request.user + obj.save() + diff --git a/src/backend/core/api/serializers.py b/src/backend/core/api/serializers.py index 4318b14f..0c2dd2c0 100644 --- a/src/backend/core/api/serializers.py +++ b/src/backend/core/api/serializers.py @@ -66,7 +66,6 @@ class BaseAccessSerializer(serializers.ModelSerializer): # Create else: - teams = user.get_teams() try: resource_id = self.context["resource_id"] except KeyError as exc: @@ -74,6 +73,7 @@ class BaseAccessSerializer(serializers.ModelSerializer): "You must set a resource ID in kwargs to create a new access." ) from exc + teams = user.get_teams() if not self.Meta.model.objects.filter( # pylint: disable=no-member Q(user=user) | Q(team__in=teams), role__in=[models.RoleChoices.OWNER, models.RoleChoices.ADMIN], @@ -172,3 +172,82 @@ class DocumentGenerationSerializer(serializers.Serializer): required=False, default="html", ) + + +class InvitationSerializer(serializers.ModelSerializer): + """Serialize invitations.""" + + abilities = serializers.SerializerMethodField(read_only=True) + + class Meta: + model = models.Invitation + fields = [ + "id", + "abilities", + "created_at", + "email", + "document", + "role", + "issuer", + "is_expired", + ] + read_only_fields = [ + "id", + "abilities", + "created_at", + "document", + "issuer", + "is_expired", + ] + + def get_abilities(self, invitation) -> dict: + """Return abilities of the logged-in user on the instance.""" + request = self.context.get("request") + if request: + return invitation.get_abilities(request.user) + return {} + + def validate(self, attrs): + """Validate and restrict invitation to new user based on email.""" + + request = self.context.get("request") + user = getattr(request, "user", None) + role = attrs.get("role") + + try: + document_id = self.context["resource_id"] + except KeyError as exc: + raise exceptions.ValidationError( + "You must set a document ID in kwargs to create a new document invitation." + ) from exc + + if not user and user.is_authenticated: + raise exceptions.PermissionDenied( + "Anonymous users are not allowed to create invitations." + ) + + teams = user.get_teams() + if not models.DocumentAccess.objects.filter( + Q(user=user) | Q(team__in=teams), + document=document_id, + role__in=[models.RoleChoices.OWNER, models.RoleChoices.ADMIN], + ).exists(): + raise exceptions.PermissionDenied( + "You are not allowed to manage invitations for this document." + ) + + if ( + role == models.RoleChoices.OWNER + and not models.DocumentAccess.objects.filter( + Q(user=user) | Q(team__in=teams), + document=document_id, + role=models.RoleChoices.OWNER, + ).exists() + ): + raise exceptions.PermissionDenied( + "Only owners of a document can invite other users as owners." + ) + + attrs["document_id"] = document_id + attrs["issuer"] = user + return attrs diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index e27c972a..7ebf4dd2 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -479,3 +479,78 @@ class TemplateAccessViewSet( queryset = models.TemplateAccess.objects.select_related("user").all() resource_field_name = "template" serializer_class = serializers.TemplateAccessSerializer + + +class InvitationViewset( + mixins.CreateModelMixin, + mixins.ListModelMixin, + mixins.RetrieveModelMixin, + mixins.DestroyModelMixin, + viewsets.GenericViewSet, +): + """API ViewSet for user invitations to document. + + GET /api/v1.0/documents//invitations/:/ + Return list of invitations related to that document or one + document access if an id is provided. + + POST /api/v1.0/documents//invitations/ with expected data: + - email: str + - role: str [owner|admin|member] + Return newly created invitation (issuer and document are automatically set) + + PUT / PATCH : Not permitted. Instead of updating your invitation, + delete and create a new one. + + DELETE /api/v1.0/documents//invitations// + Delete targeted invitation + """ + + lookup_field = "id" + pagination_class = Pagination + permission_classes = [permissions.IsAuthenticated, permissions.AccessPermission] + queryset = ( + models.Invitation.objects.all() + .select_related("document") + .order_by("-created_at") + ) + serializer_class = serializers.InvitationSerializer + + def get_serializer_context(self): + """Extra context provided to the serializer class.""" + context = super().get_serializer_context() + context["resource_id"] = self.kwargs["resource_id"] + return context + + def get_queryset(self): + """Return the queryset according to the action.""" + queryset = super().get_queryset() + queryset = queryset.filter(document=self.kwargs["resource_id"]) + + if self.action == "list": + user = self.request.user + teams = user.get_teams() + + # Determine which role the logged-in user has in the document + user_roles_query = ( + models.DocumentAccess.objects.filter( + Q(user=user) | Q(team__in=teams), + document=self.kwargs["resource_id"], + ) + .values("document") + .annotate(roles_array=ArrayAgg("role")) + .values("roles_array") + ) + + queryset = ( + # The logged-in user should be part of a document to see its accesses + queryset.filter( + Q(document__accesses__user=user) + | Q(document__accesses__team__in=teams), + ) + # Abilities are computed based on logged-in user's role and + # the user role on each document access + .annotate(user_roles=Subquery(user_roles_query)) + .distinct() + ) + return queryset diff --git a/src/backend/core/factories.py b/src/backend/core/factories.py index 3f6c0050..059e5f90 100644 --- a/src/backend/core/factories.py +++ b/src/backend/core/factories.py @@ -112,3 +112,15 @@ class TeamTemplateAccessFactory(factory.django.DjangoModelFactory): template = factory.SubFactory(TemplateFactory) team = factory.Sequence(lambda n: f"team{n}") role = factory.fuzzy.FuzzyChoice([r[0] for r in models.RoleChoices.choices]) + + +class InvitationFactory(factory.django.DjangoModelFactory): + """A factory to create invitations for a user""" + + class Meta: + model = models.Invitation + + email = factory.Faker("email") + document = factory.SubFactory(DocumentFactory) + role = factory.fuzzy.FuzzyChoice([role[0] for role in models.RoleChoices.choices]) + issuer = factory.SubFactory(UserFactory) diff --git a/src/backend/core/migrations/0002_alter_user_language_invitation_and_more.py b/src/backend/core/migrations/0002_alter_user_language_invitation_and_more.py new file mode 100644 index 00000000..dd066fa1 --- /dev/null +++ b/src/backend/core/migrations/0002_alter_user_language_invitation_and_more.py @@ -0,0 +1,42 @@ +# Generated by Django 5.0.3 on 2024-05-12 19:02 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='language', + field=models.CharField(choices="(('en-us', 'English'), ('fr-fr', 'French'))", default='en-us', help_text='The language in which the user wants to see the interface.', max_length=10, verbose_name='language'), + ), + migrations.CreateModel( + name='Invitation', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='primary key for the record as UUID', primary_key=True, serialize=False, verbose_name='id')), + ('created_at', models.DateTimeField(auto_now_add=True, help_text='date and time at which a record was created', verbose_name='created on')), + ('updated_at', models.DateTimeField(auto_now=True, help_text='date and time at which a record was last updated', verbose_name='updated on')), + ('email', models.EmailField(max_length=254, verbose_name='email address')), + ('role', models.CharField(choices=[('member', 'Member'), ('administrator', 'Administrator'), ('owner', 'Owner')], default='member', max_length=20)), + ('document', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='invitations', to='core.document')), + ('issuer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='invitations', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Document invitation', + 'verbose_name_plural': 'Document invitations', + 'db_table': 'impress_invitation', + }, + ), + migrations.AddConstraint( + model_name='invitation', + constraint=models.UniqueConstraint(fields=('email', 'document'), name='email_and_document_unique_together'), + ), + ] diff --git a/src/backend/core/models.py b/src/backend/core/models.py index 0308cd3a..ad36b554 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -3,21 +3,27 @@ Declare and configure the models for the impress core application """ import hashlib import json +import smtplib import textwrap import uuid +from datetime import timedelta +from logging import getLogger from django.conf import settings from django.contrib.auth import models as auth_models from django.contrib.auth.base_user import AbstractBaseUser -from django.core import mail, validators +from django.contrib.sites.models import Site +from django.core import exceptions, mail, validators from django.core.files.base import ContentFile from django.core.files.storage import default_storage from django.db import models from django.template.base import Template as DjangoTemplate from django.template.context import Context +from django.template.loader import render_to_string +from django.utils import html, timezone from django.utils.functional import lazy -from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ +from django.utils.translation import override import frontmatter import markdown @@ -26,6 +32,8 @@ from timezone_field import TimeZoneField from weasyprint import CSS, HTML from weasyprint.text.fonts import FontConfiguration +logger = getLogger(__name__) + def get_resource_roles(resource, user): """Compute the roles a user has on a resource.""" @@ -164,6 +172,42 @@ class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin): def __str__(self): return self.email or self.admin_email or str(self.id) + def save(self, *args, **kwargs): + """ + If it's a new user, give its user access to the documents to which s.he was invited. + """ + is_adding = self._state.adding + super().save(*args, **kwargs) + + if is_adding: + self._convert_valid_invitations() + + def _convert_valid_invitations(self): + """ + Convert valid invitations to document accesses. + Expired invitations are ignored. + """ + valid_invitations = Invitation.objects.filter( + email=self.email, + created_at__gte=( + timezone.now() + - timedelta(seconds=settings.INVITATION_VALIDITY_DURATION) + ), + ).select_related("document") + + if not valid_invitations.exists(): + return + + DocumentAccess.objects.bulk_create( + [ + DocumentAccess( + user=self, document=invitation.document, role=invitation.role + ) + for invitation in valid_invitations + ] + ) + valid_invitations.delete() + def email_user(self, subject, message, from_email=None, **kwargs): """Email this user.""" if not self.email: @@ -523,7 +567,7 @@ class Template(BaseModel): document_html = HTML( string=DjangoTemplate(self.code).render( - Context({"body": format_html(body_html), **metadata}) + Context({"body": html.format_html(body_html), **metadata}) ) ) css = CSS( @@ -576,3 +620,110 @@ class TemplateAccess(BaseAccess): Compute and return abilities for a given user on the template access. """ return self._get_abilities(self.template, user) + + +class Invitation(BaseModel): + """User invitation to a document.""" + + email = models.EmailField(_("email address"), null=False, blank=False) + document = models.ForeignKey( + Document, + on_delete=models.CASCADE, + related_name="invitations", + ) + role = models.CharField( + max_length=20, choices=RoleChoices.choices, default=RoleChoices.MEMBER + ) + issuer = models.ForeignKey( + User, + on_delete=models.CASCADE, + related_name="invitations", + ) + + class Meta: + db_table = "impress_invitation" + verbose_name = _("Document invitation") + verbose_name_plural = _("Document invitations") + constraints = [ + models.UniqueConstraint( + fields=["email", "document"], name="email_and_document_unique_together" + ) + ] + + def __str__(self): + return f"{self.email} invited to {self.document}" + + def save(self, *args, **kwargs): + """Make invitations read-only.""" + if self.created_at: + raise exceptions.PermissionDenied() + + super().save(*args, **kwargs) + self.email_invitation() + + def clean(self): + """Validate fields.""" + super().clean() + + # Check if an identity already exists for the provided email + if User.objects.filter(email=self.email).exists(): + raise exceptions.ValidationError( + {"email": _("This email is already associated to a registered user.")} + ) + + @property + def is_expired(self): + """Calculate if invitation is still valid or has expired.""" + if not self.created_at: + return None + + validity_duration = timedelta(seconds=settings.INVITATION_VALIDITY_DURATION) + return timezone.now() > (self.created_at + validity_duration) + + def get_abilities(self, user): + """Compute and return abilities for a given user.""" + can_delete = False + roles = [] + + if user.is_authenticated: + teams = user.get_teams() + try: + roles = self.user_roles or [] + except AttributeError: + try: + roles = self.document.accesses.filter( + models.Q(user=user) | models.Q(team__in=teams), + ).values_list("role", flat=True) + except (self._meta.model.DoesNotExist, IndexError): + roles = [] + + can_delete = bool( + set(roles).intersection({RoleChoices.OWNER, RoleChoices.ADMIN}) + ) + + return { + "destroy": can_delete, + "update": False, + "partial_update": False, + "retrieve": bool(roles), + } + + def email_invitation(self): + """Email invitation to the user.""" + try: + with override(self.issuer.language): + title = _("Invitation to join Impress!") + template_vars = {"title": title, "site": Site.objects.get_current()} + msg_html = render_to_string("mail/html/invitation.html", template_vars) + msg_plain = render_to_string("mail/text/invitation.txt", template_vars) + mail.send_mail( + title, + msg_plain, + settings.EMAIL_FROM, + [self.email], + html_message=msg_html, + fail_silently=False, + ) + + except smtplib.SMTPException as exception: + logger.error("invitation to %s was not sent: %s", self.email, exception) diff --git a/src/backend/core/static/images/logo-suite-numerique.png b/src/backend/core/static/images/logo-suite-numerique.png new file mode 100644 index 0000000000000000000000000000000000000000..243c96629ee72f48f0083f4ba6bcea2653c1a9c3 GIT binary patch literal 13584 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 - - - - - - - - - - - -

- {%if fullname%} - {% blocktranslate with name=fullname %}Hello {{ name }}{% endblocktranslate %} - {% else %} - {%trans "Hello" %} - {% endif %}
- {%trans "Thank you very much for your visit!"%} -

- - - - - - - - diff --git a/src/mail/mjml/invitation.mjml b/src/mail/mjml/invitation.mjml new file mode 100644 index 00000000..74b2b471 --- /dev/null +++ b/src/mail/mjml/invitation.mjml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + +

{% trans "Invitation to join a team" %}

+
+ + + +

{% blocktrans %}Welcome to Impress{% endblocktrans %}

+
+ + + + + + {% trans "We are delighted to welcome you to our community on Impress, your new companion to collaborate on documents efficiently, intuitively, and securely." %} + {% trans "Our application is designed to help you organize, collaborate, and manage permissions." %} + + {% trans "With Impress, you will be able to:" %} +
    +
  • {% trans "Create documents."%}
  • +
  • {% trans "Invite members of your document or community in just a few clicks."%}
  • +
+
+ + {% trans "Visit Impress"%} + + {% trans "We are confident that Impress will help you increase efficiency and productivity while strengthening the bond among members." %} + {% trans "Feel free to explore all the features of the application and share your feedback and suggestions with us. Your feedback is valuable to us and will enable us to continually improve our service." %} + {% trans "Once again, welcome aboard! We are eager to accompany you on you collaboration adventure." %} + + + +

{% trans "Sincerely," %}

+

{% trans "The La Suite Numérique Team" %}

+
+
+
+
+
+ + +
+ diff --git a/src/mail/mjml/partial/header.mjml b/src/mail/mjml/partial/header.mjml index 665a3c02..37bc590f 100644 --- a/src/mail/mjml/partial/header.mjml +++ b/src/mail/mjml/partial/header.mjml @@ -14,10 +14,8 @@ font-family="Roboto, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif" font-size="16px" line-height="1.5em" - color="#031963" + color="#3A3A3A" /> - - /* Reset */ @@ -33,7 +31,7 @@ /* Global styles */ h1 { - color: #055FD2; + color: #161616; font-size: 2rem; line-height: 1em; font-weight: 700;