Skip to content

Commit

Permalink
refactor: validate_user_registration api
Browse files Browse the repository at this point in the history
  • Loading branch information
mudassir-hafeez committed Jul 9, 2024
1 parent fed8f0f commit 543438e
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 29 deletions.
6 changes: 6 additions & 0 deletions edx_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .email_settings import EmailSettings
from .grades import UserCurrentGrades
from .user_info import UserInfo
from .user_validation import UserValidation


class EdxApi:
Expand Down Expand Up @@ -105,3 +106,8 @@ def user_info(self):
def bulk_user_retirement(self):
"""Bulk user retirement API"""
return BulkUserRetirement(self.get_requester(token_type="jwt"), self.base_url)

@property
def user_validation(self):
"""User validation API"""
return UserValidation(self.get_requester(), self.base_url)
29 changes: 0 additions & 29 deletions edx_api/user_info/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,32 +67,3 @@ def update_user_name(self, username, full_name):
resp.raise_for_status()

return Info(resp.json())

def validate_user_registration(self, data=None):
"""
Validate information about user data during registration.
Expects data in the form
```
{
"name": "Dan the Validator",
"username": "mslm",
"email": "[email protected]",
"confirm_email": "[email protected]",
"password": "password123",
"country": "PK"
}
```
where one may enter individual inputs if needed. Some inputs
can get extra verification checks if entered along with others,
like when the password may not equal the username.
"""
resp = self.requester.post(
urljoin(
self.base_url,
'/api/user/v1/validation/registration'
),
data=data)
resp.raise_for_status()

return resp.json()
38 changes: 38 additions & 0 deletions edx_api/user_validation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Client for user_validation API"""
from urllib.parse import urljoin

from .models import Validation


class UserValidation(object):
"""
edX user validation client
"""

api_url = "/api/user/v1/validation/registration"

def __init__(self, requester, base_url):
"""
Args:
requester (Requester): an unauthenticated objects for requests to edX
base_url (str): string representing the base URL of an edX LMS instance
"""
self.requester = requester
self.base_url = base_url

def validate_user_registration(self, registration_information=None):
"""
Validate information about user data during registration.
Args:
registration_information (dict): request payload to validate name or username
Returns:
UserValidation: Object representing the user validation
"""
resp = self.requester.post(
urljoin(self.base_url, self.api_url), data=registration_information
)
resp.raise_for_status()

return Validation(resp.json())
24 changes: 24 additions & 0 deletions edx_api/user_validation/fixtures/user_validation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"validation_responses": {
"valid_name": {
"validation_decisions": {
"name": ""
}
},
"invalid_name": {
"validation_decisions": {
"name": "Invalid name"
}
},
"valid_username": {
"validation_decisions": {
"username": ""
}
},
"invalid_username": {
"validation_decisions": {
"username": "Invalid username"
}
}
}
}
61 changes: 61 additions & 0 deletions edx_api/user_validation/init_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""
Test responses from user_validation api.
"""

import json
import os
from unittest import TestCase
from urllib.parse import urljoin

import requests_mock

from edx_api.client import EdxApi
from .models import Validation


class UserValidationTestCase(TestCase):
"""
Tests for the UserValidation API client.
"""

base_url = "https://edx.example.com"

def setUp(self):
super().setUp()

with open(
os.path.join(
os.path.dirname(__file__),
"fixtures/user_validation.json",
)
) as file: # pylint: disable=redefined-builtin
self.validation_data = json.load(file)
self.client = EdxApi({"access_token": ""}, self.base_url)

def get_mock_response(self, key):
"""
Return the validation_decisions response from the fixture.
"""
return self.validation_data['validation_responses'].get(key, {})

@requests_mock.Mocker()
def test_validate_user_registration(self, mock_req):
"""
Test that validate_user_registration validates name and username.
"""
test_cases = [
('valid_name', {'name': ''}, {'name': 'test_name'}),
('invalid_name', {'name': 'Invalid name'}, {'name': 'http://test_name'}),
('valid_username', {'username': ''}, {'username': 'test_username'}),
('invalid_username', {'username': 'Invalid username'}, {'username': '!test_username'}),
]

for key, expected_validation_decisions, request_data in test_cases:
with self.subTest(key=key):
mock_req.post(
urljoin(self.base_url, '/api/user/v1/validation/registration'),
json=self.get_mock_response(key)
)
validation_response = self.client.user_validation.validate_user_registration(request_data)
self.assertIsInstance(validation_response, Validation)
self.assertDictEqual(validation_response.validation_decisions, expected_validation_decisions)
22 changes: 22 additions & 0 deletions edx_api/user_validation/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Models for user_validation client"""


class Validation(object):
"""
Validation about user
"""
def __init__(self, json):
self.validation_decisions = json.get('validation_decisions', {})

def __str__(self):
return f"<User validation>"

@property
def name(self):
"""Returns name validation of the user"""
return self.validation_decisions.get('name')

@property
def username(self):
"""Returns username validation of the user."""
return self.validation_decisions.get('username')
42 changes: 42 additions & 0 deletions edx_api/user_validation/models_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Tests for Validation"""
import json
import os
from unittest import TestCase

from .models import Validation


class ValidationTests(TestCase):
"""Tests for Validation"""

@classmethod
def setUpClass(cls):
with open(os.path.join(os.path.dirname(__file__),
'fixtures/user_validation.json')) as file_obj:
cls.user_validation_json = json.loads(file_obj.read())

cls.validation_responses = cls.user_validation_json.get('validation_responses', {})

def test_str(self):
"""Test the __str__"""
self.assertEqual(str(self.get_validation_instance('valid_name')), "<User validation>")

def test_properties(self, key, expected_name):
"""Test properties on Validation model"""
test_cases = [
('invalid_name', 'Invalid name', 'name'),
('valid_name', '', 'name'),
('invalid_username', 'Invalid username', 'username'),
('valid_username', '', 'username'),
]

for key, expected_value, field in test_cases:
with self.subTest(key=key):
validation = self.get_validation_instance(key)
if field == 'name':
self.assertEqual(validation.name, expected_value)
elif field == 'username':
self.assertEqual(validation.username, expected_value)

def get_validation_instance(self, key):
return Validation(self.validation_responses.get(key, {}))

0 comments on commit 543438e

Please sign in to comment.