Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the canvas API factory to take parameters #6927

Merged
merged 2 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lms/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ def includeme(config): # noqa: PLR0915
config.register_service_factory(
"lms.services.grouping.service_factory", name="grouping"
)
config.register_service_factory("lms.services.file.factory", name="file")
config.register_service_factory(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the new name on register_service_factory

"lms.services.file.file_service_factory", name="file"
)
config.register_service_factory(
"lms.services.jstor.service_factory", iface=JSTORService
)
Expand Down
20 changes: 19 additions & 1 deletion lms/services/canvas_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
log = logging.getLogger(__name__)


class _SectionStudentSchema(Schema):
"""Schema for each of the students that belong to a section."""

class Meta:
unknown = EXCLUDE

id = fields.Int(required=True)


class _SectionSchema(Schema):
"""
Schema for an individual course section dict.
Expand All @@ -30,6 +39,10 @@ class Meta:
id = fields.Int(required=True)
name = fields.String(required=True)

students = fields.List(
fields.Nested(_SectionStudentSchema), required=False, allow_none=True
)


class CanvasAPIClient:
"""
Expand Down Expand Up @@ -148,7 +161,7 @@ def post_load(self, data, **_kwargs):
# Return the contents of sections without the key
return data["sections"]

def course_sections(self, course_id):
def course_sections(self, course_id, with_students=False):
"""
Return all the sections for the given course_id.

Expand All @@ -159,10 +172,15 @@ def course_sections(self, course_id):
# For documentation of this request see:
# https://canvas.instructure.com/doc/api/sections.html#method.sections.index

params = {}
if with_students:
params = {"include[]": "students"}

return self._ensure_sections_unique(
self._client.send(
"GET",
f"courses/{course_id}/sections",
params=params,
schema=self._CourseSectionsSchema,
)
)
Expand Down
29 changes: 24 additions & 5 deletions lms/services/canvas_api/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,37 @@
from lms.services.canvas_api._basic import BasicClient
from lms.services.canvas_api._pages import CanvasPagesClient
from lms.services.canvas_api.client import CanvasAPIClient
from lms.services.file import file_service_factory
from lms.services.oauth2_token import oauth2_token_service_factory


def canvas_api_client_factory(_context, request):
def canvas_api_client_factory(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take both AI and user_id as new optional parameters in the factory.

_context, request, application_instance=None, user_id=None
):
"""
Get a CanvasAPIClient from a pyramid request.

:param request: Pyramid request object
:return: An instance of CanvasAPIClient
"""
application_instance = request.lti_user.application_instance
if application_instance and user_id:
oauth2_token_service = oauth2_token_service_factory(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that oauth2_token_service_factory already uses this pattern, takes AI and user_id.

_context,
request,
application_instance=application_instance,
user_id=user_id,
)
file_service = file_service_factory(_context, request, application_instance)

else:
oauth2_token_service = request.find_service(name="oauth2_token")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, use the services from the factories without parameters.

file_service = request.find_service(name="file")

if not application_instance:
application_instance = request.lti_user.application_instance

if not user_id:
user_id = request.lti_user.user_id

developer_secret = application_instance.decrypted_developer_secret(
request.find_service(AESService)
Expand All @@ -22,13 +43,11 @@ def canvas_api_client_factory(_context, request):

authenticated_api = AuthenticatedClient(
basic_client=basic_client,
oauth2_token_service=request.find_service(name="oauth2_token"),
oauth2_token_service=oauth2_token_service,
client_id=application_instance.developer_key,
client_secret=developer_secret,
redirect_uri=request.route_url("canvas_api.oauth.callback"),
)
file_service = request.find_service(name="file")

return CanvasAPIClient(
authenticated_api,
file_service=file_service,
Expand Down
9 changes: 5 additions & 4 deletions lms/services/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ def _file_search_query( # noqa: PLR0913
return query


def factory(_context, request):
return FileService(
application_instance=request.lti_user.application_instance, db=request.db
)
def file_service_factory(_context, request, application_instance=None):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Give this a better name to be imported in other modules.

if application_instance is None:
application_instance = request.lti_user.application_instance

return FileService(application_instance=application_instance, db=request.db)
Loading
Loading