Files
edx-platform/lms/djangoapps/verify_student/services.py
2016-10-05 17:22:35 -04:00

171 lines
5.9 KiB
Python

"""
Implementation of "reverification" service to communicate with Reverification XBlock
"""
import logging
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db import IntegrityError
from opaque_keys.edx.keys import CourseKey
from student.models import User, CourseEnrollment
from lms.djangoapps.verify_student.models import VerificationCheckpoint, VerificationStatus, SkippedReverification
from .models import SoftwareSecurePhotoVerification
log = logging.getLogger(__name__)
class VerificationService(object):
"""
Learner verification XBlock service
"""
def get_status(self, user_id):
"""
Returns the user's current photo verification status.
Args:
user_id: the user's id
Returns: one of the following strings
'none' - no such verification exists
'expired' - verification has expired
'approved' - verification has been approved
'pending' - verification process is still ongoing
'must_reverify' - verification has been denied and user must resubmit photos
"""
user = User.objects.get(id=user_id)
# TODO: provide a photo verification abstraction so that this
# isn't hard-coded to use Software Secure.
return SoftwareSecurePhotoVerification.user_status(user)
def reverify_url(self):
"""
Returns the URL for a user to verify themselves.
"""
return reverse('verify_student_reverify')
class ReverificationService(object):
"""
Reverification XBlock service
"""
SKIPPED_STATUS = "skipped"
NON_VERIFIED_TRACK = "not-verified"
def get_status(self, user_id, course_id, related_assessment_location):
"""Get verification attempt status against a user for a given
'checkpoint' and 'course_id'.
Args:
user_id (str): User Id string
course_id (str): A string of course id
related_assessment_location (str): Location of Reverification XBlock
Returns: str or None
"""
user = User.objects.get(id=user_id)
course_key = CourseKey.from_string(course_id)
if not CourseEnrollment.is_enrolled_as_verified(user, course_key):
return self.NON_VERIFIED_TRACK
elif SkippedReverification.check_user_skipped_reverification_exists(user_id, course_key):
return self.SKIPPED_STATUS
try:
checkpoint_status = VerificationStatus.objects.filter(
user_id=user_id,
checkpoint__course_id=course_key,
checkpoint__checkpoint_location=related_assessment_location
).latest()
return checkpoint_status.status
except ObjectDoesNotExist:
return None
def start_verification(self, course_id, related_assessment_location):
"""Create re-verification link against a verification checkpoint.
Args:
course_id(str): A string of course id
related_assessment_location(str): Location of Reverification XBlock
Returns:
Re-verification link
"""
course_key = CourseKey.from_string(course_id)
# Get-or-create the verification checkpoint
VerificationCheckpoint.get_or_create_verification_checkpoint(course_key, related_assessment_location)
re_verification_link = reverse(
'verify_student_incourse_reverify',
args=(
unicode(course_key),
unicode(related_assessment_location)
)
)
return re_verification_link
def skip_verification(self, user_id, course_id, related_assessment_location):
"""Add skipped verification attempt entry for a user against a given
'checkpoint'.
Args:
user_id(str): User Id string
course_id(str): A string of course_id
related_assessment_location(str): Location of Reverification XBlock
Returns:
None
"""
course_key = CourseKey.from_string(course_id)
checkpoint = VerificationCheckpoint.objects.get(
course_id=course_key,
checkpoint_location=related_assessment_location
)
user = User.objects.get(id=user_id)
# user can skip a reverification attempt only if that user has not already
# skipped an attempt
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))
return
try:
# Avoid circular import
from openedx.core.djangoapps.credit.api import set_credit_requirement_status
# As a user skips the reverification it declines to fulfill the requirement so
# requirement sets to declined.
set_credit_requirement_status(
user,
course_key,
'reverification',
checkpoint.checkpoint_location,
status='declined'
)
except Exception as err: # pylint: disable=broad-except
log.error("Unable to add credit requirement status for user with id %d: %s", user_id, err)
def get_attempts(self, user_id, course_id, related_assessment_location):
"""Get re-verification attempts against a user for a given 'checkpoint'
and 'course_id'.
Args:
user_id(str): User Id string
course_id(str): A string of course id
related_assessment_location(str): Location of Reverification XBlock
Returns:
Number of re-verification attempts of a user
"""
course_key = CourseKey.from_string(course_id)
return VerificationStatus.get_user_attempts(user_id, course_key, related_assessment_location)