feat: mentor invitation

This commit is contained in:
Reto Aebersold 2023-12-08 08:31:42 +01:00
parent 50738b2bf3
commit 3205eac33f
5 changed files with 126 additions and 26 deletions

View File

@ -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"]

View File

@ -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',
},
),
]

View File

@ -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'},
),
]

View File

@ -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"

View File

@ -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