Commit 12e26506 by Clinton Blackburn Committed by Vedran Karacic

Added photo verification status API endpoint

ECOM-2470 & SOL-2126
parent 47a22b23
......@@ -2,8 +2,10 @@
Django REST Framework serializers for the User API application
"""
from django.contrib.auth.models import User
from django.utils.timezone import now
from rest_framework import serializers
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from student.models import UserProfile
from .models import UserPreference
......@@ -90,3 +92,20 @@ class CountryTimeZoneSerializer(serializers.Serializer): # pylint: disable=abst
"""
time_zone = serializers.CharField()
description = serializers.CharField()
class SoftwareSecurePhotoVerificationSerializer(serializers.ModelSerializer):
"""
Serializer that generates a representation of a user's photo verification status.
"""
is_verified = serializers.SerializerMethodField()
def get_is_verified(self, obj):
"""
Return a boolean indicating if a the user is verified.
"""
return obj.status == 'approved' and obj.expiration_datetime > now()
class Meta(object):
fields = ('status', 'expiration_datetime', 'is_verified')
model = SoftwareSecurePhotoVerification
......@@ -8,6 +8,7 @@ from django.conf.urls import patterns, url
from ..profile_images.views import ProfileImageView
from .accounts.views import AccountViewSet
from .preferences.views import PreferencesView, PreferencesDetailView
from .verification_api.views import PhotoVerificationStatusView
ACCOUNT_LIST = AccountViewSet.as_view({
......@@ -26,16 +27,21 @@ urlpatterns = patterns(
url(
r'^v1/accounts/{}/image$'.format(settings.USERNAME_PATTERN),
ProfileImageView.as_view(),
name="accounts_profile_image_api"
name='accounts_profile_image_api'
),
url(
r'^v1/accounts/{}/verification_status/$'.format(settings.USERNAME_PATTERN),
PhotoVerificationStatusView.as_view(),
name='verification_status'
),
url(
r'^v1/preferences/{}$'.format(settings.USERNAME_PATTERN),
PreferencesView.as_view(),
name="preferences_api"
name='preferences_api'
),
url(
r'^v1/preferences/{}/(?P<preference_key>[a-zA-Z0-9_]+)$'.format(settings.USERNAME_PATTERN),
PreferencesDetailView.as_view(),
name="preferences_detail_api"
name='preferences_detail_api'
),
)
""" Tests for API endpoints. """
from __future__ import unicode_literals
import datetime
import freezegun
import json
from django.conf import settings
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.utils import override_settings
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from student.tests.factories import UserFactory
FROZEN_TIME = '2015-01-01'
VERIFY_STUDENT = {'DAYS_GOOD_FOR': 365}
@freezegun.freeze_time(FROZEN_TIME)
@override_settings(VERIFY_STUDENT=VERIFY_STUDENT)
class PhotoVerificationStatusViewTests(TestCase):
""" Tests for the PhotoVerificationStatusView endpoint. """
CREATED_AT = datetime.datetime.strptime(FROZEN_TIME, '%Y-%m-%d')
PASSWORD = 'test'
def setUp(self):
super(PhotoVerificationStatusViewTests, self).setUp()
self.user = UserFactory.create(password=self.PASSWORD)
self.staff = UserFactory.create(is_staff=True, password=self.PASSWORD)
self.verification = SoftwareSecurePhotoVerification.objects.create(user=self.user, status='submitted')
self.path = reverse('verification_status', kwargs={'username': self.user.username})
self.client.login(username=self.staff.username, password=self.PASSWORD)
def assert_path_not_found(self, path):
""" Assert the path returns HTTP 404. """
response = self.client.get(path)
self.assertEqual(response.status_code, 404)
def assert_verification_returned(self, verified=False):
""" Assert the path returns HTTP 200 and returns appropriately-serialized data. """
response = self.client.get(self.path)
self.assertEqual(response.status_code, 200)
expected_expires = self.CREATED_AT + datetime.timedelta(settings.VERIFY_STUDENT['DAYS_GOOD_FOR'])
expected = {
'status': self.verification.status,
'expiration_datetime': '{}Z'.format(expected_expires.isoformat()),
'is_verified': verified
}
self.assertEqual(json.loads(response.content), expected)
def test_non_existent_user(self):
""" The endpoint should return HTTP 404 if the user does not exist. """
path = reverse('verification_status', kwargs={'username': 'abc123'})
self.assert_path_not_found(path)
def test_no_verifications(self):
""" The endpoint should return HTTP 404 if the user has no verifications. """
user = UserFactory.create()
path = reverse('verification_status', kwargs={'username': user.username})
self.assert_path_not_found(path)
def test_authentication_required(self):
""" The endpoint should return HTTP 403 if the user is not authenticated. """
self.client.logout()
response = self.client.get(self.path)
self.assertEqual(response.status_code, 401)
def test_staff_user(self):
""" The endpoint should be accessible to staff users. """
self.client.login(username=self.staff.username, password=self.PASSWORD)
self.assert_verification_returned()
def test_owner(self):
""" The endpoint should be accessible to the user who submitted the verification request. """
self.client.login(username=self.user.username, password=self.user.password)
self.assert_verification_returned()
def test_non_owner_or_staff_user(self):
""" The endpoint should NOT be accessible if the request is not made by the submitter or staff user. """
user = UserFactory.create()
self.client.login(username=user.username, password=self.PASSWORD)
response = self.client.get(self.path)
self.assertEqual(response.status_code, 403)
def test_approved_verification(self):
""" The endpoint should return that the user is verified if the user's verification is accepted. """
self.verification.status = 'approved'
self.verification.save()
self.client.login(username=self.user.username, password=self.user.password)
self.assert_verification_returned(verified=True)
""" Verification API v1 views. """
from django.http import Http404
from edx_rest_framework_extensions.authentication import JwtAuthentication
from rest_framework.authentication import SessionAuthentication
from rest_framework.generics import RetrieveAPIView
from rest_framework_oauth.authentication import OAuth2Authentication
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from openedx.core.djangoapps.user_api.serializers import SoftwareSecurePhotoVerificationSerializer
from openedx.core.lib.api.permissions import IsStaffOrOwner
class PhotoVerificationStatusView(RetrieveAPIView):
""" PhotoVerificationStatus detail endpoint. """
authentication_classes = (JwtAuthentication, OAuth2Authentication, SessionAuthentication,)
permission_classes = (IsStaffOrOwner,)
serializer_class = SoftwareSecurePhotoVerificationSerializer
def get_object(self):
username = self.kwargs['username']
verifications = SoftwareSecurePhotoVerification.objects.filter(user__username=username).order_by('-updated_at')
if len(verifications) > 0:
verification = verifications[0]
self.check_object_permissions(self.request, verification)
return verification
raise Http404
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