Skip to content
Snippets Groups Projects
Commit 0706be63 authored by Tore.Brede's avatar Tore.Brede
Browse files

GREG-94: Changing resend logic

parent 663ef121
No related branches found
No related tags found
1 merge request!136GREG-94: Resend invitation
Pipeline #99838 failed
import re import re
import datetime
from datetime import date from datetime import date
from django.utils import timezone
def camel_to_snake(s: str) -> str: def camel_to_snake(s: str) -> str:
...@@ -90,3 +92,7 @@ def _compute_checksum(input_digits: str) -> bool: ...@@ -90,3 +92,7 @@ def _compute_checksum(input_digits: str) -> bool:
k2 = 0 k2 = 0
return k1 < 10 and k2 < 10 and k1 == d[9] and k2 == d[10] return k1 < 10 and k2 < 10 and k1 == d[9] and k2 == d[10]
def get_default_invitation_expire_date_from_now():
return timezone.now() + datetime.timedelta(days=30)
import datetime
import logging import logging
import uuid
from enum import Enum from enum import Enum
from typing import Optional from typing import Optional
...@@ -8,19 +6,18 @@ from django.core import exceptions ...@@ -8,19 +6,18 @@ from django.core import exceptions
from django.db import transaction from django.db import transaction
from django.http.response import JsonResponse from django.http.response import JsonResponse
from django.utils import timezone from django.utils import timezone
from django.utils.timezone import now
from rest_framework import status from rest_framework import status
from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.generics import CreateAPIView, GenericAPIView
from rest_framework.mixins import UpdateModelMixin
from rest_framework.generics import CreateAPIView, GenericAPIView, DestroyAPIView from rest_framework.generics import CreateAPIView, GenericAPIView, DestroyAPIView
from rest_framework.mixins import UpdateModelMixin
from rest_framework.parsers import JSONParser from rest_framework.parsers import JSONParser
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from greg.models import Identity, InvitationLink, Person, Invitation from greg.models import Identity, InvitationLink, Person
from greg.permissions import IsSponsor from greg.permissions import IsSponsor
from greg.utils import get_default_invitation_expire_date_from_now
from gregui.api.serializers.guest import GuestRegisterSerializer from gregui.api.serializers.guest import GuestRegisterSerializer
from gregui.api.serializers.invitation import InviteGuestSerializer from gregui.api.serializers.invitation import InviteGuestSerializer
from gregui.mailutils import send_invite_mail from gregui.mailutils import send_invite_mail
...@@ -312,18 +309,37 @@ class ResendInvitationView(UpdateModelMixin, APIView): ...@@ -312,18 +309,37 @@ class ResendInvitationView(UpdateModelMixin, APIView):
# No invitation, not expected that the endpoint should be called in this case # No invitation, not expected that the endpoint should be called in this case
return Response(status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_400_BAD_REQUEST)
if invitation_links.count() > 1: non_expired_links = invitation_links.filter(expire__gt=timezone.now())
logger.warning(f"Person with ID {person_id} has multiple invitation links")
if non_expired_links.count() > 0:
for link in invitation_links: if non_expired_links.count() > 1:
link.uuid = uuid.uuid4() # Do not expect this to happen
link.expire = timezone.now() + datetime.timedelta(days=30) logger.warning(
link.save() f"Person with ID {person_id} has multiple invitation links"
# invitationlink = InvitationLink.objects.create( )
# invitation=link.invitation,
# expire=timezone.now() + datetime.timedelta(days=30), # Just resend all and do not create a new one
# ) for link in non_expired_links:
send_invite_mail(link)
else:
# All the invitation links have expired, create a new one
invitations_to_resend = set(
[invitation_link.invitation for invitation_link in invitation_links]
)
send_invite_mail(link) if len(invitations_to_resend) > 1:
# Do not expected that a person has several open invitations, it could happen
# if he has been invited by different sponsor at the same time, but that
# could be an indication that there has been a mixup
logger.warning(
f"Multiple invitations exist for person with ID {person_id}"
)
for invitation in invitations_to_resend:
invitation_link = InvitationLink.objects.create(
invitation=invitation,
expire=get_default_invitation_expire_date_from_now(),
)
send_invite_mail(invitation_link)
return Response(status=status.HTTP_200_OK) return Response(status=status.HTTP_200_OK)
...@@ -13,7 +13,7 @@ logger = logging.getLogger(__name__) ...@@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
def prepare_arguments( def prepare_arguments(
template: EmailTemplate, context: dict[str, str], mail_to: str template: EmailTemplate, context: dict[str, str], mail_to: str
) -> dict[str, Union[str, list[str]]]: ) -> dict[str, Union[str, list[str]]]:
"""Combine input to a dict ready for use as arguments ti django's send_mail""" """Combine input to a dict ready for use as arguments ti django's send_mail"""
return { return {
...@@ -25,7 +25,7 @@ def prepare_arguments( ...@@ -25,7 +25,7 @@ def prepare_arguments(
def registration_template( def registration_template(
institution: str, sponsor: str, mail_to: str institution: str, sponsor: str, mail_to: str
) -> dict[str, Union[str, list[str]]]: ) -> dict[str, Union[str, list[str]]]:
""" """
Prepare email for registration Prepare email for registration
...@@ -74,7 +74,7 @@ def send_invite_mail(link: InvitationLink) -> Optional[str]: ...@@ -74,7 +74,7 @@ def send_invite_mail(link: InvitationLink) -> Optional[str]:
email_address = link.invitation.role.person.private_email email_address = link.invitation.role.person.private_email
if not email_address: if not email_address:
logger.warning( logger.warning(
f"No e-mail address found for invitation link with ID: {link.id}" "No e-mail address found for invitation link with ID: {%s}" % link.id
) )
return None return None
......
import datetime import datetime
import pytest import pytest
from django.utils import timezone
from rest_framework import status from rest_framework import status
from rest_framework.reverse import reverse from rest_framework.reverse import reverse
from rest_framework.test import APIRequestFactory, force_authenticate from rest_framework.test import APIRequestFactory, force_authenticate
...@@ -69,3 +71,85 @@ def test_invite_cancel( ...@@ -69,3 +71,85 @@ def test_invite_cancel(
assert Role.objects.filter(id=role.id).count() == 0 assert Role.objects.filter(id=role.id).count() == 0
assert Invitation.objects.filter(id=invitation.id).count() == 0 assert Invitation.objects.filter(id=invitation.id).count() == 0
assert InvitationLink.objects.filter(invitation__id=invitation.id).count() == 0 assert InvitationLink.objects.filter(invitation__id=invitation.id).count() == 0
@pytest.mark.django_db
def test_invite_resend_existing_invite_active(
client,
log_in,
user_sponsor,
person,
invitation,
invitation_link,
invitation_link_expired,
mocker,
):
send_invite_mock_function = mocker.patch(
"gregui.api.views.invitation.send_invite_mail"
)
log_in(user_sponsor)
invitation_links_for_person = InvitationLink.objects.filter(
invitation__role__person_id=person.id
)
assert invitation_links_for_person.count() == 2
original_expire_date = invitation_link_expired.expire
original_date = invitation_link.expire
url = reverse("gregui-v1:invite-resend", kwargs={"person_id": person.id})
response = client.patch(url)
assert response.status_code == status.HTTP_200_OK
# One e-mail should have been sent with an invite
assert send_invite_mock_function.call_count == 1
# Just check that the expire dates have not changed
invitation_link_expired.refresh_from_db()
assert original_expire_date == invitation_link_expired.expire
invitation_link.refresh_from_db()
assert original_date == invitation_link.expire
# The number of invitations should not have changed
invitation_links_for_person = InvitationLink.objects.filter(
invitation__role__person_id=person.id
)
assert invitation_links_for_person.count() == 2
@pytest.mark.django_db
def test_invite_resend_existing_invite_not_active(
client, log_in, user_sponsor, person, invitation_link_expired, mocker
):
send_invite_mock_function = mocker.patch(
"gregui.api.views.invitation.send_invite_mail", return_value=10
)
log_in(user_sponsor)
invitation_links_for_person = InvitationLink.objects.filter(
invitation__role__person_id=person.id
)
assert invitation_links_for_person.count() == 1
original_expire_date = invitation_link_expired.expire
url = reverse("gregui-v1:invite-resend", kwargs={"person_id": person.id})
response = client.patch(url)
assert response.status_code == status.HTTP_200_OK
# One e-mail should have been sent with an invite
assert send_invite_mock_function.call_count == 1
# Just check that the expire dates have not changed
invitation_link_expired.refresh_from_db()
assert original_expire_date == invitation_link_expired.expire
# There should now be two invitations
invitation_links_for_person = InvitationLink.objects.filter(
invitation__role__person_id=person.id
)
assert invitation_links_for_person.count() == 2
# If there is no active link the following line will raise an exception
InvitationLink.objects.get(
invitation__role__person_id=person.id, expire__gt=timezone.now()
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment