vbv/server/vbv_lernwelt/course/views.py

252 lines
7.8 KiB
Python

import uuid
import structlog
from django.shortcuts import get_object_or_404
from rest_framework.decorators import api_view
from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
from wagtail.models import Page
from vbv_lernwelt.core.utils import get_django_content_type
from vbv_lernwelt.course.models import CircleDocument, CourseCompletion, CourseSession
from vbv_lernwelt.course.serializers import (
CourseCompletionSerializer,
CourseSessionSerializer,
DocumentUploadFinishInputSerializer,
DocumentUploadStartInputSerializer,
)
from vbv_lernwelt.course.services import mark_course_completion
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
from vbv_lernwelt.files.models import UploadFile
from vbv_lernwelt.files.services import FileDirectUploadService
from vbv_lernwelt.iam.permissions import (
can_mark_course_completion,
can_view_course_completions,
course_sessions_for_user_qs,
has_course_access,
has_course_access_by_page_request,
is_circle_expert,
)
from vbv_lernwelt.learning_mentor.models import LearningMentor
logger = structlog.get_logger(__name__)
@api_view(["GET"])
def course_page_api_view(request, slug_or_id):
try:
if slug_or_id.isdigit():
page = Page.objects.get(id=slug_or_id)
else:
page = Page.objects.get(slug=slug_or_id)
if not has_course_access_by_page_request(request, page):
raise PermissionDenied()
data = page.specific.get_serializer_class()(page.specific).data
return Response(data)
except PermissionDenied as e:
raise e
except Exception as e:
logger.exception(e)
return Response({"error": str(e)}, status=404)
def _request_course_completion(course_session_id, user_id):
try:
response_data = CourseCompletionSerializer(
CourseCompletion.objects.filter(
user_id=user_id, course_session_id=course_session_id
),
many=True,
).data
return Response(status=200, data=response_data)
except PermissionDenied as e:
raise e
except Exception as e:
logger.error(e)
return Response({"error": str(e)}, status=404)
@api_view(["GET"])
def request_course_completion(request, course_session_id):
course_id = get_object_or_404(CourseSession, id=course_session_id).course_id
if has_course_access(request.user, course_id):
return _request_course_completion(course_session_id, request.user.id)
raise PermissionDenied()
@api_view(["GET"])
def request_course_completion_for_user(
request, course_session_id: int, user_id: uuid.UUID
):
if can_view_course_completions(
user=request.user, # noqa
course_session_id=course_session_id,
target_user_id=str(user_id),
):
return _request_course_completion(course_session_id, user_id)
raise PermissionDenied()
@api_view(["POST"])
def mark_course_completion_view(request):
try:
page_id = request.data.get("page_id")
completion_status = request.data.get("completion_status", "SUCCESS")
course_session_id = request.data.get("course_session_id")
page = Page.objects.get(id=page_id)
if not can_mark_course_completion(
user=request.user, # noqa
course_session_id=course_session_id,
):
raise PermissionDenied()
mark_course_completion(
page=page,
user=request.user,
course_session=CourseSession.objects.get(id=course_session_id),
completion_status=completion_status,
)
response_data = CourseCompletionSerializer(
CourseCompletion.objects.filter(
user=request.user, course_session_id=course_session_id
),
many=True,
).data
logger.debug(
"mark_course_completion successful",
label="completion_api",
page_id=page_id,
page_type=get_django_content_type(page.specific),
page_slug=page.slug,
page_title=page.title,
user_id=request.user.id,
course_session_id=course_session_id,
completion_status=completion_status,
)
return Response(status=200, data=response_data)
except PermissionDenied as e:
raise e
except Exception as e:
logger.error(e, exc_info=True)
return Response({"error": str(e)}, status=404)
@api_view(["GET"])
def get_course_sessions(request):
try:
# participant/member/expert course sessions
regular_course_sessions = course_sessions_for_user_qs(
request.user
).prefetch_related("course")
# enrich with supervisor course sessions
supervisor_course_sessions = CourseSession.objects.filter(
id__in=CourseSessionGroup.objects.filter(
supervisor=request.user
).values_list("course_session", flat=True)
).prefetch_related("course")
# enrich with mentor course sessions
mentor_course_sessions = CourseSession.objects.filter(
id__in=LearningMentor.objects.filter(mentor=request.user).values_list(
"course_session", flat=True
)
).prefetch_related("course")
all_to_serialize = (
regular_course_sessions
| supervisor_course_sessions
| mentor_course_sessions
).distinct()
return Response(
status=200,
data=CourseSessionSerializer(
all_to_serialize, many=True, context={"user": request.user}
).data,
)
except PermissionDenied as e:
raise e
except Exception as e:
logger.error(e, exc_info=True)
return Response({"error": str(e)}, status=404)
@api_view(["POST"])
def document_upload_start(request):
serializer = DocumentUploadStartInputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
if not is_circle_expert(
request.user,
serializer.validated_data["course_session"],
serializer.validated_data["learning_sequence"],
):
raise PermissionDenied()
service = FileDirectUploadService(request.user)
file, presigned_data = service.start(
serializer.validated_data["file_name"], serializer.validated_data["file_type"]
)
document = CircleDocument(
file=file,
name=serializer.validated_data["name"],
course_session_id=serializer.validated_data["course_session"],
learning_sequence_id=serializer.validated_data["learning_sequence"],
)
document.save()
presigned_data["id"] = document.id
presigned_data["file_id"] = file.id
return Response(data=presigned_data)
@api_view(["POST"])
def document_upload_finish(request):
serializer = DocumentUploadFinishInputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
file_id = serializer.validated_data["file_id"]
file = get_object_or_404(UploadFile, id=file_id)
if file.uploaded_by != request.user:
raise PermissionDenied()
service = FileDirectUploadService(request.user)
service.finish(file=file)
return Response({"url": file.url})
@api_view(["POST"])
def document_direct_upload(request, file_id):
file = get_object_or_404(UploadFile, id=file_id)
file_obj = request.FILES["file"]
service = FileDirectUploadService(request.user)
file = service.upload_local(file=file, file_obj=file_obj)
return Response({"url": file.url})
@api_view(["DELETE"])
def document_delete(request, document_id):
document = get_object_or_404(CircleDocument, id=document_id)
if not is_circle_expert(
request.user, document.course_session.id, document.learning_sequence.id
):
raise PermissionDenied()
document.delete()
return Response(status=200)