add location_id field for the Reverification XBlock in VerificationStatus model

ECOM-1477
This commit is contained in:
zubair-arbi
2015-04-29 16:12:03 +05:00
parent 5a1d180f14
commit da94aca522
4 changed files with 203 additions and 30 deletions

View File

@@ -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']

View File

@@ -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):

View File

@@ -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):

View File

@@ -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(