Code cleanup due to review comments
* make `user_status` more intelligent * remove some logic from the templates * rename `parse_error_msg` to `parsed_error_msg` * fix up and add more tests LMS-1387
This commit is contained in:
@@ -418,7 +418,6 @@ MKTG_URL_LINK_MAP = {
|
||||
|
||||
COURSES_WITH_UNSAFE_CODE = []
|
||||
|
||||
|
||||
############################## EVENT TRACKING #################################
|
||||
|
||||
TRACK_MAX_EVENT = 10000
|
||||
|
||||
@@ -25,14 +25,13 @@ from django.core.validators import validate_email, validate_slug, ValidationErro
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.http import (HttpResponse, HttpResponseBadRequest, HttpResponseForbidden,
|
||||
HttpResponseNotAllowed, Http404)
|
||||
Http404)
|
||||
from django.shortcuts import redirect
|
||||
from django_future.csrf import ensure_csrf_cookie
|
||||
from django.utils.http import cookie_date, base36_to_int, urlencode
|
||||
from django.utils.http import cookie_date, base36_to_int
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.decorators.http import require_POST, require_GET
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.utils.translation import ugettext as _u
|
||||
|
||||
from ratelimitbackend.exceptions import RateLimitException
|
||||
|
||||
@@ -337,7 +336,7 @@ def dashboard(request):
|
||||
)
|
||||
)
|
||||
# Verification Attempts
|
||||
verification_status = SoftwareSecurePhotoVerification.user_status(user)
|
||||
verification_status, verification_msg = SoftwareSecurePhotoVerification.user_status(user)
|
||||
# get info w.r.t ExternalAuthMap
|
||||
external_auth_map = None
|
||||
try:
|
||||
@@ -355,8 +354,8 @@ def dashboard(request):
|
||||
'all_course_modes': course_modes,
|
||||
'cert_statuses': cert_statuses,
|
||||
'show_email_settings_for': show_email_settings_for,
|
||||
'verification_status': verification_status[0],
|
||||
'verification_msg': verification_status[1],
|
||||
'verification_status': verification_status,
|
||||
'verification_msg': verification_msg,
|
||||
}
|
||||
|
||||
return render_to_response('dashboard.html', context)
|
||||
@@ -663,11 +662,11 @@ def manage_user_standing(request):
|
||||
row = [user.username, user.standing.all()[0].changed_by]
|
||||
rows.append(row)
|
||||
|
||||
|
||||
context = {'headers': headers, 'rows': rows}
|
||||
|
||||
return render_to_response("manage_user_standing.html", context)
|
||||
|
||||
|
||||
@require_POST
|
||||
@login_required
|
||||
@ensure_csrf_cookie
|
||||
@@ -681,34 +680,34 @@ def disable_account_ajax(request):
|
||||
username = request.POST.get('username')
|
||||
context = {}
|
||||
if username is None or username.strip() == '':
|
||||
context['message'] = _u('Please enter a username')
|
||||
context['message'] = _('Please enter a username')
|
||||
return JsonResponse(context, status=400)
|
||||
|
||||
account_action = request.POST.get('account_action')
|
||||
if account_action is None:
|
||||
context['message'] = _u('Please choose an option')
|
||||
context['message'] = _('Please choose an option')
|
||||
return JsonResponse(context, status=400)
|
||||
|
||||
username = username.strip()
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
context['message'] = _u("User with username {} does not exist").format(username)
|
||||
context['message'] = _("User with username {} does not exist").format(username)
|
||||
return JsonResponse(context, status=400)
|
||||
else:
|
||||
user_account, _ = UserStanding.objects.get_or_create(
|
||||
user_account, _succss = UserStanding.objects.get_or_create(
|
||||
user=user, defaults={'changed_by': request.user},
|
||||
)
|
||||
if account_action == 'disable':
|
||||
user_account.account_status = UserStanding.ACCOUNT_DISABLED
|
||||
context['message'] = _u("Successfully disabled {}'s account").format(username)
|
||||
context['message'] = _("Successfully disabled {}'s account").format(username)
|
||||
log.info("{} disabled {}'s account".format(request.user, username))
|
||||
elif account_action == 'reenable':
|
||||
user_account.account_status = UserStanding.ACCOUNT_ENABLED
|
||||
context['message'] = _u("Successfully reenabled {}'s account").format(username)
|
||||
context['message'] = _("Successfully reenabled {}'s account").format(username)
|
||||
log.info("{} reenabled {}'s account".format(request.user, username))
|
||||
else:
|
||||
context['message'] = _u("Unexpected account status")
|
||||
context['message'] = _("Unexpected account status")
|
||||
return JsonResponse(context, status=400)
|
||||
user_account.changed_by = request.user
|
||||
user_account.standing_last_changed_at = datetime.datetime.now(UTC)
|
||||
|
||||
@@ -115,7 +115,6 @@ class PhotoVerification(StatusModel):
|
||||
attempt.status == "created"
|
||||
pending_requests = PhotoVerification.submitted.all()
|
||||
"""
|
||||
|
||||
######################## Fields Set During Creation ########################
|
||||
# See class docstring for description of status states
|
||||
STATUS = Choices('created', 'ready', 'submitted', 'must_retry', 'approved', 'denied')
|
||||
@@ -233,27 +232,44 @@ class PhotoVerification(StatusModel):
|
||||
@classmethod
|
||||
def user_status(cls, user):
|
||||
"""
|
||||
Returns the status of the user based on their latest verification attempt
|
||||
Returns the status of the user based on their past verification attempts
|
||||
|
||||
If no such verification exists, returns 'none'
|
||||
If verification has expired, returns 'expired'
|
||||
If the verification has been approved, returns 'approved'
|
||||
If the verification process is still ongoing, returns 'pending'
|
||||
If the verification has been denied and the user must resubmit photos, returns 'must_reverify'
|
||||
"""
|
||||
try:
|
||||
attempts = cls.objects.filter(user=user).order_by('-updated_at')
|
||||
attempt = attempts[0]
|
||||
except IndexError:
|
||||
return ('none', '')
|
||||
status = 'none'
|
||||
error_msg = ''
|
||||
|
||||
if attempt.created_at < cls._earliest_allowed_date():
|
||||
return ('expired', '')
|
||||
if cls.user_is_verified(user):
|
||||
status = 'approved'
|
||||
elif cls.user_has_valid_or_pending(user):
|
||||
# user_has_valid_or_pending does include 'approved', but if we are
|
||||
# here, we know that the attempt is still pending
|
||||
status = 'pending'
|
||||
else:
|
||||
# we need to check the most recent attempt to see if we need to ask them to do
|
||||
# a retry
|
||||
try:
|
||||
attempts = cls.objects.filter(user=user).order_by('-updated_at')
|
||||
attempt = attempts[0]
|
||||
except IndexError:
|
||||
return ('none', error_msg)
|
||||
if attempt.created_at < cls._earliest_allowed_date():
|
||||
return ('expired', error_msg)
|
||||
|
||||
error_msg = attempt.error_msg
|
||||
if attempt.error_msg:
|
||||
error_msg = attempt.parse_error_msg()
|
||||
# right now, this is the only state at which they must reverify. It
|
||||
# may change later
|
||||
if attempt.status == 'denied':
|
||||
status = 'must_reverify'
|
||||
if attempt.error_msg:
|
||||
error_msg = attempt.parsed_error_msg()
|
||||
|
||||
return (attempt.status, error_msg)
|
||||
return (status, error_msg)
|
||||
|
||||
def parse_error_msg(self):
|
||||
def parsed_error_msg(self):
|
||||
"""
|
||||
Sometimes, the error message we've received needs to be parsed into
|
||||
something more human readable
|
||||
@@ -523,7 +539,7 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
|
||||
self.status = "must_retry"
|
||||
self.save()
|
||||
|
||||
def parse_error_msg(self):
|
||||
def parsed_error_msg(self):
|
||||
"""
|
||||
Parse the error messages we receive from SoftwareSecure
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ class TestPhotoVerification(TestCase):
|
||||
attempt.save()
|
||||
|
||||
status = SoftwareSecurePhotoVerification.user_status(user)
|
||||
self.assertEquals(status, (attempt.status, ''))
|
||||
self.assertEquals(status, ('approved', ''))
|
||||
|
||||
# create another one for the same user, make sure the right one is
|
||||
# returned
|
||||
@@ -331,14 +331,20 @@ class TestPhotoVerification(TestCase):
|
||||
attempt2.save()
|
||||
|
||||
status = SoftwareSecurePhotoVerification.user_status(user)
|
||||
self.assertEquals(status, (attempt2.status, "No photo ID was provided."))
|
||||
self.assertEquals(status, ('approved', ''))
|
||||
|
||||
# now delete the first one and verify that the denial is being handled
|
||||
# properly
|
||||
attempt.delete()
|
||||
status = SoftwareSecurePhotoVerification.user_status(user)
|
||||
self.assertEquals(status, ('must_reverify', "No photo ID was provided."))
|
||||
|
||||
def test_parse_error_msg_success(self):
|
||||
user = UserFactory.create()
|
||||
attempt = SoftwareSecurePhotoVerification(user=user)
|
||||
attempt.status = 'denied'
|
||||
attempt.error_msg = '[{"photoIdReasons": ["Not provided"]}]'
|
||||
parsed_error_msg = attempt.parse_error_msg()
|
||||
parsed_error_msg = attempt.parsed_error_msg()
|
||||
self.assertEquals("No photo ID was provided.", parsed_error_msg)
|
||||
|
||||
def test_parse_error_msg_failure(self):
|
||||
@@ -350,8 +356,9 @@ class TestPhotoVerification(TestCase):
|
||||
'Not Provided',
|
||||
'[{"IdReasons": ["Not provided"]}]',
|
||||
'{"IdReasons": ["Not provided"]}',
|
||||
u'[{"ïḋṚëäṡöṅṡ": ["Ⓝⓞⓣ ⓟⓡⓞⓥⓘⓓⓔⓓ "]}]',
|
||||
}
|
||||
for msg in bad_messages:
|
||||
attempt.error_msg = msg
|
||||
parsed_error_msg = attempt.parse_error_msg()
|
||||
parsed_error_msg = attempt.parsed_error_msg()
|
||||
self.assertEquals(parsed_error_msg, "There was an error verifying your ID photos.")
|
||||
|
||||
@@ -21,10 +21,7 @@
|
||||
</li>
|
||||
%endif
|
||||
|
||||
<%doc>
|
||||
This is for 'pending' statuses, where we are waiting for a response
|
||||
</%doc>
|
||||
%if verification_status in ('must_retry', 'submitted'):
|
||||
%if verification_status == 'pending':
|
||||
<li class="status status-verification is-pending">
|
||||
<span class="title status-title">${_("ID-Verification Status")}</span>
|
||||
|
||||
@@ -41,7 +38,7 @@ This is for 'pending' statuses, where we are waiting for a response
|
||||
|
||||
%endif
|
||||
|
||||
%if verification_status == 'denied':
|
||||
%if verification_status == 'must_reverify':
|
||||
<li class="status status-verification is-denied">
|
||||
<span class="title status-title">${_("ID-Verification Status")}</span>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user