From 8eed0d03e51801b81686f88964f217c61da58902 Mon Sep 17 00:00:00 2001 From: Anler Hp Date: Fri, 25 Jul 2014 10:50:30 +0200 Subject: [PATCH] Task #399 - Memberships' resend-invitation handler In order to resend and invitation email you just POST to detail-url `memberships-resend-invitation` --- settings/testing.py | 2 ++ taiga/projects/api.py | 11 ++++++----- taiga/projects/services/__init__.py | 2 ++ taiga/projects/services/invitations.py | 8 ++++++++ tests/factories.py | 17 +++++++++++++++++ tests/fixtures.py | 7 +++++++ tests/integration/test_memberships.py | 12 ++++++++++++ 7 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 taiga/projects/services/invitations.py diff --git a/settings/testing.py b/settings/testing.py index 13fe1999..36cb7571 100644 --- a/settings/testing.py +++ b/settings/testing.py @@ -22,3 +22,5 @@ SOUTH_TESTS_MIGRATE = False CELERY_ALWAYS_EAGER = True MEDIA_ROOT = "/tmp" + +EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 823991b0..3f256081 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -25,8 +25,6 @@ from rest_framework.exceptions import ParseError from rest_framework import viewsets from rest_framework import status -from djmail.template_mail import MagicMailBuilder - from taiga.base import filters from taiga.base import exceptions as exc from taiga.base.decorators import list_route @@ -182,6 +180,11 @@ class MembershipViewSet(ModelCrudViewSet): members_serialized = self.serializer_class(members, many=True) return Response(data=members_serialized.data) + @detail_route(methods=["POST"]) + def resend_invitation(self, request, **kwargs): + services.send_invitation(invitation=self.get_object()) + return Response(status=status.HTTP_204_NO_CONTENT) + def pre_save(self, object): # Only assign new token if a current token value is empty. if not object.token: @@ -196,9 +199,7 @@ class MembershipViewSet(ModelCrudViewSet): return # Send email only if a new membership is created - mbuilder = MagicMailBuilder() - email = mbuilder.membership_invitation(object.email, {"membership": object}) - email.send() + services.send_invitation(invitation=object) class InvitationViewSet(ModelListViewSet): diff --git a/taiga/projects/services/__init__.py b/taiga/projects/services/__init__.py index 0276e3c5..4f46c6af 100644 --- a/taiga/projects/services/__init__.py +++ b/taiga/projects/services/__init__.py @@ -33,3 +33,5 @@ from .stats import get_stats_for_project from .members import create_members_in_bulk from .members import get_members_from_bulk + +from .invitations import send_invitation diff --git a/taiga/projects/services/invitations.py b/taiga/projects/services/invitations.py new file mode 100644 index 00000000..34e23010 --- /dev/null +++ b/taiga/projects/services/invitations.py @@ -0,0 +1,8 @@ +from djmail.template_mail import MagicMailBuilder + + +def send_invitation(invitation): + """Send an invitation email""" + mbuilder = MagicMailBuilder() + email = mbuilder.membership_invitation(invitation.email, {"membership": invitation}) + email.send() diff --git a/tests/factories.py b/tests/factories.py index ae980c9d..e0a9ae73 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -348,6 +348,23 @@ def create_membership(**kwargs): return MembershipFactory.create(**defaults) +def create_invitation(**kwargs): + "Create an invitation along with its dependencies" + project = kwargs.pop("project", ProjectFactory()) + project.points.add(PointsFactory.create(project=project, value=None)) + + defaults = { + "project": project, + "role": RoleFactory.create(project=project), + "email": "invited-user@email.com", + "token": "tokenvalue", + "invited_by_id": project.owner.id + } + defaults.update(kwargs) + + return MembershipFactory.create(**defaults) + + def create_userstory(**kwargs): "Create an user story along with its dependencies" project = kwargs.pop("project", ProjectFactory()) diff --git a/tests/fixtures.py b/tests/fixtures.py index da177227..75f5134f 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -32,3 +32,10 @@ def client(): from testclient_extensions import Client return Client() + + +@pytest.fixture +def outbox(): + from django.core import mail + + return mail.outbox diff --git a/tests/integration/test_memberships.py b/tests/integration/test_memberships.py index f7377661..148dccfd 100644 --- a/tests/integration/test_memberships.py +++ b/tests/integration/test_memberships.py @@ -51,3 +51,15 @@ def test_api_create_bulk_members(client): assert response.status_code == 200 assert response.data[0]["email"] == john.email assert response.data[1]["email"] == joseph.email + + +def test_api_resend_invitation(client, outbox): + invitation = f.create_invitation() + url = reverse("memberships-resend-invitation", kwargs={"pk": invitation.pk}) + + client.login(invitation.project.owner) + response = client.post(url) + + assert response.status_code == 204 + assert len(outbox) == 1 + assert outbox[0].to == [invitation.email]