Repository: liqd/a4-opin

Issue:
Wrong user in project
When I get an invitation to a project via email and I am logged in with a different user and click one the link in the email, the second user is added to the project


Discussion:

Resolving patch:
diff --git a/euth/memberships/forms.py b/euth/memberships/forms.py
--- a/euth/memberships/forms.py
+++ b/euth/memberships/forms.py
@@ -12,10 +12,17 @@ class Meta:
         model = models.Invite
         fields = ['accept', 'reject']
 
+    def __init__(self, user=None, **kwargs):
+        super().__init__(**kwargs)
+        self.user = user
+
     def clean(self):
         data = self.data
         if 'accept' not in data and 'reject' not in data:
             raise ValidationError('Reject or accept')
+        if 'accept' in data and not self.user.email == self.instance.email:
+            raise ValidationError('This user has another email address than '
+                                  'the one that received the invitation.')
         return data
 
     def is_accepted(self):
diff --git a/euth/memberships/views.py b/euth/memberships/views.py
--- a/euth/memberships/views.py
+++ b/euth/memberships/views.py
@@ -43,6 +43,11 @@ class InviteView(mixin.LoginRequiredMixin, generic.UpdateView):
     slug_field = 'token'
     slug_url_kwarg = 'invite_token'
 
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs.update({'user': self.request.user})
+        return kwargs
+
     def form_valid(self, form):
         if form.is_accepted():
             form.instance.accept(self.request.user)


Test patch:
diff --git a/tests/memberships/test_memberships_models.py b/tests/memberships/test_memberships_models.py
--- a/tests/memberships/test_memberships_models.py
+++ b/tests/memberships/test_memberships_models.py
@@ -48,14 +48,14 @@ def test_invite_email(project, user):
 
 
 @pytest.mark.django_db
-def test_invate_accept(invite, user):
+def test_invite_accept(invite, user):
     invite.accept(user)
     assert not bool(models.Invite.objects.filter(pk=invite.pk))
     assert user in invite.project.participants.all()
 
 
 @pytest.mark.django_db
-def test_invate_reject(invite, user):
+def test_invite_reject(invite, user):
     invite.reject()
     assert not bool(models.Invite.objects.filter(pk=invite.pk))
     assert user not in invite.project.participants.all()
diff --git a/tests/memberships/test_memberships_views.py b/tests/memberships/test_memberships_views.py
--- a/tests/memberships/test_memberships_views.py
+++ b/tests/memberships/test_memberships_views.py
@@ -4,6 +4,7 @@
 
 from euth.memberships import models
 from tests.helpers import redirect_target, templates_used
+from tests.memberships.factories import InviteFactory
 
 
 @pytest.mark.django_db
@@ -82,7 +83,35 @@ def test_create_request(client, project, user):
 
 
 @pytest.mark.django_db
-def test_accept_invite(client, invite, user):
+def test_cant_accept_invite(client, invite, user):
+    url = reverse('membership-invite-accept',
+                  kwargs={'invite_token': invite.token})
+    response = client.get(url)
+    assert redirect_target(response) == 'account_login'
+
+    client.login(username=user.email, password='password')
+    response = client.get(url)
+    assert response.status_code == 200
+    assert (
+        'euth_projects/includes/project_hero_unit.html'
+        in templates_used(response)
+    )
+    assert 'euth_memberships/invite_form.html' in templates_used(response)
+
+    response = client.post(url, data={'accept': ''})
+    assert response.status_code == 200
+    assert (
+        'This user has another email address '
+        'than the one that received the invitation.'
+        in response.context['form'].errors['__all__']
+    )
+    assert user not in invite.project.participants.all()
+
+
+@pytest.mark.django_db
+def test_accept_invite(client, user):
+    invite = InviteFactory(email=user.email)
+    assert invite.email == user.email
     url = reverse('membership-invite-accept',
                   kwargs={'invite_token': invite.token})
     response = client.get(url)