Commit 803bc553 by zubair-arbi

use reverification xblock location as an identifier of reverification checkpoint

ECOM-1612
parent de3cccdb
...@@ -23,9 +23,9 @@ class VerificationStatusAdmin(admin.ModelAdmin): ...@@ -23,9 +23,9 @@ class VerificationStatusAdmin(admin.ModelAdmin):
""" """
Admin for the VerificationStatus table. Admin for the VerificationStatus table.
""" """
list_display = ('timestamp', 'user', 'status', 'checkpoint', 'location_id') list_display = ('timestamp', 'user', 'status', 'checkpoint')
readonly_fields = () readonly_fields = ()
search_fields = ('checkpoint', 'user') search_fields = ('checkpoint__checkpoint_location', 'user__username')
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
"""When editing an existing record, all fields should be read-only. """When editing an existing record, all fields should be read-only.
...@@ -36,7 +36,7 @@ class VerificationStatusAdmin(admin.ModelAdmin): ...@@ -36,7 +36,7 @@ class VerificationStatusAdmin(admin.ModelAdmin):
""" """
if obj: if obj:
return self.readonly_fields + ('status', 'checkpoint', 'user', 'location_id', 'response', 'error') return self.readonly_fields + ('status', 'checkpoint', 'user', 'response', 'error')
return self.readonly_fields return self.readonly_fields
def has_delete_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None):
...@@ -48,7 +48,7 @@ class SkippedReverificationAdmin(admin.ModelAdmin): ...@@ -48,7 +48,7 @@ class SkippedReverificationAdmin(admin.ModelAdmin):
"""Admin for the SkippedReverification table. """ """Admin for the SkippedReverification table. """
list_display = ('created_at', 'user', 'course_id', 'checkpoint') list_display = ('created_at', 'user', 'course_id', 'checkpoint')
readonly_fields = ('user', 'course_id') readonly_fields = ('user', 'course_id')
search_fields = ('user', 'course_id', 'checkpoint') search_fields = ('user__username', 'course_id', 'checkpoint__checkpoint_location')
def has_add_permission(self, request): def has_add_permission(self, request):
"""Skipped verifications can't be created in Django admin. """ """Skipped verifications can't be created in Django admin. """
......
...@@ -9,6 +9,7 @@ from django.core.urlresolvers import reverse ...@@ -9,6 +9,7 @@ from django.core.urlresolvers import reverse
from django.db import IntegrityError from django.db import IntegrityError
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
from verify_student.models import VerificationCheckpoint, VerificationStatus, SkippedReverification from verify_student.models import VerificationCheckpoint, VerificationStatus, SkippedReverification
...@@ -20,19 +21,19 @@ class ReverificationService(object): ...@@ -20,19 +21,19 @@ class ReverificationService(object):
Reverification XBlock service Reverification XBlock service
""" """
def get_status(self, user_id, course_id, related_assessment): def get_status(self, user_id, course_id, related_assessment_location):
""" """Get verification attempt status against a user for a given
Get verification attempt status against a user for a given 'checkpoint' 'checkpoint' and 'course_id'.
and 'course_id'.
Args: Args:
user_id(str): User Id string user_id(str): User Id string
course_id(str): A string of course id course_id(str): A string of course id
related_assessment(str): Verification checkpoint name related_assessment_location(str): Location of Reverification XBlock
Returns: Returns:
"skipped" if has skip the re-verification or Verification Status string if "skipped" if the user has skipped the re-verification or
any attempt submitted by user else None Verification Status string if the user has submitted photo
verification attempt else None
""" """
course_key = CourseKey.from_string(course_id) course_key = CourseKey.from_string(course_id)
has_skipped = SkippedReverification.check_user_skipped_reverification_exists(user_id, course_key) has_skipped = SkippedReverification.check_user_skipped_reverification_exists(user_id, course_key)
...@@ -42,69 +43,73 @@ class ReverificationService(object): ...@@ -42,69 +43,73 @@ class ReverificationService(object):
checkpoint_status = VerificationStatus.objects.filter( checkpoint_status = VerificationStatus.objects.filter(
user_id=user_id, user_id=user_id,
checkpoint__course_id=course_key, checkpoint__course_id=course_key,
checkpoint__checkpoint_name=related_assessment checkpoint__checkpoint_location=related_assessment_location
).latest() ).latest()
return checkpoint_status.status return checkpoint_status.status
except ObjectDoesNotExist: except ObjectDoesNotExist:
return None return None
def start_verification(self, course_id, related_assessment, item_id): def start_verification(self, course_id, related_assessment_location):
""" """Create re-verification link against a verification checkpoint.
Create re-verification link against a verification checkpoint.
Args: Args:
course_id(str): A string of course id course_id(str): A string of course id
related_assessment(str): Verification checkpoint name related_assessment_location(str): Location of Reverification XBlock
Returns: Returns:
Re-verification link Re-verification link
""" """
course_key = CourseKey.from_string(course_id) course_key = CourseKey.from_string(course_id)
VerificationCheckpoint.objects.get_or_create(course_id=course_key, checkpoint_name=related_assessment) VerificationCheckpoint.objects.get_or_create(
course_id=course_key,
checkpoint_location=related_assessment_location
)
re_verification_link = reverse( re_verification_link = reverse(
'verify_student_incourse_reverify', 'verify_student_incourse_reverify',
args=( args=(
unicode(course_key), unicode(course_key),
unicode(related_assessment), unicode(related_assessment_location)
unicode(item_id)
) )
) )
return re_verification_link return re_verification_link
def skip_verification(self, checkpoint_name, user_id, course_id): def skip_verification(self, user_id, course_id, related_assessment_location):
""" """Add skipped verification attempt entry for a user against a given
Add skipped verification attempt entry against a given 'checkpoint' 'checkpoint'.
Args: Args:
checkpoint_name(str): Verification checkpoint name
user_id(str): User Id string user_id(str): User Id string
course_id(str): A string of course_id course_id(str): A string of course_id
related_assessment_location(str): Location of Reverification XBlock
Returns: Returns:
None None
""" """
course_key = CourseKey.from_string(course_id) course_key = CourseKey.from_string(course_id)
checkpoint = VerificationCheckpoint.objects.get(course_id=course_key, checkpoint_name=checkpoint_name) checkpoint = VerificationCheckpoint.objects.get(
course_id=course_key,
checkpoint_location=related_assessment_location
)
# if user do not already skipped the attempt for this course only then he can skip # user can skip a reverification attempt only if that user has not already
# skipped an attempt
try: try:
SkippedReverification.add_skipped_reverification_attempt(checkpoint, user_id, course_key) SkippedReverification.add_skipped_reverification_attempt(checkpoint, user_id, course_key)
except IntegrityError: except IntegrityError:
log.exception("Skipped attempt already exists for user %s: with course %s:", user_id, unicode(course_id)) log.exception("Skipped attempt already exists for user %s: with course %s:", user_id, unicode(course_id))
def get_attempts(self, user_id, course_id, related_assessment, location_id): def get_attempts(self, user_id, course_id, related_assessment_location):
""" """Get re-verification attempts against a user for a given 'checkpoint'
Get re-verification attempts against a user for a given 'checkpoint'
and 'course_id'. and 'course_id'.
Args: Args:
user_id(str): User Id string user_id(str): User Id string
course_id(str): A string of course id course_id(str): A string of course id
related_assessment(str): Verification checkpoint name related_assessment_location(str): Location of Reverification XBlock
location_id(str): Location of Reverification XBlock in courseware
Returns: Returns:
Number of re-verification attempts of a user Number of re-verification attempts of a user
""" """
course_key = CourseKey.from_string(course_id) course_key = CourseKey.from_string(course_id)
return VerificationStatus.get_user_attempts(user_id, course_key, related_assessment, location_id) return VerificationStatus.get_user_attempts(user_id, course_key, related_assessment_location)
...@@ -31,89 +31,101 @@ class TestReverificationService(ModuleStoreTestCase): ...@@ -31,89 +31,101 @@ class TestReverificationService(ModuleStoreTestCase):
min_price=100, min_price=100,
) )
self.item = ItemFactory.create(parent=course, category='chapter', display_name='Test Section') self.item = ItemFactory.create(parent=course, category='chapter', display_name='Test Section')
self.final_checkpoint_location = u'i4x://{org}/{course}/edx-reverification-block/final_uuid'.format(
org=self.course_key.org, course=self.course_key.course
)
@ddt.data("final_term", "mid_term") @ddt.data('final', 'midterm')
def test_start_verification(self, checkpoint_name): def test_start_verification(self, checkpoint_name):
""" """Test the 'start_verification' service method.
Test the 'start_verification' service method. If checkpoint exists for
a specific course then return the checkpoint otherwise create that Check that if a reverification checkpoint exists for a specific course
checkpoint. then 'start_verification' method returns that checkpoint otherwise it
creates that checkpoint.
""" """
reverification_service = ReverificationService() reverification_service = ReverificationService()
reverification_service.start_verification(unicode(self.course_key), checkpoint_name, self.item.location) checkpoint_location = u'i4x://{org}/{course}/edx-reverification-block/{checkpoint}'.format(
org=self.course_key.org, course=self.course_key.course, checkpoint=checkpoint_name
)
expected_url = ( expected_url = (
'/verify_student/reverify' '/verify_student/reverify'
'/{course_key}' '/{course_key}'
'/{checkpoint_name}' '/{checkpoint_location}/'
'/{usage_id}/' ).format(course_key=unicode(self.course_key), checkpoint_location=checkpoint_location)
).format(course_key=unicode(self.course_key), checkpoint_name=checkpoint_name, usage_id=self.item.location)
self.assertEqual( self.assertEqual(
expected_url, reverification_service.start_verification(unicode(self.course_key), checkpoint_location),
reverification_service.start_verification(unicode(self.course_key), checkpoint_name, self.item.location) expected_url
) )
def test_get_status(self): def test_get_status(self):
"""Test the verification statuses of a user for a given 'checkpoint'
and 'course_id'.
""" """
Test the verification statuses of a user for a given 'checkpoint' and
'course_id'.
"""
checkpoint_name = 'final_term'
reverification_service = ReverificationService() reverification_service = ReverificationService()
self.assertIsNone(reverification_service.get_status(self.user.id, unicode(self.course_key), checkpoint_name)) self.assertIsNone(
reverification_service.get_status(self.user.id, unicode(self.course_key), self.final_checkpoint_location)
)
checkpoint_obj = VerificationCheckpoint.objects.create( checkpoint_obj = VerificationCheckpoint.objects.create(
course_id=unicode(self.course_key), course_id=unicode(self.course_key),
checkpoint_name=checkpoint_name checkpoint_location=self.final_checkpoint_location
) )
VerificationStatus.objects.create(checkpoint=checkpoint_obj, user=self.user, status='submitted') VerificationStatus.objects.create(checkpoint=checkpoint_obj, user=self.user, status='submitted')
self.assertEqual( self.assertEqual(
reverification_service.get_status(self.user.id, unicode(self.course_key), checkpoint_name), reverification_service.get_status(self.user.id, unicode(self.course_key), self.final_checkpoint_location),
'submitted' 'submitted'
) )
VerificationStatus.objects.create(checkpoint=checkpoint_obj, user=self.user, status='submitted') VerificationStatus.objects.create(checkpoint=checkpoint_obj, user=self.user, status='approved')
self.assertEqual( self.assertEqual(
reverification_service.get_status(self.user.id, unicode(self.course_key), checkpoint_name), reverification_service.get_status(self.user.id, unicode(self.course_key), self.final_checkpoint_location),
'submitted' 'approved'
) )
def test_skip_verification(self): def test_skip_verification(self):
""" """
Adding the test skip verification attempt for the user Test adding skip attempt of a user for a reverification checkpoint.
""" """
checkpoint_name = 'final_term'
reverification_service = ReverificationService() reverification_service = ReverificationService()
VerificationCheckpoint.objects.create( VerificationCheckpoint.objects.create(
course_id=unicode(self.course_key), course_id=unicode(self.course_key),
checkpoint_name=checkpoint_name checkpoint_location=self.final_checkpoint_location
) )
reverification_service.skip_verification(checkpoint_name, self.user.id, unicode(self.course_key)) reverification_service.skip_verification(self.user.id, unicode(self.course_key), self.final_checkpoint_location)
self.assertEqual(1, SkippedReverification.objects.filter(user=self.user, course_id=self.course_key).count()) self.assertEqual(
SkippedReverification.objects.filter(user=self.user, course_id=self.course_key).count(),
1
)
reverification_service.skip_verification(checkpoint_name, self.user.id, unicode(self.course_key)) # now test that a user can have only one entry for a skipped
self.assertEqual(1, SkippedReverification.objects.filter(user=self.user, course_id=self.course_key).count()) # reverification for a course
reverification_service.skip_verification(self.user.id, unicode(self.course_key), self.final_checkpoint_location)
self.assertEqual(
SkippedReverification.objects.filter(user=self.user, course_id=self.course_key).count(),
1
)
def test_get_attempts(self): def test_get_attempts(self):
""" """Check verification attempts count against a user for a given
Check verification attempts count against a user for a given
'checkpoint' and 'course_id'. 'checkpoint' and 'course_id'.
""" """
checkpoint_name = 'final_term'
reverification_service = ReverificationService() reverification_service = ReverificationService()
course_id = unicode(self.course_key) course_id = unicode(self.course_key)
self.assertEqual( self.assertEqual(
reverification_service.get_attempts(self.user.id, course_id, checkpoint_name, location_id=None), reverification_service.get_attempts(self.user.id, course_id, self.final_checkpoint_location),
0 0
) )
# now create a checkpoint and add user's entry against it then test # now create a checkpoint and add user's entry against it then test
# that the 'get_attempts' service method returns count accordingly # that the 'get_attempts' service method returns correct count
checkpoint_obj = VerificationCheckpoint.objects.create(course_id=course_id, checkpoint_name=checkpoint_name) checkpoint_obj = VerificationCheckpoint.objects.create(
course_id=course_id,
checkpoint_location=self.final_checkpoint_location
)
VerificationStatus.objects.create(checkpoint=checkpoint_obj, user=self.user, status='submitted') VerificationStatus.objects.create(checkpoint=checkpoint_obj, user=self.user, status='submitted')
self.assertEqual( self.assertEqual(
reverification_service.get_attempts(self.user.id, course_id, checkpoint_name, location_id=None), reverification_service.get_attempts(self.user.id, course_id, self.final_checkpoint_location),
1 1
) )
...@@ -116,9 +116,8 @@ urlpatterns = patterns( ...@@ -116,9 +116,8 @@ urlpatterns = patterns(
# Users are sent to this end-point from within courseware # Users are sent to this end-point from within courseware
# to re-verify their identities by re-submitting face photos. # to re-verify their identities by re-submitting face photos.
url( url(
r'^reverify/{course_id}/{checkpoint}/{usage_id}/$'.format( r'^reverify/{course_id}/{usage_id}/$'.format(
course_id=settings.COURSE_ID_PATTERN, course_id=settings.COURSE_ID_PATTERN,
checkpoint=settings.CHECKPOINT_PATTERN,
usage_id=settings.USAGE_ID_PATTERN usage_id=settings.USAGE_ID_PATTERN
), ),
views.InCourseReverifyView.as_view(), views.InCourseReverifyView.as_view(),
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
return new edx.verify_student.InCourseReverifyView({ return new edx.verify_student.InCourseReverifyView({
courseKey: el.data('course-key'), courseKey: el.data('course-key'),
checkpointName: el.data('checkpoint-name'),
platformName: el.data('platform-name'), platformName: el.data('platform-name'),
usageId: el.data('usage-id'), usageId: el.data('usage-id'),
errorModel: errorView.model errorModel: errorView.model
......
...@@ -16,7 +16,6 @@ var edx = edx || {}; ...@@ -16,7 +16,6 @@ var edx = edx || {};
defaults: { defaults: {
courseKey: '', courseKey: '',
checkpointName: '',
faceImage: '', faceImage: '',
usageId: '' usageId: ''
}, },
...@@ -28,9 +27,8 @@ var edx = edx || {}; ...@@ -28,9 +27,8 @@ var edx = edx || {};
face_image: model.get( 'faceImage' ) face_image: model.get( 'faceImage' )
}, },
url = _.str.sprintf( url = _.str.sprintf(
'/verify_student/reverify/%(courseKey)s/%(checkpointName)s/%(usageId)s/', { '/verify_student/reverify/%(courseKey)s/%(usageId)s/', {
courseKey: model.get('courseKey'), courseKey: model.get('courseKey'),
checkpointName: model.get('checkpointName'),
usageId: model.get('usageId') usageId: model.get('usageId')
} }
); );
......
...@@ -26,14 +26,12 @@ ...@@ -26,14 +26,12 @@
this.errorModel = obj.errorModel || null; this.errorModel = obj.errorModel || null;
this.courseKey = obj.courseKey || null; this.courseKey = obj.courseKey || null;
this.checkpointName = obj.checkpointName || null;
this.platformName = obj.platformName || null; this.platformName = obj.platformName || null;
this.usageId = obj.usageId || null; this.usageId = obj.usageId || null;
this.model = new edx.verify_student.ReverificationModel({ this.model = new edx.verify_student.ReverificationModel({
courseKey: this.courseKey, courseKey: this.courseKey,
checkpointName: this.checkpointName,
usageId: this.usageId usageId: this.usageId
}); });
...@@ -47,7 +45,6 @@ ...@@ -47,7 +45,6 @@
$( this.templateId ).html(), $( this.templateId ).html(),
{ {
courseKey: this.courseKey, courseKey: this.courseKey,
checkpointName: this.checkpointName,
platformName: this.platformName platformName: this.platformName
} }
); );
......
...@@ -43,7 +43,6 @@ from verify_student.views import PayAndVerifyView ...@@ -43,7 +43,6 @@ from verify_student.views import PayAndVerifyView
<div id="incourse-reverify-container" <div id="incourse-reverify-container"
class="incourse-reverify" class="incourse-reverify"
data-course-key='${course_key}' data-course-key='${course_key}'
data-checkpoint-name='${checkpoint_name}'
data-platform-name='${platform_name}' data-platform-name='${platform_name}'
data-usage-id='${usage_id}' data-usage-id='${usage_id}'
></div> ></div>
......
...@@ -50,7 +50,7 @@ git+https://github.com/hmarr/django-debug-toolbar-mongo.git@b0686a76f1ce3532088c ...@@ -50,7 +50,7 @@ git+https://github.com/hmarr/django-debug-toolbar-mongo.git@b0686a76f1ce3532088c
git+https://github.com/edx/edx-lint.git@8bf82a32ecb8598c415413df66f5232ab8d974e9#egg=edx_lint==0.2.1 git+https://github.com/edx/edx-lint.git@8bf82a32ecb8598c415413df66f5232ab8d974e9#egg=edx_lint==0.2.1
-e git+https://github.com/edx/xblock-utils.git@db22bc40fd2a75458a3c66d057f88aff5a7383e6#egg=xblock-utils -e git+https://github.com/edx/xblock-utils.git@db22bc40fd2a75458a3c66d057f88aff5a7383e6#egg=xblock-utils
-e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive -e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive
-e git+https://github.com/edx/edx-reverification-block.git@2ff0d21f6614874067168bd244e68d8215041f3b#egg=edx-reverification-block -e git+https://github.com/edx/edx-reverification-block.git@03da85753d5f563a22c1282c0e89fcb2e828b8c1#egg=edx-reverification-block
git+https://github.com/edx/ecommerce-api-client.git@1.0.0#egg=ecommerce-api-client==1.0.0 git+https://github.com/edx/ecommerce-api-client.git@1.0.0#egg=ecommerce-api-client==1.0.0
# Third Party XBlocks # Third Party XBlocks
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment