Commit 775ae010 by David Ormsbee

Shorted names of models in verify_student

parent 8f572e53
......@@ -4,8 +4,8 @@ Models for Student Identity Verification
This is where we put any models relating to establishing the real-life identity
of a student over a period of time. Right now, the only models are the abstract
`PhotoVerificationAttempt`, and its one concrete implementation
`SoftwareSecurePhotoVerificationAttempt`. The hope is to keep as much of the
`PhotoVerification`, and its one concrete implementation
`SoftwareSecurePhotoVerification`. The hope is to keep as much of the
photo verification process as generic as possible.
"""
from datetime import datetime
......@@ -63,14 +63,14 @@ def status_before_must_be(*valid_start_statuses):
return decorator_func
class PhotoVerificationAttempt(StatusModel):
class PhotoVerification(StatusModel):
"""
Each PhotoVerificationAttempt represents a Student's attempt to establish
Each PhotoVerification represents a Student's attempt to establish
their identity by uploading a photo of themselves and a picture ID. An
attempt actually has a number of fields that need to be filled out at
different steps of the approval process. While it's useful as a Django Model
for the querying facilities, **you should only create and edit a
`PhotoVerificationAttempt` object through the methods provided**. Do not
`PhotoVerification` object through the methods provided**. Do not
just construct one and start setting fields unless you really know what
you're doing.
......@@ -96,9 +96,9 @@ class PhotoVerificationAttempt(StatusModel):
Because this Model inherits from StatusModel, we can also do things like::
attempt.status == PhotoVerificationAttempt.STATUS.created
attempt.status == PhotoVerification.STATUS.created
attempt.status == "created"
pending_requests = PhotoVerificationAttempt.submitted.all()
pending_requests = PhotoVerification.submitted.all()
"""
######################## Fields Set During Creation ########################
# See class docstring for description of status states
......@@ -154,24 +154,33 @@ class PhotoVerificationAttempt(StatusModel):
class Meta:
abstract = True
ordering = ['-created_at']
##### Methods listed in the order you'd typically call them
@classmethod
def user_is_verified(cls, user_id):
"""Returns whether or not a user has satisfactorily proved their
def user_is_verified(cls, user):
"""
Returns whether or not a user has satisfactorily proved their
identity. Depending on the policy, this can expire after some period of
time, so a user might have to renew periodically."""
raise NotImplementedError
@classmethod
def active_for_user(cls, user_id):
"""Return all PhotoVerificationAttempts that are still active (i.e. not
def active_for_user(cls, user):
"""
Return all PhotoVerifications that are still active (i.e. not
approved or denied).
Should there only be one active at any given time for a user? Enforced
at the DB level?
"""
raise NotImplementedError
# This should only be one at the most, but just in case we create more
# by mistake, we'll grab the most recently created one.
active_attempts = cls.objects.filter(user=user, status='created')
if active_attempts:
return active_attempts[0]
else:
return None
@status_before_must_be("created")
def upload_face_image(self, img):
......@@ -315,10 +324,10 @@ class PhotoVerificationAttempt(StatusModel):
self.save()
class SoftwareSecurePhotoVerificationAttempt(PhotoVerificationAttempt):
class SoftwareSecurePhotoVerification(PhotoVerification):
"""
Model to verify identity using a service provided by Software Secure. Much
of the logic is inherited from `PhotoVerificationAttempt`, but this class
of the logic is inherited from `PhotoVerification`, but this class
encrypts the photos.
Software Secure (http://www.softwaresecure.com/) is a remote proctoring
......@@ -368,4 +377,3 @@ class SoftwareSecurePhotoVerificationAttempt(PhotoVerificationAttempt):
)
rsa_cipher = PKCS1_OAEP.new(key)
rsa_encrypted_aes_key = rsa_cipher.encrypt(aes_key)
# -*- coding: utf-8 -*-
from nose.tools import assert_in, assert_is_none, assert_equals, \
assert_raises, assert_not_equals
# -*- coding: utf-8 -*-
from nose.tools import (
assert_in, assert_is_none, assert_equals, assert_raises, assert_not_equals
)
from django.test import TestCase
from student.tests.factories import UserFactory
from verify_student.models import PhotoVerificationAttempt, VerificationException
from verify_student.models import SoftwareSecurePhotoVerification, VerificationException
class TestPhotoVerificationAttempt(object):
class TestPhotoVerification(object):
def test_state_transitions(self):
"""Make sure we can't make unexpected status transitions.
......@@ -14,12 +15,12 @@ class TestPhotoVerificationAttempt(object):
The status transitions we expect are::
created → ready → submitted → approved
↑ ↓
↑ ↓
→ denied
"""
user = UserFactory.create()
attempt = PhotoVerificationAttempt(user=user)
assert_equals(attempt.status, PhotoVerificationAttempt.STATUS.created)
attempt = SoftwareSecurePhotoVerification(user=user)
assert_equals(attempt.status, SoftwareSecurePhotoVerification.STATUS.created)
assert_equals(attempt.status, "created")
# This should fail because we don't have the necessary fields filled out
......@@ -38,7 +39,7 @@ class TestPhotoVerificationAttempt(object):
assert_equals(attempt.status, "ready")
# Once again, state transitions should fail here. We can't approve or
# deny anything until it's been placed into the submitted state -- i.e.
# deny anything until it's been placed into the submitted state -- i.e.
# the user has clicked on whatever agreements, or given payment, or done
# whatever the application requires before it agrees to process their
# attempt.
......
......@@ -25,4 +25,19 @@ urlpatterns = patterns(
views.final_verification,
name="verify_student/final_verification"
),
# The above are what we did for the design mockups, but what we're really
# looking at now is:
url(
r'^show_verification_page',
views.show_verification_page,
name="verify_student/show_verification_page"
),
url(
r'^start_or_resume_attempt',
views.start_or_resume_attempt,
name="verify_student/start_or_resume_attempt"
)
)
......@@ -4,14 +4,26 @@
"""
from mitxmako.shortcuts import render_to_response
from verify_student.models import SoftwareSecurePhotoVerification
# @login_required
def start_or_resume_attempt(request):
def start_or_resume_attempt(request, course_id):
"""
If they've already started a PhotoVerificationAttempt, we move to wherever
they are in that process. If they've completed one, then we skip straight
to payment.
"""
pass
# If the user has already been verified within the given time period,
# redirect straight to the payment -- no need to verify again.
#if SoftwareSecurePhotoVerification.user_is_verified(user):
# pass
attempt = SoftwareSecurePhotoVerification.active_for_user(request.user)
if not attempt:
# Redirect to show requirements
pass
# if attempt.
def show_requirements(request):
"""This might just be a plain template without a view."""
......@@ -29,3 +41,9 @@ def photo_id_upload(request):
def final_verification(request):
context = { "course_id" : "edX/Certs101/2013_Test" }
return render_to_response("verify_student/final_verification.html", context)
#
def show_verification_page(request):
pass
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