basic flow from enroll mode selection to verify screen

This commit is contained in:
David Ormsbee
2013-08-22 13:56:23 -04:00
parent 1676fc31a5
commit 0dd5819683
10 changed files with 130 additions and 38 deletions

View File

@@ -8,7 +8,7 @@ of a student over a period of time. Right now, the only models are the abstract
`SoftwareSecurePhotoVerification`. The hope is to keep as much of the
photo verification process as generic as possible.
"""
from datetime import datetime
from datetime import datetime, timedelta
from hashlib import md5
import base64
import functools
@@ -17,6 +17,7 @@ import uuid
import pytz
from django.conf import settings
from django.db import models
from django.contrib.auth.models import User
from model_utils.models import StatusModel
@@ -69,10 +70,10 @@ class PhotoVerification(StatusModel):
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
`PhotoVerification` object through the methods provided**. Do not
just construct one and start setting fields unless you really know what
you're doing.
for the querying facilities, **you should only edit a `PhotoVerification`
object through the methods provided**. Initialize them with a user:
attempt = PhotoVerification(user=user)
We track this attempt through various states:
@@ -100,6 +101,9 @@ class PhotoVerification(StatusModel):
attempt.status == "created"
pending_requests = PhotoVerification.submitted.all()
"""
# We can make this configurable later...
DAYS_GOOD_FOR = settings.VERIFY_STUDENT["DAYS_GOOD_FOR"]
######################## Fields Set During Creation ########################
# See class docstring for description of status states
STATUS = Choices('created', 'ready', 'submitted', 'approved', 'denied')
@@ -158,12 +162,37 @@ class PhotoVerification(StatusModel):
##### Methods listed in the order you'd typically call them
@classmethod
def user_is_verified(cls, user):
def user_is_verified(cls, user, earliest_allowed_date=None):
"""
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
time, so a user might have to renew periodically.
"""
earliest_allowed_date = (
earliest_allowed_date or
datetime.now(pytz.UTC) - timedelta(days=cls.DAYS_GOOD_FOR)
)
return cls.objects.filter(
user=user,
status="approved",
created_at__lte=earliest_allowed_date
).exists()
@classmethod
def user_has_valid_or_pending(cls, user, earliest_allowed_date=None):
"""
TODO: eliminate duplication with user_is_verified
"""
valid_statuses = ['ready', 'submitted', 'approved']
earliest_allowed_date = (
earliest_allowed_date or
datetime.now(pytz.UTC) - timedelta(days=cls.DAYS_GOOD_FOR)
)
return cls.objects.filter(
user=user,
status__in=valid_statuses,
created_at__lte=earliest_allowed_date
).exists()
@classmethod
def active_for_user(cls, user):

View File

@@ -31,8 +31,6 @@ class StartView(TestCase):
user = UserFactory.create(username="rusty", password="test")
self.client.login(username="rusty", password="test")
def must_be_logged_in(self):
self.assertHttpForbidden(self.client.get(self.start_url()))

View File

@@ -35,9 +35,9 @@ urlpatterns = patterns(
),
url(
r'^start_or_resume_attempt',
views.start_or_resume_attempt,
name="verify_student/start_or_resume_attempt"
r'^verify',
views.VerifyView.as_view(),
name="verify_student_verify"
)
)

View File

@@ -4,28 +4,36 @@
"""
from mitxmako.shortcuts import render_to_response
from verify_student.models import SoftwareSecurePhotoVerification
from django.conf import settings
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.views.generic.base import View
from course_modes.models import CourseMode
from verify_student.models import SoftwareSecurePhotoVerification
# @login_required
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.
"""
# 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
class VerifyView(View):
attempt = SoftwareSecurePhotoVerification.active_for_user(request.user)
if not attempt:
# Redirect to show requirements
pass
def get(self, request):
"""
"""
# 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_has_valid_or_pending(request.user):
progress_state = "payment"
else:
# If they haven't completed a verification attempt, we have to
# restart with a new one. We can't reuse an older one because we
# won't be able to show them their encrypted photo_id -- it's easier
# bookkeeping-wise just to start over.
progress_state = "start"
return render_to_response('verify_student/face_upload.html')
def post(request):
attempt = SoftwareSecurePhotoVerification(user=request.user)
# if attempt.
def show_requirements(request):
"""This might just be a plain template without a view."""

View File

@@ -823,3 +823,8 @@ def enable_theme(theme_name):
# avoid collisions with default edX static files
STATICFILES_DIRS.append((u'themes/%s' % theme_name,
theme_root / 'static'))
################# Student Verification #################
VERIFY_STUDENT = {
"DAYS_GOOD_FOR" : 365, # How many days is a verficiation good for?
}