Skip to content

Commit 928d9b6

Browse files
committed
feat: add LTI tools for LTI APIs in edX
1 parent 56ab615 commit 928d9b6

File tree

3 files changed

+118
-0
lines changed

3 files changed

+118
-0
lines changed

edx_api/client.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .grades import UserCurrentGrades
1616
from .user_info import UserInfo
1717
from .user_validation import UserValidation
18+
from .lti_tools import LTITools
1819

1920

2021
class EdxApi:
@@ -123,3 +124,9 @@ def user_validation(self):
123124
def course_runs(self):
124125
"""Course runs management API (Works with CMS)"""
125126
return CourseRuns(self.get_requester(token_type="jwt"), self.base_url)
127+
128+
@property
129+
def lti_tools(self):
130+
"""LTI Tools API"""
131+
return LTITools(self.get_requester(), self.base_url)
132+

edx_api/lti_tools/__init__.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Client for user_validation API"""
2+
from urllib.parse import urljoin
3+
4+
5+
class LTITools:
6+
"""
7+
Open edX user validation client
8+
"""
9+
10+
def __init__(self, requester, base_url):
11+
"""
12+
Args:
13+
requester (Requester): an authenticated objects for requests to edX
14+
base_url (str): string representing the base URL of an edX LMS instance
15+
"""
16+
self.requester = requester
17+
self.base_url = base_url
18+
19+
20+
def fix_lti_user(self, username, email):
21+
"""
22+
Fixes an LTI user with duplicate email
23+
24+
Args:
25+
username (str): Username of the Application user
26+
email (str): Email of the Application user
27+
28+
Returns:
29+
bool: True if the user was fixed successfully, False otherwise
30+
"""
31+
request_data = dict(username=username, email=email)
32+
33+
# the request is done on behalf of the current logged in user
34+
return self.requester.post(
35+
urljoin(
36+
self.base_url,
37+
'/api/lti-user-fix/'
38+
),
39+
json=request_data)

edx_api/lti_tools/init_test.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""Tests for LTI Tools API client"""
2+
3+
from unittest.mock import Mock
4+
from urllib.parse import urljoin
5+
6+
from edx_api.lti_tools import LTITools
7+
8+
9+
class TestLTITools:
10+
"""Tests for LTITools class"""
11+
12+
def setup_method(self):
13+
"""Set up test fixtures"""
14+
self.requester = Mock()
15+
self.base_url = "https://example.edx.org"
16+
self.client = LTITools(self.requester, self.base_url)
17+
18+
def test_init(self):
19+
"""Test LTITools initialization"""
20+
assert self.client.requester == self.requester
21+
assert self.client.base_url == self.base_url
22+
23+
def test_fix_lti_user_success(self):
24+
"""Test fix_lti_user with successful response"""
25+
username = "test_user"
26+
27+
expected_response = Mock()
28+
self.requester.post.return_value = expected_response
29+
30+
result = self.client.fix_lti_user(username, email)
31+
32+
self.requester.post.assert_called_once_with(
33+
urljoin(self.base_url, '/api/lti-user-fix/'),
34+
json={'username': username, 'email': email}
35+
)
36+
assert result == expected_response
37+
38+
def test_fix_lti_user_with_different_credentials(self):
39+
"""Test fix_lti_user with different username and email"""
40+
username = "another_user"
41+
42+
expected_response = Mock()
43+
self.requester.post.return_value = expected_response
44+
45+
result = self.client.fix_lti_user(username, email)
46+
47+
self.requester.post.assert_called_once_with(
48+
urljoin(self.base_url, '/api/lti-user-fix/'),
49+
json={'username': username, 'email': email}
50+
)
51+
assert result == expected_response
52+
53+
def test_fix_lti_user_url_construction(self):
54+
"""Test that the correct URL is constructed"""
55+
username = "user"
56+
57+
58+
self.client.fix_lti_user(username, email)
59+
60+
call_args = self.requester.post.call_args
61+
expected_url = urljoin(self.base_url, '/api/lti-user-fix/')
62+
assert call_args[0][0] == expected_url
63+
64+
def test_fix_lti_user_request_data_format(self):
65+
"""Test that request data is formatted correctly"""
66+
username = "test_user"
67+
68+
69+
self.client.fix_lti_user(username, email)
70+
71+
call_args = self.requester.post.call_args
72+
assert call_args[1]['json'] == {'username': username, 'email': email}

0 commit comments

Comments
 (0)