diff --git a/server/vbv_lernwelt/learning_mentor/admin.py b/server/vbv_lernwelt/learning_mentor/admin.py index 92ec7e7b..112b4838 100644 --- a/server/vbv_lernwelt/learning_mentor/admin.py +++ b/server/vbv_lernwelt/learning_mentor/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from vbv_lernwelt.learning_mentor.models import LearningMentor +from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation @admin.register(LearningMentor) @@ -11,3 +11,9 @@ class LearningMentorAdmin(admin.ModelAdmin): participant_count.short_description = "Participants" list_display = ["mentor", "course", "participant_count"] + + +@admin.register(MentorInvitation) +class MentorInvitationAdmin(admin.ModelAdmin): + list_display = ["id", "email", "participant", "created"] + readonly_fields = ["id", "created"] diff --git a/server/vbv_lernwelt/learning_mentor/migrations/0002_mentorinvitation.py b/server/vbv_lernwelt/learning_mentor/migrations/0002_mentorinvitation.py new file mode 100644 index 00000000..5d0dc191 --- /dev/null +++ b/server/vbv_lernwelt/learning_mentor/migrations/0002_mentorinvitation.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.20 on 2023-12-07 13:46 + +from django.db import migrations, models +import django.db.models.deletion +import django_extensions.db.fields +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0005_course_enable_circle_documents'), + ('learning_mentor', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='MentorInvitation', + fields=[ + ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')), + ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('email', models.EmailField(max_length=254)), + ('participant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='course.coursesessionuser')), + ], + options={ + 'verbose_name': 'Mentor Invitation', + 'verbose_name_plural': 'Mentor Invitations', + }, + ), + ] diff --git a/server/vbv_lernwelt/learning_mentor/migrations/0003_auto_20231207_1448.py b/server/vbv_lernwelt/learning_mentor/migrations/0003_auto_20231207_1448.py new file mode 100644 index 00000000..b14bbb59 --- /dev/null +++ b/server/vbv_lernwelt/learning_mentor/migrations/0003_auto_20231207_1448.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.20 on 2023-12-07 13:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('learning_mentor', '0002_mentorinvitation'), + ] + + operations = [ + migrations.AlterModelOptions( + name='learningmentor', + options={'verbose_name': 'Lernbegleiter', 'verbose_name_plural': 'Lernbegleiter'}, + ), + migrations.AlterModelOptions( + name='mentorinvitation', + options={'verbose_name': 'Lernbegleiter Einladung', 'verbose_name_plural': 'Lernbegleiter Einladungen'}, + ), + ] diff --git a/server/vbv_lernwelt/learning_mentor/models.py b/server/vbv_lernwelt/learning_mentor/models.py index 1ecee56c..07c31dc3 100644 --- a/server/vbv_lernwelt/learning_mentor/models.py +++ b/server/vbv_lernwelt/learning_mentor/models.py @@ -1,4 +1,7 @@ +import uuid + from django.db import models +from django_extensions.db.models import TimeStampedModel from vbv_lernwelt.core.models import User from vbv_lernwelt.course.models import CourseSessionUser @@ -16,6 +19,8 @@ class LearningMentor(models.Model): class Meta: unique_together = [["mentor", "course"]] + verbose_name = "Lernbegleiter" + verbose_name_plural = "Lernbegleiter" def __str__(self): return f"{self.mentor} ({self.course.title})" @@ -23,3 +28,18 @@ class LearningMentor(models.Model): @property def course_sessions(self): return self.participants.values_list("course_session", flat=True).distinct() + + +class MentorInvitation(TimeStampedModel): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + email = models.EmailField() + participant = models.ForeignKey( + CourseSessionUser, on_delete=models.CASCADE + ) + + def __str__(self): + return f"{self.email} ({self.participant})" + + class Meta: + verbose_name = "Lernbegleiter Einladung" + verbose_name_plural = "Lernbegleiter Einladungen" diff --git a/server/vbv_lernwelt/learning_mentor/views.py b/server/vbv_lernwelt/learning_mentor/views.py index e791071d..8ea1393d 100644 --- a/server/vbv_lernwelt/learning_mentor/views.py +++ b/server/vbv_lernwelt/learning_mentor/views.py @@ -1,5 +1,7 @@ -from rest_framework.decorators import api_view +from django.shortcuts import redirect +from rest_framework.decorators import api_view, permission_classes from rest_framework.generics import get_object_or_404 +from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from vbv_lernwelt.core.serializers import UserSerializer @@ -13,30 +15,50 @@ from vbv_lernwelt.learnpath.models import Circle @api_view(["GET"]) +@permission_classes([IsAuthenticated]) def mentor_summary(request, course_session_id: int): + course_session = CourseSession.objects.get(id=course_session_id) + + mentor = get_object_or_404( + LearningMentor, mentor=request.user, course=course_session.course + ) + + participants = mentor.participants.filter(course_session=course_session) + users = [p.user for p in participants] + + praxis_assignments, circle_ids = get_praxis_assignments(course_session, users) + + circles = Circle.objects.filter(id__in=circle_ids).values("id", "title") + + return Response( + { + "participants": [UserSerializer(user).data for user in users], + "circles": list(circles), + "praxis_assignments": PraxisAssignmentStatusSerializer( + praxis_assignments, many=True + ).data, + } + ) + + +@api_view(["GET"]) +@permission_classes([IsAuthenticated]) +def list_invitations(request, course_session_id: int): + pass + + +@api_view(["POST"]) +@permission_classes([IsAuthenticated]) +def create_invitation(request, course_session_id: int): + # Validate request + # Create invitation + # Send email + pass + + +@api_view(["GET"]) +def accept_invitation(request, course_session_id: int): if not request.user.is_authenticated: - return Response(status=403) + return redirect(f"/onboarding/vv/account/create?next={request.path}") - if request.method == "GET": - course_session = CourseSession.objects.get(id=course_session_id) - - mentor = get_object_or_404( - LearningMentor, mentor=request.user, course=course_session.course - ) - - participants = mentor.participants.filter(course_session=course_session) - users = [p.user for p in participants] - - praxis_assignments, circle_ids = get_praxis_assignments(course_session, users) - - circles = Circle.objects.filter(id__in=circle_ids).values("id", "title") - - return Response( - { - "participants": [UserSerializer(user).data for user in users], - "circles": list(circles), - "praxis_assignments": PraxisAssignmentStatusSerializer( - praxis_assignments, many=True - ).data, - } - ) + # Validate invitation