add location_id field for the Reverification XBlock in VerificationStatus model
ECOM-1477
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'VerificationStatus.location_id'
|
||||
db.add_column('verify_student_verificationstatus', 'location_id',
|
||||
self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'VerificationStatus.location_id'
|
||||
db.delete_column('verify_student_verificationstatus', 'location_id')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'reverification.midcoursereverificationwindow': {
|
||||
'Meta': {'object_name': 'MidcourseReverificationWindow'},
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'end_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'start_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'verify_student.incoursereverificationconfiguration': {
|
||||
'Meta': {'object_name': 'InCourseReverificationConfiguration'},
|
||||
'change_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'verify_student.skippedreverification': {
|
||||
'Meta': {'unique_together': "(('user', 'course_id'),)", 'object_name': 'SkippedReverification'},
|
||||
'checkpoint': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'skipped_checkpoint'", 'to': "orm['verify_student.VerificationCheckpoint']"}),
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'verify_student.softwaresecurephotoverification': {
|
||||
'Meta': {'ordering': "['-created_at']", 'object_name': 'SoftwareSecurePhotoVerification'},
|
||||
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
|
||||
'display': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
|
||||
'error_code': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'error_msg': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'face_image_url': ('django.db.models.fields.URLField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'photo_id_image_url': ('django.db.models.fields.URLField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'photo_id_key': ('django.db.models.fields.TextField', [], {'max_length': '1024'}),
|
||||
'receipt_id': ('django.db.models.fields.CharField', [], {'default': "'9997c000-3299-4097-a2cf-9ab35f9efdb5'", 'max_length': '255', 'db_index': 'True'}),
|
||||
'reviewing_service': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'reviewing_user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'photo_verifications_reviewed'", 'null': 'True', 'to': "orm['auth.User']"}),
|
||||
'status': ('model_utils.fields.StatusField', [], {'default': "'created'", 'max_length': '100', u'no_check_for_status': 'True'}),
|
||||
'status_changed': ('model_utils.fields.MonitorField', [], {'default': 'datetime.datetime.now', u'monitor': "u'status'"}),
|
||||
'submitted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'}),
|
||||
'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
|
||||
'window': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['reverification.MidcourseReverificationWindow']", 'null': 'True'})
|
||||
},
|
||||
'verify_student.verificationcheckpoint': {
|
||||
'Meta': {'unique_together': "(('course_id', 'checkpoint_name'),)", 'object_name': 'VerificationCheckpoint'},
|
||||
'checkpoint_name': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'photo_verification': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['verify_student.SoftwareSecurePhotoVerification']", 'symmetrical': 'False'})
|
||||
},
|
||||
'verify_student.verificationstatus': {
|
||||
'Meta': {'object_name': 'VerificationStatus'},
|
||||
'checkpoint': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'checkpoint_status'", 'to': "orm['verify_student.VerificationCheckpoint']"}),
|
||||
'error': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'location_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'response': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
|
||||
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['verify_student']
|
||||
@@ -13,33 +13,31 @@ from email.utils import formatdate
|
||||
import functools
|
||||
import json
|
||||
import logging
|
||||
import pytz
|
||||
import requests
|
||||
import uuid
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from boto.s3.connection import S3Connection
|
||||
from boto.s3.key import Key
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
import pytz
|
||||
import requests
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import ugettext as _
|
||||
from config_models.models import ConfigurationModel
|
||||
from model_utils.models import StatusModel
|
||||
from model_utils import Choices
|
||||
|
||||
from reverification.models import MidcourseReverificationWindow
|
||||
from verify_student.ssencrypt import (
|
||||
random_aes_key, encrypt_and_encode,
|
||||
generate_signed_message, rsa_encrypt
|
||||
)
|
||||
|
||||
from reverification.models import MidcourseReverificationWindow
|
||||
|
||||
from xmodule_django.models import CourseKeyField
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
from config_models.models import ConfigurationModel
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def generateUUID(): # pylint: disable=invalid-name
|
||||
@@ -1018,21 +1016,30 @@ class VerificationStatus(models.Model):
|
||||
response = models.TextField(null=True, blank=True)
|
||||
error = models.TextField(null=True, blank=True)
|
||||
|
||||
# This field is used to save location of Reverification module in courseware
|
||||
location_id = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
max_length=255,
|
||||
help_text=ugettext_lazy("Usage id of Reverification XBlock.")
|
||||
)
|
||||
|
||||
class Meta(object): # pylint: disable=missing-docstring
|
||||
get_latest_by = "timestamp"
|
||||
|
||||
@classmethod
|
||||
def add_verification_status(cls, checkpoint, user, status):
|
||||
def add_verification_status(cls, checkpoint, user, status, location_id=''):
|
||||
""" Create new verification status object
|
||||
|
||||
Arguments:
|
||||
checkpoint(VerificationCheckpoint): VerificationCheckpoint object
|
||||
user(User): user object
|
||||
status(str): String representing the status from VERIFICATION_STATUS_CHOICES
|
||||
location_id(str): Usage key of Reverification XBlock
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
cls.objects.create(checkpoint=checkpoint, user=user, status=status)
|
||||
cls.objects.create(checkpoint=checkpoint, user=user, status=status, location_id=location_id)
|
||||
|
||||
@classmethod
|
||||
def add_status_from_checkpoints(cls, checkpoints, user, status):
|
||||
@@ -1046,7 +1053,14 @@ class VerificationStatus(models.Model):
|
||||
None
|
||||
"""
|
||||
for checkpoint in checkpoints:
|
||||
cls.objects.create(checkpoint=checkpoint, user=user, status=status)
|
||||
# get 'location_id' from last entry (if it exists) and add it in
|
||||
# new entry
|
||||
try:
|
||||
location_id = cls.objects.filter(checkpoint=checkpoint).latest().location_id
|
||||
except cls.DoesNotExist:
|
||||
location_id = ''
|
||||
|
||||
cls.objects.create(checkpoint=checkpoint, user=user, status=status, location_id=location_id)
|
||||
|
||||
|
||||
class InCourseReverificationConfiguration(ConfigurationModel):
|
||||
|
||||
@@ -675,7 +675,7 @@ class VerificationCheckpointTest(ModuleStoreTestCase):
|
||||
|
||||
@ddt.ddt
|
||||
class VerificationStatusTest(ModuleStoreTestCase):
|
||||
"""Tests for the VerificationStatus model. """
|
||||
""" Tests for the VerificationStatus model. """
|
||||
|
||||
def setUp(self):
|
||||
super(VerificationStatusTest, self).setUp()
|
||||
@@ -683,33 +683,70 @@ class VerificationStatusTest(ModuleStoreTestCase):
|
||||
self.course = CourseFactory.create()
|
||||
self.check_point1 = VerificationCheckpoint.objects.create(course_id=self.course.id, checkpoint_name="midterm")
|
||||
self.check_point2 = VerificationCheckpoint.objects.create(course_id=self.course.id, checkpoint_name="final")
|
||||
self.dummy_reverification_item_id_1 = 'i4x://{}/{}/edx-reverification-block/related_assessment_1'.format(
|
||||
self.course.location.org,
|
||||
self.course.location.course
|
||||
)
|
||||
self.dummy_reverification_item_id_2 = 'i4x://{}/{}/edx-reverification-block/related_assessment_2'.format(
|
||||
self.course.location.org,
|
||||
self.course.location.course
|
||||
)
|
||||
|
||||
@ddt.data('submitted', "approved", "denied", "error")
|
||||
def test_add_verification_status(self, status):
|
||||
"""adding verfication status using the class method."""
|
||||
""" Adding verification status using the class method. """
|
||||
|
||||
# adding verification status
|
||||
VerificationStatus.add_verification_status(checkpoint=self.check_point1, user=self.user, status=status)
|
||||
VerificationStatus.add_verification_status(
|
||||
checkpoint=self.check_point1,
|
||||
user=self.user,
|
||||
status=status,
|
||||
location_id=self.dummy_reverification_item_id_1
|
||||
)
|
||||
|
||||
# getting the status from db
|
||||
result = VerificationStatus.objects.filter(checkpoint=self.check_point1)[0]
|
||||
self.assertEqual(result.status, status)
|
||||
self.assertEqual(result.user, self.user)
|
||||
|
||||
@ddt.data('submitted', "approved", "denied", "error")
|
||||
@ddt.data("approved", "denied", "error")
|
||||
def test_add_status_from_checkpoints(self, status):
|
||||
"""adding verfication status for checkpoints list."""
|
||||
""" Adding verification status for checkpoints list after submitting sspv. """
|
||||
|
||||
# adding verification status with multiple points
|
||||
# add initial verification status for checkpoints
|
||||
initial_status = "submitted"
|
||||
VerificationStatus.add_verification_status(
|
||||
checkpoint=self.check_point1,
|
||||
user=self.user,
|
||||
status=initial_status,
|
||||
location_id=self.dummy_reverification_item_id_1
|
||||
)
|
||||
VerificationStatus.add_verification_status(
|
||||
checkpoint=self.check_point2,
|
||||
user=self.user,
|
||||
status=initial_status,
|
||||
location_id=self.dummy_reverification_item_id_2
|
||||
)
|
||||
|
||||
# now add verification status for multiple checkpoint points
|
||||
VerificationStatus.add_status_from_checkpoints(
|
||||
checkpoints=[self.check_point1, self.check_point2], user=self.user, status=status
|
||||
)
|
||||
|
||||
# getting the status from db.
|
||||
result = VerificationStatus.objects.filter(user=self.user)
|
||||
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)
|
||||
# test that verification status entries with new status have been added
|
||||
# for both checkpoints and all entries have related 'location_id'.
|
||||
result = VerificationStatus.objects.filter(user=self.user, checkpoint=self.check_point1)
|
||||
self.assertEqual(len(result), len(self.check_point1.checkpoint_status.all()))
|
||||
self.assertEqual(
|
||||
list(result.values_list('location_id', flat=True)),
|
||||
list(self.check_point1.checkpoint_status.all().values_list('location_id', flat=True))
|
||||
)
|
||||
result = VerificationStatus.objects.filter(user=self.user, checkpoint=self.check_point2)
|
||||
self.assertEqual(len(result), len(self.check_point2.checkpoint_status.all()))
|
||||
self.assertEqual(
|
||||
list(result.values_list('location_id', flat=True)),
|
||||
list(self.check_point2.checkpoint_status.all().values_list('location_id', flat=True))
|
||||
)
|
||||
|
||||
|
||||
class SkippedReverificationTest(ModuleStoreTestCase):
|
||||
|
||||
@@ -1244,7 +1244,7 @@ class InCourseReverifyView(View):
|
||||
request.user, request.POST['face_image'], init_verification.photo_id_key
|
||||
)
|
||||
checkpoint.add_verification_attempt(attempt)
|
||||
VerificationStatus.add_verification_status(checkpoint, user, "submitted")
|
||||
VerificationStatus.add_verification_status(checkpoint, user, "submitted", usage_id)
|
||||
|
||||
# emit the reverification event
|
||||
self._track_reverification_events(
|
||||
|
||||
Reference in New Issue
Block a user