Repository: apluslms/a-plus

Issue:
Refactor enrollment checks to use the uniqueness constraint
After the PR https://github.com/apluslms/a-plus/pull/599, enrollments are guaranteed to be unique in a course instance. Therefore, it is not necessary to assume that there could be multiple enrollments in this way: `enrollment = Enrollment.objects.filter(course_instance=course_instance, user_profile=user.userprofile).first()`,
https://github.com/apluslms/a-plus/blob/d34f94b7c9a8e4d22cd28d08968b36787bb344c4/external_services/lti.py#L96
Lines like that could be refactored if there is a cleaner way. In lti.py, the QuerySet method `get` could be used with exception handling if the enrollment does not exist.
Refactor enrollment checks to use the uniqueness constraint
After the PR https://github.com/apluslms/a-plus/pull/599, enrollments are guaranteed to be unique in a course instance. Therefore, it is not necessary to assume that there could be multiple enrollments in this way: `enrollment = Enrollment.objects.filter(course_instance=course_instance, user_profile=user.userprofile).first()`,
https://github.com/apluslms/a-plus/blob/d34f94b7c9a8e4d22cd28d08968b36787bb344c4/external_services/lti.py#L96
Lines like that could be refactored if there is a cleaner way. In lti.py, the QuerySet method `get` could be used with exception handling if the enrollment does not exist.


Discussion:

Resolving patch:
diff --git a/course/models.py b/course/models.py
--- a/course/models.py
+++ b/course/models.py
@@ -539,7 +539,10 @@ def tag_user(self, user, tag):
         UserTagging.objects.create(tag=tag, user=user.userprofile, course_instance=self)
 
     def get_enrollment_for(self, user):
-        return Enrollment.objects.filter(course_instance=self, user_profile=user.userprofile).first()
+        try:
+            return Enrollment.objects.get(course_instance=self, user_profile=user.userprofile)
+        except Enrollment.DoesNotExist:
+            return None
 
     def get_user_tags(self, user):
         return self.taggings.filter(user=user.uesrprofile).select_related('tag')
diff --git a/external_services/lti.py b/external_services/lti.py
--- a/external_services/lti.py
+++ b/external_services/lti.py
@@ -2,8 +2,8 @@
 from urllib.parse import urlsplit, urljoin
 
 from django.conf import settings
-from django.core.exceptions import PermissionDenied
-from django.utils.translation import get_language
+from django.http import Http404
+from django.utils.translation import get_language, ugettext_lazy as _
 from rest_framework.reverse import reverse
 from rest_framework.settings import api_settings
 from oauthlib.common import urldecode
@@ -93,9 +93,10 @@ def __init__(self, service, user, instance, request, title, context_id=None, lin
     def user_info(self, course_instance, user):
         if self.service.is_anonymous:
             # Anonymize user information
-            enrollment = Enrollment.objects.filter(course_instance=course_instance, user_profile=user.userprofile).first()
-            if not enrollment:
-                raise PermissionDenied()
+            try:
+                enrollment = Enrollment.objects.get(course_instance=course_instance, user_profile=user.userprofile)
+            except Enrollment.DoesNotExist:
+                raise Http404(_("Course enrollment required for accessing the LTI service."))
             # Creates anon name and id for pre-pseudonymisation Enrollments
             if not (enrollment.anon_name or enrollment.anon_id):
                 # the model's post_save functions take care of the creation


Test patch: