diff --git a/lms/djangoapps/verify_student/models.py b/lms/djangoapps/verify_student/models.py index 41604a1b09..e7f7137e72 100644 --- a/lms/djangoapps/verify_student/models.py +++ b/lms/djangoapps/verify_student/models.py @@ -1077,3 +1077,28 @@ class SkippedReverification(models.Model): class Meta: # pylint: disable=missing-docstring, old-style-class unique_together = (('user', 'course_id'),) + + @classmethod + def add_skipped_reverification_attempt(cls, checkpoint, user_id, course_id): + """ Create skipped reverification object + + Arguments: + checkpoint(VerificationCheckpoint): VerificationCheckpoint object + user_id(str): User Id of currently logged in user + course_id(CourseKey): CourseKey + Returns: + None + """ + cls.objects.create(checkpoint=checkpoint, user_id=user_id, course_id=course_id) + + @classmethod + def check_user_skipped_reverification_exists(cls, user, course_id): + """Check user skipped re-verification attempt exists against specific course + + Arguments: + user(User): user object + course_id(CourseKey): CourseKey + Returns: + Boolean + """ + return cls.objects.filter(user=user, course_id=course_id).exists() diff --git a/lms/djangoapps/verify_student/services.py b/lms/djangoapps/verify_student/services.py index 83c2a641da..8d3c1d73fc 100644 --- a/lms/djangoapps/verify_student/services.py +++ b/lms/djangoapps/verify_student/services.py @@ -2,10 +2,14 @@ Implement the Reverification XBlock "reverification" server """ +import logging from opaque_keys.edx.keys import CourseKey from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse -from verify_student.models import VerificationCheckpoint, VerificationStatus +from verify_student.models import VerificationCheckpoint, VerificationStatus, SkippedReverification +from django.db import IntegrityError + +log = logging.getLogger(__name__) class ReverificationService(object): @@ -14,7 +18,7 @@ class ReverificationService(object): """ def get_status(self, user_id, course_id, related_assessment): - """ Check if the user has any verification attempt for this checkpoint and course_id + """ Check if the user has any verification attempt or has skipped the verification Args: user_id(str): User Id string @@ -22,9 +26,13 @@ class ReverificationService(object): related_assessment(str): Verification checkpoint name Returns: - Verification Status string if any attempt submitted by user else None + "skipped" if has skip the re-verification or Verification Status string if + any attempt submitted by user else None """ course_key = CourseKey.from_string(course_id) + has_skipped = SkippedReverification.check_user_skipped_reverification_exists(user_id, course_key) + if has_skipped: + return "skipped" try: checkpoint_status = VerificationStatus.objects.filter( user_id=user_id, @@ -56,3 +64,23 @@ class ReverificationService(object): ) ) return re_verification_link + + def skip_verification(self, checkpoint_name, user_id, course_id): + """Create the add verification attempt + + Args: + course_id(str): A string of course_id + user_id(str): User Id string + checkpoint_name(str): Verification checkpoint name + + Returns: + None + """ + course_key = CourseKey.from_string(course_id) + checkpoint = VerificationCheckpoint.objects.get(course_id=course_key, checkpoint_name=checkpoint_name) + + # if user do not already skipped the attempt for this course only then he can skip + try: + SkippedReverification.add_skipped_reverification_attempt(checkpoint, user_id, course_key) + except IntegrityError: + log.exception("Skipped attempt already exists for user %s: with course %s:", user_id, unicode(course_id)) diff --git a/lms/djangoapps/verify_student/tests/test_models.py b/lms/djangoapps/verify_student/tests/test_models.py index 4348f367fd..795f66ce4c 100644 --- a/lms/djangoapps/verify_student/tests/test_models.py +++ b/lms/djangoapps/verify_student/tests/test_models.py @@ -18,7 +18,8 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from verify_student.models import ( - SoftwareSecurePhotoVerification, VerificationException, VerificationCheckpoint, VerificationStatus + SoftwareSecurePhotoVerification, VerificationException, VerificationCheckpoint, VerificationStatus, + SkippedReverification ) FAKE_SETTINGS = { @@ -709,3 +710,71 @@ class VerificationStatusTest(ModuleStoreTestCase): self.assertEqual(len(result), len([self.check_point1.checkpoint_name, self.check_point2.checkpoint_name])) self.assertEqual(result[0].checkpoint.checkpoint_name, self.check_point1.checkpoint_name) self.assertEqual(result[1].checkpoint.checkpoint_name, self.check_point2.checkpoint_name) + + +class SkippedReverificationTest(ModuleStoreTestCase): + """Tests for the SkippedReverification model. """ + + def setUp(self): + super(SkippedReverificationTest, self).setUp() + self.user = UserFactory.create() + self.course = CourseFactory.create() + self.checkpoint = VerificationCheckpoint.objects.create(course_id=self.course.id, checkpoint_name="midterm") + + def test_add_skipped_attempts(self): + """adding skipped re-verification object using class method.""" + + # adding verification status + SkippedReverification.add_skipped_reverification_attempt( + checkpoint=self.checkpoint, user_id=self.user.id, course_id=unicode(self.course.id) + ) + + # getting the status from db + result = SkippedReverification.objects.filter(course_id=self.course.id)[0] + self.assertEqual(result.checkpoint, self.checkpoint) + self.assertEqual(result.user, self.user) + self.assertEqual(result.course_id, self.course.id) + + def test_unique_constraint(self): + """adding skipped re-verification with same user and course id will + raise integrity exception + """ + + # adding verification object + SkippedReverification.add_skipped_reverification_attempt( + checkpoint=self.checkpoint, user_id=self.user.id, course_id=unicode(self.course.id) + ) + + with self.assertRaises(IntegrityError): + SkippedReverification.add_skipped_reverification_attempt( + checkpoint=self.checkpoint, user_id=self.user.id, course_id=unicode(self.course.id) + ) + + # Create skipped attempt for different user + user2 = UserFactory.create() + SkippedReverification.add_skipped_reverification_attempt( + checkpoint=self.checkpoint, user_id=user2.id, course_id=unicode(self.course.id) + ) + + # getting the status from db + result = SkippedReverification.objects.filter(user=user2)[0] + self.assertEqual(result.checkpoint, self.checkpoint) + self.assertEqual(result.user, user2) + self.assertEqual(result.course_id, self.course.id) + + def test_check_user_skipped_reverification_exists(self): + """Checking check_user_skipped_reverification_exists method returns boolean status""" + + # adding verification status + SkippedReverification.add_skipped_reverification_attempt( + checkpoint=self.checkpoint, user_id=self.user.id, course_id=unicode(self.course.id) + ) + + self.assertTrue( + SkippedReverification.check_user_skipped_reverification_exists(course_id=self.course.id, user=self.user) + ) + + user2 = UserFactory.create() + self.assertFalse( + SkippedReverification.check_user_skipped_reverification_exists(course_id=self.course.id, user=user2) + ) diff --git a/lms/djangoapps/verify_student/tests/test_services.py b/lms/djangoapps/verify_student/tests/test_services.py index 5af5b3006e..29dd4f069f 100644 --- a/lms/djangoapps/verify_student/tests/test_services.py +++ b/lms/djangoapps/verify_student/tests/test_services.py @@ -8,7 +8,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from student.tests.factories import UserFactory from course_modes.tests.factories import CourseModeFactory from verify_student.services import ReverificationService -from verify_student.models import VerificationCheckpoint, VerificationStatus +from verify_student.models import VerificationCheckpoint, VerificationStatus, SkippedReverification @ddt.ddt @@ -62,3 +62,21 @@ class TestReverifyService(ModuleStoreTestCase): VerificationStatus.objects.create(checkpoint=checkpoint_obj, user=self.user, status='submitted') self.assertEqual(rev.get_status(self.user.id, unicode(self.course_key), checkpoint_name), 'submitted') + + def test_skip_verification(self): + """ Adding the test skip verification attempt for the user """ + + checkpoint_name = 'final_term' + rev = ReverificationService() + + VerificationCheckpoint.objects.create( + course_id=unicode(self.course_key), checkpoint_name=checkpoint_name + ) + + rev.skip_verification(checkpoint_name, self.user.id, unicode(self.course_key)) + + self.assertEqual(1, SkippedReverification.objects.filter(user=self.user, course_id=self.course_key).count()) + + rev.skip_verification(checkpoint_name, self.user.id, unicode(self.course_key)) + + self.assertEqual(1, SkippedReverification.objects.filter(user=self.user, course_id=self.course_key).count())