diff --git a/physionet-django/training/views.py b/physionet-django/training/views.py index 6b2b56aa1..6ed60a575 100644 --- a/physionet-django/training/views.py +++ b/physionet-django/training/views.py @@ -41,7 +41,23 @@ def get_course_and_module_progress(user, course, module_order): This function takes a user, course, and module order as input parameters, and returns the course progress and module progress objects associated with the user, course, and module order. """ - course_progress, _ = CourseProgress.objects.get_or_create(user=user, course=course) + # get the course progress of the user for the course + course_progress = CourseProgress.objects.filter(user=user, course=course).first() + if not course_progress: + course_progress = CourseProgress.objects.create(user=user, course=course) + # Initiate the training and set the status to review + slug = get_random_string(20) + while Training.objects.filter(slug=slug).exists(): + slug = get_random_string(20) + training = Training() + training.slug = slug + training.training_type = course.training_type + training.user = user + training.course = course + training.process_datetime = timezone.now() + training.status = TrainingStatus.REVIEW + training.save() + module = get_object_or_404(course.modules, order=module_order) module_progress, _ = ModuleProgress.objects.get_or_create(course_progress=course_progress, module=module) return course_progress, module_progress @@ -88,16 +104,7 @@ def handle_course_completion(course, course_progress): with transaction.atomic(): course_progress.status = CourseProgress.Status.COMPLETED course_progress.save() - training = Training() - slug = get_random_string(20) - while Training.objects.filter(slug=slug).exists(): - slug = get_random_string(20) - - training.slug = slug - training.training_type = course_progress.course.training_type - training.course = course_progress.course - training.user = course_progress.user - training.process_datetime = timezone.now() + training = Training.objects.filter(course=course, user=course_progress.user).first() training.status = TrainingStatus.ACCEPTED training.save() @@ -275,8 +282,7 @@ def take_training(request, training_slug): if course is None: raise Http404() modules = Module.objects.filter(course=course).order_by('order') - # get the progress of the user for the modules, updated_date - course_progress, _ = CourseProgress.objects.get_or_create(user=request.user, course=course) + course_progress, _ = get_course_and_module_progress(request.user, course, modules.first().order) for module in modules: module_progress = course_progress.module_progresses.filter(module_id=module.id).last() diff --git a/physionet-django/user/managers.py b/physionet-django/user/managers.py index d92b0040f..46b1ecd68 100644 --- a/physionet-django/user/managers.py +++ b/physionet-django/user/managers.py @@ -1,30 +1,57 @@ -from django.db.models import DateTimeField, ExpressionWrapper, QuerySet, F, Q +from django.db.models import (DateTimeField, ExpressionWrapper, QuerySet, F, Q, + OuterRef, Subquery, Case, When) from django.utils import timezone -from user.enums import TrainingStatus - +from user.enums import TrainingStatus, RequiredField +from training.models import Course class TrainingQuerySet(QuerySet): def get_review(self): - return self.filter(status=TrainingStatus.REVIEW) + return self.filter( + Q(status=TrainingStatus.REVIEW), + Q(training_type__required_field=RequiredField.DOCUMENT) + | Q(training_type__required_field=RequiredField.URL) + ) + + # adding a query to fetch the on-platform courses that are in the status REVIEW. + def in_progress(self): + return self.filter( + Q(status=TrainingStatus.REVIEW), + Q(training_type__required_field=RequiredField.PLATFORM) + ) def get_valid(self): + return self.filter( Q(status=TrainingStatus.ACCEPTED), Q(training_type__valid_duration__isnull=True) - | Q(process_datetime__gte=timezone.now() - F('training_type__valid_duration')), + | Q(process_datetime__gte=timezone.now() - Case( + When(training_type__required_field=RequiredField.PLATFORM, then=F('course__valid_duration')), + default=F('training_type__valid_duration') + )), ).annotate( valid_datetime=ExpressionWrapper( - F('process_datetime') + F('training_type__valid_duration'), output_field=DateTimeField() + F('process_datetime') + Case( + When(training_type__required_field=RequiredField.PLATFORM, then=F('course__valid_duration')), + default=F('training_type__valid_duration') + ), output_field=DateTimeField() ) ) def get_expired(self): + return self.filter( - status=TrainingStatus.ACCEPTED, process_datetime__lt=timezone.now() - F('training_type__valid_duration') + Q(status=TrainingStatus.ACCEPTED), + Q(process_datetime__lt=timezone.now() - Case( + When(training_type__required_field=RequiredField.PLATFORM, then=F('course__valid_duration')), + default=F('training_type__valid_duration') + )), ).annotate( valid_datetime=ExpressionWrapper( - F('process_datetime') + F('training_type__valid_duration'), output_field=DateTimeField() + F('process_datetime') + Case( + When(training_type__required_field=RequiredField.PLATFORM, then=F('course__valid_duration')), + default=F('training_type__valid_duration') + ), output_field=DateTimeField() ) ) diff --git a/physionet-django/user/views.py b/physionet-django/user/views.py index 28361a6d2..607457f93 100644 --- a/physionet-django/user/views.py +++ b/physionet-django/user/views.py @@ -824,6 +824,7 @@ def edit_certification(request): ) training_by_status = { "under review": training.get_review(), + "in progress": training.in_progress(), "active": training.get_valid(), "expired": training.get_expired(), "rejected": training.get_rejected(),