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

Issue/662 Add API coverage for LTI resource links #673

Merged
merged 10 commits into from
Dec 9, 2024
78 changes: 78 additions & 0 deletions canvasapi/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from canvasapi.grading_period import GradingPeriod
from canvasapi.grading_standard import GradingStandard
from canvasapi.license import License
from canvasapi.lti_resource_link import LTIResourceLink
from canvasapi.module import Module
from canvasapi.new_quiz import NewQuiz
from canvasapi.outcome_import import OutcomeImport
Expand Down Expand Up @@ -438,6 +439,41 @@

return LatePolicy(self._requester, late_policy_json["late_policy"])

def create_lti_resource_link(self, url, title=None, custom=None, **kwargs):
"""
Create a new LTI resource link.

:calls: `POST /api/v1/courses/:course_id/lti_resource_links \
<https://canvas.instructure.com/doc/api/lti_resource_links.html#method.lti/resource_links.create>`_

:param course_id: The ID of the course.
:type course_id: `int`
:param url: The launch URL for the resource link.
:type url: `str`
:param title: The title of the resource link.
:type title: `str`, optional
:param custom: Custom parameters to send to the tool.
:type custom: `dict`, optional

:rtype: :class:`canvasapi.lti_resource_link.LTIResourceLink`
"""

if not url:
raise RequiredFieldMissing("The 'url' paramter is required.")

Check warning on line 462 in canvasapi/course.py

View check run for this annotation

Codecov / codecov/patch

canvasapi/course.py#L462

Added line #L462 was not covered by tests

kwargs["url"] = url
if title:
kwargs["title"] = title
if custom:
kwargs["custom"] = custom

Check warning on line 468 in canvasapi/course.py

View check run for this annotation

Codecov / codecov/patch

canvasapi/course.py#L468

Added line #L468 was not covered by tests

response = self._requester.request(
"POST",
f"courses/{self.id}/lti_resource_links",
_kwargs=combine_kwargs(**kwargs),
)
return LTIResourceLink(self._requester, response.json())

def create_module(self, module, **kwargs):
"""
Create a new module.
Expand Down Expand Up @@ -1645,6 +1681,48 @@
_kwargs=combine_kwargs(**kwargs),
)

def get_lti_resource_link(self, lti_resource_link, **kwargs):
"""
Return details about the specified resource link.

:calls: `GET /api/v1/courses/:course_id/lti_resource_links/:id \
<https://canvas.instructure.com/doc/api/lti_resource_links.html#method.lti/resource_links.show>`_

:param lti_resource_link: The object or ID of the LTI resource link.
:type lti_resource_link: :class:`canvasapi.lti_resource_link.LTIResourceLink` or int

:rtype: :class:`canvasapi.lti_resource_link.LTIResourceLink`
"""

lti_resource_link_id = obj_or_id(
lti_resource_link, "lti_resource_link", (LTIResourceLink,)
)

response = self._requester.request(
"GET",
f"courses/{self.id}/lti_resource_links/{lti_resource_link_id}",
_kwargs=combine_kwargs(**kwargs),
)
return LTIResourceLink(self._requester, response.json())

def get_lti_resource_links(self, **kwargs):
"""
Returns all LTI resource links for this course as a PaginatedList.

:calls: `GET /api/v1/courses/:course_id/lti_resource_links \
<https://canvas.instructure.com/doc/api/lti_resource_links.html#method.lti/resource_links.index>`_

:rtype: :class:`canvasapi.paginated_list.PaginatedList`
"""

return PaginatedList(
LTIResourceLink,
self._requester,
"GET",
f"courses/{self.id}/lti_resource_links",
kwargs=combine_kwargs(**kwargs),
)

def get_migration_systems(self, **kwargs):
"""
Return a list of migration systems.
Expand Down
6 changes: 6 additions & 0 deletions canvasapi/lti_resource_link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from canvasapi.canvas_object import CanvasObject


class LTIResourceLink(CanvasObject):
def __str__(self):
return "{} ({})".format(self.url, self.title)

Check warning on line 6 in canvasapi/lti_resource_link.py

View check run for this annotation

Codecov / codecov/patch

canvasapi/lti_resource_link.py#L6

Added line #L6 was not covered by tests
48 changes: 48 additions & 0 deletions tests/fixtures/lti_resource_link.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"create_lti_resource_link": {
"method": "POST",
"endpoint": "courses/1/lti_resource_links",
"data": {
"id": 45,
"context_id": 1,
"context_type": "Course",
"context_external_tool_id": 1,
"resource_type": "assignment",
"canvas_launch_url": "https://example.instructure.com/courses/1/external_tools/retrieve?resource_link_lookup_uuid=ae43ba23-d238-49bc-ab55-ba7f79f77896",
"resource_link_uuid": "ae43ba23-d238-49bc-ab55-ba7f79f77896",
"lookup_uuid": "c522554a-d4be-49ef-b163-9c87fdc6ad6f",
"title": "Test LTI Resource Link",
"url": "https://example.com/lti/launch/content_item/123"
},
"status_code": 200
},

"get_lti_resource_link": {
"method": "GET",
"endpoint": "courses/1/lti_resource_links/45",
"data": {
"id": 45,
"title": "Test LTI Resource Link"
},
"status_code": 200
},
"list_lti_resource_links": {
"method": "GET",
"endpoint": "courses/1/lti_resource_links",
"data": [
{
"id": 45,
"title": "Test LTI Resource Link"
},
{
"id": 56,
"title": "Test LTI Resource Link 2"
},
{
"id": 67,
"title": "Test LTI Resource Link 3"
}
],
"status_code": 200
}
}
34 changes: 34 additions & 0 deletions tests/test_course.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from canvasapi.grading_standard import GradingStandard
from canvasapi.group import Group, GroupCategory
from canvasapi.license import License
from canvasapi.lti_resource_link import LTIResourceLink
from canvasapi.module import Module
from canvasapi.new_quiz import NewQuiz
from canvasapi.outcome import OutcomeGroup, OutcomeLink, OutcomeResult
Expand Down Expand Up @@ -1890,6 +1891,39 @@ def test_resolve_path_null(self, m):
self.assertIsInstance(root_folder_list[0], Folder)
self.assertEqual("course_files", root_folder_list[0].name)

# create_lti_resource_link()
def test_create_lti_resource_link(self, m):
register_uris({"lti_resource_link": ["create_lti_resource_link"]}, m)
evnt = self.course.create_lti_resource_link(
url="https://example.com/lti/launch/content_item/123",
title="Test LTI Resource Link",
)
self.assertIsInstance(evnt, LTIResourceLink)
self.assertEqual(evnt.title, "Test LTI Resource Link")
self.assertEqual(evnt.url, "https://example.com/lti/launch/content_item/123")

# get_lti_resource_links()
def test_get_lti_resource_links(self, m):
register_uris({"lti_resource_link": ["list_lti_resource_links"]}, m)

lti_resource_links = self.course.get_lti_resource_links()
lti_resource_link_list = [link for link in lti_resource_links]
self.assertEqual(len(lti_resource_link_list), 3)
self.assertIsInstance(lti_resource_link_list[0], LTIResourceLink)

# get_lti_resource_link()
def test_get_lti_resource_link(self, m):
register_uris({"lti_resource_link": ["get_lti_resource_link"]}, m)

lti_resource_link_by_id = self.course.get_lti_resource_link(45)
self.assertIsInstance(lti_resource_link_by_id, LTIResourceLink)
self.assertEqual(lti_resource_link_by_id.title, "Test LTI Resource Link")
lti_resource_link_by_obj = self.course.get_lti_resource_link(
lti_resource_link_by_id
)
self.assertIsInstance(lti_resource_link_by_obj, LTIResourceLink)
self.assertEqual(lti_resource_link_by_obj.title, "Test LTI Resource Link")


@requests_mock.Mocker()
class TestCourseNickname(unittest.TestCase):
Expand Down
Loading