Skip to content

Commit

Permalink
feat: drop Python 3.8 and add Python 3.12 support
Browse files Browse the repository at this point in the history
- Dropped support for Python 3.8 and added support for Python 3.12.
- Removed importlib-metadata<7 pin from constraints as it's unpin issue was closed.
- Updated pylintrc file with latest version of edx-lint.
- Fixed app_label error for model named CourseAllowPIISharingInLTIFlag.
- Released a new version.
  • Loading branch information
Muhammad Faraz Maqsood committed Nov 14, 2024
1 parent 4bacb6e commit 5beb2e1
Show file tree
Hide file tree
Showing 19 changed files with 341 additions and 382 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ jobs:
matrix:
os: [ubuntu-latest]
python-version:
- '3.8'
- '3.11'
- '3.12'
toxenv: [django42, quality]

steps:
Expand All @@ -38,7 +38,7 @@ jobs:
run: tox

- name: Run Coverage
if: matrix.python-version == '3.8' && matrix.toxenv=='py38-django42'
if: matrix.python-version == '3.11' && matrix.toxenv=='py311-django42'
uses: codecov/codecov-action@v1
with:
flags: unittests
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ Please See the `releases tab <https://github.com/openedx/xblock-lti-consumer/rel
Unreleased
~~~~~~~~~~

9.12.0 - 2024-11-14
-------------------
* Dropped support for Python 3.8 and added support for Python 3.12.
* Removed importlib-metadata<7 pin from constraints as it's unpin issue was closed.
* Updated pylintrc file with latest version of edx-lint.
* Fixed app_label error for model named CourseAllowPIISharingInLTIFlag.

9.11.3 - 2024-05-30
-------------------
* Remove utf-8 encoding for user full name
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ One Time Setup
cd xblock-lti-consumer
# Set up a virtualenv using virtualenvwrapper with the same name as the repo and activate it
mkvirtualenv -p python3.8 xblock-lti-consumer
mkvirtualenv -p python3.11 xblock-lti-consumer
Every time you develop something in this repo
Expand Down
2 changes: 1 addition & 1 deletion lti_consumer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
from .apps import LTIConsumerApp
from .lti_xblock import LtiConsumerXBlock

__version__ = '9.11.3'
__version__ = '9.12.0'
1 change: 1 addition & 0 deletions lti_consumer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -920,4 +920,5 @@ def __str__(self):
class Meta:
# This model was moved from edx-platform, with intention of retaining existing data.
# This is referencing the original table name.
app_label = "lti_consumer"
db_table = "xblock_config_courseeditltifieldsenabledflag"
17 changes: 12 additions & 5 deletions lti_consumer/plugin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ def public_keyset_endpoint(
external_id = f"{external_app}:{external_slug}"

try:
version = None
public_jwk = {}
if usage_id:
lti_config = LtiConfiguration.objects.get(location=UsageKey.from_string(usage_id))
version = lti_config.version
Expand All @@ -127,7 +129,7 @@ def public_keyset_endpoint(
version = lti_config.get("version")
public_jwk = lti_config.get("lti_1p3_public_jwk", {})

if version != LtiConfiguration.LTI_1P3:
if version is None or version != LtiConfiguration.LTI_1P3:
raise LtiError(
"LTI Error: LTI 1.1 blocks do not have a public keyset endpoint."
)
Expand Down Expand Up @@ -413,12 +415,14 @@ def access_token_endpoint(
JsonResponse or Http404
References:
Sucess: https://tools.ietf.org/html/rfc6749#section-4.4.3
Success: https://tools.ietf.org/html/rfc6749#section-4.4.3
Failure: https://tools.ietf.org/html/rfc6749#section-5.2
"""
external_id = f"{external_app}:{external_slug}"

try:
version = None
lti_consumer = None
if usage_id:
lti_config = LtiConfiguration.objects.get(location=UsageKey.from_string(usage_id))
version = lti_config.version
Expand Down Expand Up @@ -457,9 +461,12 @@ def access_token_endpoint(
)
raise Http404 from exc

if version != LtiConfiguration.LTI_1P3:
if version is None or version != LtiConfiguration.LTI_1P3:
return JsonResponse({"error": "invalid_lti_version"}, status=HTTP_404_NOT_FOUND)

if lti_consumer is None:
return JsonResponse({"error": "lti_consumer_not_initialized"}, status=HTTP_404_NOT_FOUND)

try:
token = lti_consumer.access_token(
dict(urllib.parse.parse_qsl(
Expand All @@ -471,10 +478,10 @@ def access_token_endpoint(

# Handle errors and return a proper response
except MissingRequiredClaim:
# Missing request attibutes
# Missing request attributes
return JsonResponse({"error": "invalid_request"}, status=HTTP_400_BAD_REQUEST)
except (MalformedJwtToken, TokenSignatureExpired):
# Triggered when a invalid grant token is used
# Triggered when an invalid grant token is used
return JsonResponse({"error": "invalid_grant"}, status=HTTP_400_BAD_REQUEST)
except (NoSuitableKeys, UnknownClientId):
# Client ID is not registered in the block or
Expand Down
27 changes: 21 additions & 6 deletions lti_consumer/tests/unit/plugin/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,13 @@ def test_access_token_endpoint(self):
self.mock_client.access_token.return_value = token

body = self.get_body(create_jwt(self.key, {}))
response = self.client.post(self.url, data=body)
response = self.client.post(self.url, data=json.dumps(body), content_type='application/json')
self.mock_client.access_token.assert_called_once()
called_args = self.mock_client.access_token.call_args[0]
actual_arg = called_args[0]
actual_dict = json.loads(next(iter(actual_arg.keys())))

self.mock_client.access_token.called_once_with(body)
self.assertEqual(actual_dict, body)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), token)

Expand All @@ -715,9 +719,14 @@ def test_access_token_endpoint_with_location_in_url(self):
args=[str(self.config.location)]
)
body = self.get_body(create_jwt(self.key, {}))
response = self.client.post(url, data=body)
response = self.client.post(url, data=json.dumps(body), content_type='application/json')

self.mock_client.access_token.called_once_with(body)
self.mock_client.access_token.assert_called_once()
called_args = self.mock_client.access_token.call_args[0]
actual_arg = called_args[0]
actual_dict = json.loads(next(iter(actual_arg.keys())))

self.assertEqual(actual_dict, body)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), token)

Expand Down Expand Up @@ -748,7 +757,8 @@ def test_access_token_endpoint_with_external_id_in_url(
body = self.get_body(create_jwt(self.key, {}))
response = self.client.post(
reverse('lti_consumer:lti_consumer.access_token_via_external_id', args=['x', 'x']),
data=body,
data=json.dumps(body),
content_type='application/json'
)

get_external_config_from_filter.assert_called_once_with({}, 'x:x')
Expand All @@ -765,7 +775,12 @@ def test_access_token_endpoint_with_external_id_in_url(
tool_key=external_config['lti_1p3_tool_public_key'],
tool_keyset_url=external_config['lti_1p3_tool_keyset_url'],
)
lti_consumer().access_token.called_once_with(body)
lti_consumer().access_token.assert_called_once()
called_args = lti_consumer().access_token.call_args[0]
actual_arg = called_args[0]
actual_dict = json.loads(next(iter(actual_arg.keys())))

self.assertEqual(actual_dict, body)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), token)

Expand Down
5 changes: 3 additions & 2 deletions pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
# SERIOUSLY.
#
# ------------------------------
# Generated by edx-lint version: 5.3.6
# Generated by edx-lint version: 5.4.1
# ------------------------------
[MASTER]
ignore =
Expand Down Expand Up @@ -288,6 +288,7 @@ disable =

logging-fstring-interpolation,
django-not-configured,
too-many-positional-arguments,

[REPORTS]
output-format = text
Expand Down Expand Up @@ -384,4 +385,4 @@ int-import-graph =
[EXCEPTIONS]
overgeneral-exceptions = builtins.Exception

# 9cc29d4fbd4438c7636de003db74bef089bad86e
# 181f52c3a503ef58edecad11109d1ed21e793de8
82 changes: 38 additions & 44 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# This file is autogenerated by pip-compile with Python 3.8
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# make upgrade
Expand All @@ -8,30 +8,25 @@ appdirs==1.4.4
# via fs
asgiref==3.8.1
# via django
attrs==23.2.0
attrs==24.2.0
# via -r requirements/base.in
backports-zoneinfo==0.2.1 ; python_version < "3.9"
# via
# -c requirements/constraints.txt
# django
# djangorestframework
bleach==6.1.0
bleach==6.2.0
# via -r requirements/base.in
boto3==1.34.90
boto3==1.35.60
# via fs-s3fs
botocore==1.34.90
botocore==1.35.60
# via
# boto3
# s3transfer
certifi==2024.2.2
certifi==2024.8.30
# via requests
cffi==1.16.0
cffi==1.17.1
# via pynacl
charset-normalizer==3.3.2
charset-normalizer==3.4.0
# via requests
click==8.1.7
# via edx-django-utils
django==4.2.11
django==4.2.16
# via
# -c requirements/common_constraints.txt
# -r requirements/base.in
Expand All @@ -52,19 +47,21 @@ django-config-models==2.7.0
# via -r requirements/base.in
django-crum==0.7.9
# via edx-django-utils
django-filter==24.2
django-filter==24.3
# via -r requirements/base.in
django-statici18n==2.5.0
# via -r requirements/base.in
django-waffle==4.1.0
# via edx-django-utils
djangorestframework==3.15.1
djangorestframework==3.15.2
# via django-config-models
dnspython==2.7.0
# via pymongo
edx-ccx-keys==1.3.0
# via -r requirements/base.in
edx-django-utils==5.12.0
edx-django-utils==7.0.0
# via django-config-models
edx-opaque-keys[django]==2.8.0
edx-opaque-keys[django]==2.11.0
# via
# -r requirements/base.in
# edx-ccx-keys
Expand All @@ -77,7 +74,7 @@ fs-s3fs==1.1.1
# via openedx-django-pyfs
future==1.0.0
# via pyjwkest
idna==3.7
idna==3.10
# via requests
jmespath==1.0.1
# via
Expand All @@ -87,75 +84,72 @@ jsonfield==3.1.0
# via -r requirements/base.in
lazy==1.6
# via -r requirements/base.in
lxml==5.2.1
lxml==5.3.0
# via
# -r requirements/base.in
# xblock
mako==1.3.3
mako==1.3.6
# via
# -r requirements/base.in
# xblock
markupsafe==2.1.5
markupsafe==3.0.2
# via
# mako
# xblock
newrelic==9.9.0
newrelic==10.2.0
# via edx-django-utils
oauthlib==3.2.2
# via -r requirements/base.in
openedx-django-pyfs==3.6.0
openedx-django-pyfs==3.7.0
# via -r requirements/base.in
openedx-filters==1.8.1
openedx-filters==1.11.0
# via -r requirements/base.in
pbr==6.0.0
pbr==6.1.0
# via stevedore
psutil==5.9.8
psutil==6.1.0
# via edx-django-utils
pycparser==2.22
# via cffi
pycryptodomex==3.20.0
pycryptodomex==3.21.0
# via
# -r requirements/base.in
# pyjwkest
pyjwkest==1.4.2
# via -r requirements/base.in
pymongo==3.13.0
pymongo==4.10.1
# via edx-opaque-keys
pynacl==1.5.0
# via edx-django-utils
python-dateutil==2.9.0.post0
# via
# botocore
# xblock
pytz==2024.1
pytz==2024.2
# via xblock
pyyaml==6.0.1
pyyaml==6.0.2
# via xblock
requests==2.31.0
requests==2.32.3
# via pyjwkest
s3transfer==0.10.1
s3transfer==0.10.3
# via boto3
simplejson==3.19.2
simplejson==3.19.3
# via xblock
six==1.16.0
# via
# bleach
# edx-ccx-keys
# fs
# fs-s3fs
# pyjwkest
# python-dateutil
sqlparse==0.5.0
sqlparse==0.5.2
# via django
stevedore==5.2.0
stevedore==5.3.0
# via
# edx-django-utils
# edx-opaque-keys
typing-extensions==4.11.0
# via
# asgiref
# edx-opaque-keys
urllib3==1.26.18
typing-extensions==4.12.2
# via edx-opaque-keys
urllib3==1.26.20
# via
# -c requirements/constraints.txt
# botocore
Expand All @@ -164,9 +158,9 @@ web-fragments==2.2.0
# via xblock
webencodings==0.5.1
# via bleach
webob==1.8.7
webob==1.8.9
# via xblock
xblock==4.0.0
xblock==5.1.0
# via -r requirements/base.in

# The following packages are considered to be unsafe in a requirements file:
Expand Down
Loading

0 comments on commit 5beb2e1

Please sign in to comment.