Added photo verification status API endpoint
ECOM-2470 & SOL-2126
This commit is contained in:
committed by
Vedran Karacic
parent
47a22b23bc
commit
12e2650630
@@ -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'
|
||||
),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
""" 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)
|
||||
28
openedx/core/djangoapps/user_api/verification_api/views.py
Normal file
28
openedx/core/djangoapps/user_api/verification_api/views.py
Normal file
@@ -0,0 +1,28 @@
|
||||
""" 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
|
||||
Reference in New Issue
Block a user