From 1f491b419041ebd093bf7b7255e4b6847880320c Mon Sep 17 00:00:00 2001 From: Simon Chen Date: Tue, 26 Feb 2019 14:13:58 -0500 Subject: [PATCH] Revert "LEARNER-6945 Populate software secure photo verification" This reverts commit 019f6c4dcf924475599e005e8de34a2de7a1d733. --- .../commands/populate_expiry_date.py | 104 --------------- .../tests/test_populate_expiry_date.py | 124 ------------------ lms/djangoapps/verify_student/models.py | 17 --- .../verify_student/tests/test_views.py | 15 --- lms/djangoapps/verify_student/views.py | 11 +- 5 files changed, 1 insertion(+), 270 deletions(-) delete mode 100644 lms/djangoapps/verify_student/management/commands/populate_expiry_date.py delete mode 100644 lms/djangoapps/verify_student/management/commands/tests/test_populate_expiry_date.py diff --git a/lms/djangoapps/verify_student/management/commands/populate_expiry_date.py b/lms/djangoapps/verify_student/management/commands/populate_expiry_date.py deleted file mode 100644 index adf6db2125..0000000000 --- a/lms/djangoapps/verify_student/management/commands/populate_expiry_date.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -Django admin command to populate expiry_date for approved verifications in SoftwareSecurePhotoVerification -""" -import logging -import time -from datetime import timedelta - -from django.conf import settings -from django.core.management.base import BaseCommand -from django.db.models import F -from util.query import use_read_replica_if_available - -from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification - -logger = logging.getLogger(__name__) - - -class Command(BaseCommand): - """ - This command sets the expiry_date for users for which the verification is approved - - The task is performed in batches with maximum number of rows to process given in argument `batch_size` - and a sleep time between each batch given by `sleep_time` - - Default values: - `batch_size` = 1000 rows - `sleep_time` = 10 seconds - - Example usage: - $ ./manage.py lms populate_expiry_date --batch_size=1000 --sleep_time=5 - OR - $ ./manage.py lms populate_expiry_date - """ - help = 'Populate expiry_date for approved verifications' - - def add_arguments(self, parser): - parser.add_argument( - '--batch_size', - action='store', - dest='batch_size', - type=int, - default=1000, - help='Maximum number of database rows to process. ' - 'This helps avoid locking the database while updating large amount of data.') - parser.add_argument( - '--sleep_time', - action='store', - dest='sleep_time', - type=int, - default=10, - help='Sleep time in seconds between update of batches') - - def handle(self, *args, **options): - """ - Handler for the command - - It filters approved Software Secure Photo Verification and then for each distinct user it finds the most - recent approved verification and set its expiry_date - """ - batch_size = options['batch_size'] - sleep_time = options['sleep_time'] - - query = SoftwareSecurePhotoVerification.objects.filter(status='approved').order_by() - sspv = use_read_replica_if_available(query) - - if not sspv.count(): - logger.info("No approved entries found in SoftwareSecurePhotoVerification") - return - - distinct_user_ids = set() - update_verification_ids = [] - update_verification_count = 0 - - for verification in sspv: - if verification.user_id not in distinct_user_ids: - distinct_user_ids.add(verification.user_id) - - recent_verification = self.find_recent_verification(sspv, verification.user_id) - if not recent_verification.expiry_date: - update_verification_ids.append(recent_verification.pk) - update_verification_count += 1 - - if update_verification_count == batch_size: - self.bulk_update(update_verification_ids) - update_verification_count = 0 - update_verification_ids = [] - time.sleep(sleep_time) - - if update_verification_ids: - self.bulk_update(update_verification_ids) - - def bulk_update(self, verification_ids): - """ - It updates the expiry_date for all the verification whose ids lie in verification_ids - """ - recent_verification_qs = SoftwareSecurePhotoVerification.objects.filter(pk__in=verification_ids) - recent_verification_qs.update(expiry_date=F('updated_at') + timedelta( - days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"])) - - def find_recent_verification(self, model, user_id): - """ - Returns the most recent approved verification for a user - """ - return model.filter(user_id=user_id).latest('updated_at') diff --git a/lms/djangoapps/verify_student/management/commands/tests/test_populate_expiry_date.py b/lms/djangoapps/verify_student/management/commands/tests/test_populate_expiry_date.py deleted file mode 100644 index 7c4f10b651..0000000000 --- a/lms/djangoapps/verify_student/management/commands/tests/test_populate_expiry_date.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -Tests for django admin command `populate_expiry_date` in the verify_student module -""" - -from datetime import timedelta - -import boto -from django.conf import settings -from django.core.management import call_command -from django.test import TestCase -from mock import patch -from student.tests.factories import UserFactory -from testfixtures import LogCapture - -from common.test.utils import MockS3Mixin -from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification -from lms.djangoapps.verify_student.tests.test_models import ( - FAKE_SETTINGS, - mock_software_secure_post -) - -LOGGER_NAME = 'lms.djangoapps.verify_student.management.commands.populate_expiry_date' - - -@patch.dict(settings.VERIFY_STUDENT, FAKE_SETTINGS) -@patch('lms.djangoapps.verify_student.models.requests.post', new=mock_software_secure_post) -class TestPopulateExpiryDate(MockS3Mixin, TestCase): - """ Tests for django admin command `populate_expiry_date` in the verify_student module """ - - def setUp(self): - """ Initial set up for tests """ - super(TestPopulateExpiryDate, self).setUp() - connection = boto.connect_s3() - connection.create_bucket(FAKE_SETTINGS['SOFTWARE_SECURE']['S3_BUCKET']) - - def create_and_submit(self, user): - """ Helper method that lets us create new SoftwareSecurePhotoVerifications """ - attempt = SoftwareSecurePhotoVerification(user=user) - attempt.upload_face_image("Fake Data") - attempt.upload_photo_id_image("More Fake Data") - attempt.mark_ready() - attempt.submit() - return attempt - - def test_expiry_date_already_present(self): - """ - Test that the expiry_date for most recent approved verification is updated only when the - expiry_date is not already present - """ - user = UserFactory.create() - verification = self.create_and_submit(user) - verification.status = 'approved' - verification.expiry_date = verification.updated_at + timedelta(days=10) - verification.save() - - expiry_date = verification.expiry_date - call_command('populate_expiry_date') - - # Check that the expiry_date for approved verification is not changed when it is already present - verification_expiry_date = SoftwareSecurePhotoVerification.objects.get(pk=verification.pk).expiry_date - - self.assertEqual(verification_expiry_date, expiry_date) - - def test_recent_approved_verification(self): - """ - Test that the expiry_date for most recent approved verification is updated - A user can have multiple approved Software Secure Photo Verification over the year - Only the most recent is considered for course verification - """ - user = UserFactory.create() - outdated_verification = self.create_and_submit(user) - outdated_verification.status = 'approved' - outdated_verification.save() - - recent_verification = self.create_and_submit(user) - recent_verification.status = 'approved' - recent_verification.save() - - call_command('populate_expiry_date') - - # Check that expiry_date for only one verification is set - assert len(SoftwareSecurePhotoVerification.objects.filter(expiry_date__isnull=False)) == 1 - - # Check that the expiry_date date set for verification is not for the outdated approved verification - expiry_date = SoftwareSecurePhotoVerification.objects.get(pk=outdated_verification.pk).expiry_date - self.assertIsNone(expiry_date) - - def test_approved_verification_expiry_date(self): - """ - Tests that the command correctly updates expiry_date - Criteria : - Verification for which status is approved and expiry_date is null - """ - # Create verification with status : submitted - user = UserFactory.create() - self.create_and_submit(user) - - # Create verification with status : approved - approved_verification = self.create_and_submit(user) - approved_verification.status = 'approved' - approved_verification.save() - - expected_date = approved_verification.updated_at + timedelta( - days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"]) - - call_command('populate_expiry_date') - - # Check to make sure we have one verification with expiry_date set and one with null - assert len(SoftwareSecurePhotoVerification.objects.filter(expiry_date__isnull=True)) == 1 - assert len(SoftwareSecurePhotoVerification.objects.filter(expiry_date__isnull=False)) == 1 - - # Confirm that expiry_date set for approved verification is correct - approved_verification = SoftwareSecurePhotoVerification.objects.get(pk=approved_verification.pk) - self.assertEqual(approved_verification.expiry_date, expected_date) - - def test_no_approved_verification_found(self): - """ - Test that if no approved verifications are found the management command terminates gracefully - """ - with LogCapture(LOGGER_NAME) as logger: - call_command('populate_expiry_date') - logger.check( - (LOGGER_NAME, 'INFO', "No approved entries found in SoftwareSecurePhotoVerification") - ) diff --git a/lms/djangoapps/verify_student/models.py b/lms/djangoapps/verify_student/models.py index 5ac659ca0a..425437a666 100644 --- a/lms/djangoapps/verify_student/models.py +++ b/lms/djangoapps/verify_student/models.py @@ -561,23 +561,6 @@ class SoftwareSecurePhotoVerification(PhotoVerification): expiry_date = models.DateTimeField(null=True, blank=True, db_index=True) expiry_email_date = models.DateTimeField(null=True, blank=True, db_index=True) - @status_before_must_be("must_retry", "submitted", "approved", "denied") - def approve(self, user_id=None, service=""): - """ - Approve the verification attempt for user - - Valid attempt statuses when calling this method: - `submitted`, `approved`, `denied` - - After method completes: - status is set to `approved` - expiry_date is set to one year from now - """ - self.expiry_date = datetime.now(pytz.UTC) + timedelta( - days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"] - ) - super(SoftwareSecurePhotoVerification, self).approve(user_id, service) - @classmethod def get_initial_verification(cls, user, earliest_allowed_date=None): """Get initial verification for a user with the 'photo_id_key'. diff --git a/lms/djangoapps/verify_student/tests/test_views.py b/lms/djangoapps/verify_student/tests/test_views.py index 0d05d5fc6c..0abd7442c3 100644 --- a/lms/djangoapps/verify_student/tests/test_views.py +++ b/lms/djangoapps/verify_student/tests/test_views.py @@ -1764,17 +1764,6 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase): """ Test for verification passed. """ - expiry_date = datetime.now(pytz.UTC) + timedelta( - days=settings.VERIFY_STUDENT["DAYS_GOOD_FOR"] - ) - verification = SoftwareSecurePhotoVerification.objects.create(user=self.user) - verification.mark_ready() - verification.submit() - verification.approve() - verification.expiry_date = datetime.now(pytz.UTC) - verification.expiry_email_date = datetime.now(pytz.UTC) - verification.save() - data = { "EdX-ID": self.receipt_id, "Result": "PASS", @@ -1789,11 +1778,7 @@ class TestPhotoVerificationResultsCallback(ModuleStoreTestCase): HTTP_DATE='testdate' ) attempt = SoftwareSecurePhotoVerification.objects.get(receipt_id=self.receipt_id) - old_verification = SoftwareSecurePhotoVerification.objects.get(pk=verification.pk) self.assertEqual(attempt.status, u'approved') - self.assertEqual(attempt.expiry_date.date(), expiry_date.date()) - self.assertIsNone(old_verification.expiry_date) - self.assertIsNone(old_verification.expiry_email_date) self.assertEquals(response.content, 'OK!') self.assertEqual(len(mail.outbox), 1) diff --git a/lms/djangoapps/verify_student/views.py b/lms/djangoapps/verify_student/views.py index 0d2a4f2f2b..db601878b1 100644 --- a/lms/djangoapps/verify_student/views.py +++ b/lms/djangoapps/verify_student/views.py @@ -1158,16 +1158,7 @@ def results_callback(request): 'platform_name': settings.PLATFORM_NAME, } if result == "PASS": - # If this verification is not an outdated version then make expiry date of previous approved verification NULL - # Setting expiry date to NULL is important so that it does not get filtered in the management command - # that sends email when verification expires : verify_student/send_verification_expiry_email - if attempt.status != 'approved': - log.info(u'Making expiry date of previous approved verification NULL for {}'.format(attempt.user_id)) - verification = SoftwareSecurePhotoVerification.objects.filter(status='approved', - user_id=attempt.user_id).latest('updated_at') - SoftwareSecurePhotoVerification.objects.filter(pk=verification.pk).update(expiry_date=None, - expiry_email_date=None) - log.debug(u'Approving verification for {}'.format(receipt_id)) + log.debug(u"Approving verification for %s", receipt_id) attempt.approve() status = u"approved" expiry_date = datetime.date.today() + datetime.timedelta(