diff --git a/server/vbv_lernwelt/learning_mentor/tests/test_invitation.py b/server/vbv_lernwelt/learning_mentor/tests/test_invitation.py index 5eacddbe..aefff4c8 100644 --- a/server/vbv_lernwelt/learning_mentor/tests/test_invitation.py +++ b/server/vbv_lernwelt/learning_mentor/tests/test_invitation.py @@ -1,3 +1,5 @@ +from unittest.mock import patch + from django.urls import reverse from rest_framework import status from rest_framework.test import APITestCase @@ -9,6 +11,8 @@ from vbv_lernwelt.course.creators.test_utils import ( create_user, ) from vbv_lernwelt.course.models import CourseSessionUser +from vbv_lernwelt.learning_mentor.models import MentorInvitation +from vbv_lernwelt.notify.email.email_services import EmailTemplate class LearningMentorInvitationTest(APITestCase): @@ -31,10 +35,11 @@ class LearningMentorInvitationTest(APITestCase): # THEN self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - def test_create_invitation(self) -> None: + @patch("vbv_lernwelt.learning_mentor.views.send_email") + def test_create_invitation(self, mock_send_mail) -> None: # GIVEN self.client.force_login(self.participant) - add_course_session_user( + participant_cs_user = add_course_session_user( self.course_session, self.participant, role=CourseSessionUser.Role.MEMBER, @@ -42,9 +47,44 @@ class LearningMentorInvitationTest(APITestCase): invite_url = reverse( "create_invitation", kwargs={"course_session_id": self.course_session.id} ) + email = "test@example.com" # WHEN - response = self.client.post(invite_url, data={"email": "test@example.com"}) + response = self.client.post(invite_url, data={"email": email}) # THEN + invitation_id = response.data["invitation"] self.assertEqual(response.status_code, status.HTTP_200_OK) + + self.assertTrue( + MentorInvitation.objects.filter( + id=invitation_id, + ).exists() + ) + + mock_send_mail.assert_called_once_with( + recipient_email=email, + template=EmailTemplate.LEARNING_MENTOR_INVITATION, + template_data={ + "inviter_name": f"{self.participant.first_name} {self.participant.last_name}", + "inviter_email": self.participant.email, + "target_url": f"https://my.vbv-afa.ch/lernbegleitung/{self.course_session.id}/invitation/{invitation_id}", + }, + template_language=self.participant.language, + fail_silently=True, + ) + + def test_accept_invitation(self) -> None: + # GIVEN + invitee = create_user("invitee") + self.client.force_login(invitee) + + accept_url = reverse( + "create_invitation", kwargs={"course_session_id": self.course_session.id} + ) + + # WHEN + response = self.client.get(accept_url) + + # THEN + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) diff --git a/server/vbv_lernwelt/learning_mentor/tests/test_api.py b/server/vbv_lernwelt/learning_mentor/tests/test_mentor.py similarity index 100% rename from server/vbv_lernwelt/learning_mentor/tests/test_api.py rename to server/vbv_lernwelt/learning_mentor/tests/test_mentor.py diff --git a/server/vbv_lernwelt/learning_mentor/urls.py b/server/vbv_lernwelt/learning_mentor/urls.py index 88e9cba3..0f184849 100644 --- a/server/vbv_lernwelt/learning_mentor/urls.py +++ b/server/vbv_lernwelt/learning_mentor/urls.py @@ -5,4 +5,5 @@ from . import views urlpatterns = [ path("summary", views.mentor_summary, name="mentor_summary"), path("invite", views.create_invitation, name="create_invitation"), + path("accept", views.accept_invitation, name="accept_invitation"), ] diff --git a/server/vbv_lernwelt/learning_mentor/views.py b/server/vbv_lernwelt/learning_mentor/views.py index e3de9cad..8729bac2 100644 --- a/server/vbv_lernwelt/learning_mentor/views.py +++ b/server/vbv_lernwelt/learning_mentor/views.py @@ -1,4 +1,3 @@ -from django.shortcuts import redirect from rest_framework import permissions from rest_framework.decorators import api_view, permission_classes from rest_framework.generics import get_object_or_404 @@ -14,6 +13,7 @@ from vbv_lernwelt.learning_mentor.content.praxis_assignment import ( from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation from vbv_lernwelt.learning_mentor.serializers import PraxisAssignmentStatusSerializer from vbv_lernwelt.learnpath.models import Circle +from vbv_lernwelt.notify.email.email_services import EmailTemplate, send_email @api_view(["GET"]) @@ -59,26 +59,40 @@ def list_invitations(request, course_session_id: int): @api_view(["POST"]) @permission_classes([IsAuthenticated, CourseSessionMember]) def create_invitation(request, course_session_id: int): + user = request.user + course_session = get_object_or_404(CourseSession, id=course_session_id) course_session_user = get_object_or_404( - CourseSessionUser, user=request.user, course_session=course_session + CourseSessionUser, user=user, course_session=course_session ) email = request.data.get("email") if not email: return Response({"error": "email is required"}, status=400) - invitation = MentorInvitation.objects.get_or_create( + invitation, _ = MentorInvitation.objects.get_or_create( email=email, participant=course_session_user, ) - return Response({}) + target_url = f"/lernbegleitung/{course_session_id}/invitation/{invitation.id}" + + send_email( + recipient_email=email, + template=EmailTemplate.LEARNING_MENTOR_INVITATION, + template_data={ + "inviter_name": f"{user.first_name} {user.last_name}", + "inviter_email": user.email, + "target_url": f"https://my.vbv-afa.ch{target_url}", + }, + template_language=request.user.language, + fail_silently=True, + ) + + return Response({"invitation": invitation.id}) -@api_view(["GET"]) +@api_view(["POST"]) +@permission_classes([IsAuthenticated]) def accept_invitation(request, course_session_id: int): - if not request.user.is_authenticated: - return redirect(f"/onboarding/vv/account/create?next={request.path}") - - # Validate invitation + return Response({}) diff --git a/server/vbv_lernwelt/notify/email/email_services.py b/server/vbv_lernwelt/notify/email/email_services.py index 66cb7b97..ed36f748 100644 --- a/server/vbv_lernwelt/notify/email/email_services.py +++ b/server/vbv_lernwelt/notify/email/email_services.py @@ -62,6 +62,9 @@ class EmailTemplate(Enum): # VBV - Neues Feedback für Circle NEW_FEEDBACK = {"de": "d-40fb94d5149949e7b8e7ddfcf0fcfdde"} + # VBV - Lernbegleitung Einladung + LEARNING_MENTOR_INVITATION = {"de": "", "fr": "", "it": ""} + def send_email( recipient_email: str,