wip: learning mentor

This commit is contained in:
Reto Aebersold 2023-12-04 10:06:19 +01:00
parent 421a10524b
commit 278d659905
16 changed files with 185 additions and 6 deletions

View File

@ -0,0 +1,11 @@
<script setup lang="ts"></script>
<template>
<div class="bg-gray-200">
<main>
<div>
<router-view></router-view>
</div>
</main>
</div>
</template>

View File

@ -130,6 +130,7 @@ LOCAL_APPS = [
"vbv_lernwelt.importer",
"vbv_lernwelt.edoniq_test",
"vbv_lernwelt.course_session_group",
"vbv_lernwelt.learning_mentor",
]
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS

View File

@ -53,6 +53,7 @@ from vbv_lernwelt.importer.views import (
coursesessions_trainers_import,
t2l_sync,
)
from vbv_lernwelt.learning_mentor.views import mentor_summary
from vbv_lernwelt.notify.views import email_notification_settings
from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
@ -125,6 +126,10 @@ urlpatterns = [
request_course_completion_for_user,
name="request_course_completion_for_user"),
path(r"api/mentor/<signed_int:course_session_id>/",
mentor_summary,
name="mentor_summary"),
# assignment
path(
r"api/assignment/<signed_int:assignment_id>/<signed_int:course_session_id>/status/",

View File

@ -10,7 +10,7 @@ from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletionStatu
from vbv_lernwelt.assignment.services import update_assignment_completion
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
from vbv_lernwelt.iam.permissions import has_course_access, is_course_session_expert
from vbv_lernwelt.iam.permissions import can_evaluate_assignments, has_course_access
logger = structlog.get_logger(__name__)
@ -92,7 +92,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
AssignmentCompletionStatus.EVALUATION_SUBMITTED,
AssignmentCompletionStatus.EVALUATION_IN_PROGRESS,
):
if not is_course_session_expert(info.context.user, course_session_id):
if not can_evaluate_assignments(info.context.user, course_session_id):
raise PermissionDenied()
evaluation_data = {

View File

@ -7,7 +7,7 @@ from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.core.graphql.types import JSONStreamField
from vbv_lernwelt.course.graphql.interfaces import CoursePageInterface
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.iam.permissions import has_course_access, is_course_session_expert
from vbv_lernwelt.iam.permissions import can_evaluate_assignments, has_course_access
from vbv_lernwelt.learnpath.graphql.types import LearningContentInterface
@ -103,7 +103,7 @@ def resolve_assignment_completion(
if assignment_user_id is None:
assignment_user_id = info.context.user.id
if str(assignment_user_id) == str(info.context.user.id) or is_course_session_expert(
if str(assignment_user_id) == str(info.context.user.id) or can_evaluate_assignments(
info.context.user, course_session_id
):
course_id = CourseSession.objects.get(id=course_session_id).course_id

View File

@ -4,7 +4,7 @@ from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
from vbv_lernwelt.assignment.models import AssignmentCompletion
from vbv_lernwelt.iam.permissions import is_course_session_expert
from vbv_lernwelt.iam.permissions import can_evaluate_assignments
logger = structlog.get_logger(__name__)
@ -12,7 +12,7 @@ logger = structlog.get_logger(__name__)
@api_view(["GET"])
def request_assignment_completion_status(request, assignment_id, course_session_id):
# TODO quickfix before GraphQL...
if is_course_session_expert(request.user, course_session_id):
if can_evaluate_assignments(request.user, course_session_id):
qs = AssignmentCompletion.objects.filter(
course_session_id=course_session_id,
assignment_id=assignment_id,

View File

@ -48,6 +48,23 @@ def is_course_session_expert(user, course_session_id: int):
return is_supervisor or is_expert
def can_evaluate_assignments(user, course_session_id: int):
if user.is_superuser:
return True
is_supervisor = CourseSessionGroup.objects.filter(
supervisor=user, course_session__id=course_session_id
).exists()
is_expert = CourseSessionUser.objects.filter(
course_session_id=course_session_id,
user=user,
role=CourseSessionUser.Role.EXPERT,
).exists()
return is_supervisor or is_expert
def course_sessions_for_user_qs(user):
if user.is_superuser:
return CourseSession.objects.all()

View File

@ -0,0 +1,10 @@
from django.contrib import admin
from vbv_lernwelt.learning_mentor.models import LearningMentor
@admin.register(LearningMentor)
class LearningMentorAdmin(admin.ModelAdmin):
list_display = [
"mentor_email",
]

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class LearningMentorConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "vbv_lernwelt.learning_mentor"

View File

@ -0,0 +1,42 @@
# Generated by Django 3.2.20 on 2023-12-01 10:11
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="LearningMentor",
fields=[
(
"mentor_email",
models.EmailField(
max_length=254, primary_key=True, serialize=False
),
),
(
"mentor",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
),
),
(
"students",
models.ManyToManyField(
related_name="students", to=settings.AUTH_USER_MODEL
),
),
],
),
]

View File

@ -0,0 +1,13 @@
from django.db import models
from vbv_lernwelt.core.models import User
class LearningMentor(models.Model):
mentor_email = models.EmailField(primary_key=True)
mentor = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
students = models.ManyToManyField(User, related_name="students")
def __str__(self):
return self.mentor_email

View File

@ -0,0 +1,26 @@
from django.urls import reverse
from rest_framework.test import APITestCase
from vbv_lernwelt.course.creators.test_utils import create_course, create_course_session
class LearningMentorAPITest(APITestCase):
# def setUp(self) -> None:
# create_default_users()
# create_test_course(with_sessions=True)
#
# self.mentor = User.objects.get(username="expert-vv.expert1@eiger-versicherungen.ch")
def test_api(self) -> None:
# GIVEN
course, course_page = create_course("Test Course")
course_session = create_course_session(course=course, title="Test VV")
# self.client.force_login(self.mentor)
url = reverse("mentor_summary", kwargs={"course_session_id": course_session.id})
# WHEN
response = self.client.get(url)
# THEN
# self.assertEqual(response.status_code, status.HTTP_200_OK)

View File

@ -0,0 +1,48 @@
from rest_framework.decorators import api_view
from rest_framework.response import Response
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.feedback.models import FeedbackResponse
from vbv_lernwelt.feedback.utils import feedback_users
from vbv_lernwelt.learnpath.models import Circle
def get_practical_assignment():
pass
def get_feedbacks(course_session: CourseSession):
circle_feedbacks = []
fbs = FeedbackResponse.objects.filter(
submitted=True,
course_session=course_session,
feedback_user__in=feedback_users(course_session.id),
)
def get_all_feedbacks(course_session: CourseSession):
circle_feedbacks = []
circles = (
course_session.course.get_learning_path()
.get_descendants()
.live()
.specific()
.exact_type(Circle)
)
print(circles)
@api_view(["GET"])
def mentor_summary(request, course_session_id: int):
if not request.user.is_authenticated:
return Response(status=403)
if request.method == "GET":
course_session = CourseSession.objects.get(id=course_session_id)
get_all_feedbacks(course_session)
return Response({})