### Clone Tutorial Repository - Git Source: https://docs.anthology.com/docs/blackboard/uef/Tutorials/tutorial-lti This command clones the Git repository for the tutorial. It serves as the starting point for obtaining the necessary code and project structure for migrating an LTI tool to a UEF integration. Ensure Git is installed on your system. ```git git clone https://github.com/blackboard/BBDN-UEF-Python.git ``` -------------------------------- ### Authenticated REST Call Example Source: https://docs.anthology.com/docs/blackboard/rest-apis/getting-started/basic-authentication Demonstrates how to make an authenticated GET request using the obtained access token. ```APIDOC ## GET /users ### Description Retrieves user information. Requires a valid bearer token in the authorization header. ### Method GET ### Endpoint https://yourserver/learn/api/public/v1/users ### Parameters #### Query Parameters - **query** (string) - Optional - Specifies the user query parameter (e.g., userName). ### Request Example ```bash curl -X GET -H "authorization: Bearer abcdefghijklmnopqrstuvwxyz" https://yourserver/learn/api/public/v1/users?query=userName ``` ### Response #### Success Response (200) - The structure of the user response depends on the specific query parameters used. Refer to the Learn REST API Documentation for detailed response schemas. ``` -------------------------------- ### Start ngrok Tunnel - Bash Source: https://docs.anthology.com/docs/blackboard/uef/Tutorials/tutorial-lti This command starts an ngrok HTTP tunnel on port 5000, using a specified hostname. ngrok is used to expose your local development server to the internet, which is necessary for LTI and UEF integrations to communicate with external services. This command requires ngrok to be installed and authenticated. ```bash ./ngrok http 5000 --hostname uef.ngrok.io ``` -------------------------------- ### UEF Portal Event Payload Example Source: https://docs.anthology.com/docs/blackboard/uef/uef-authentication This JSON payload illustrates a portal event from the Ultra UI, such as opening or closing a panel. It includes the event type ('new' for opening), portal-specific identifiers, and selector data. ```json { "type": "event:event", "portalId": "some-portal-id", "selector": "anonymous-element", "selectorData": { "class": "pageTitle" }, "eventType": "new" } ``` -------------------------------- ### Portal Panel Response Example Source: https://docs.anthology.com/uef-documentation/start This is an example of a 'portal:panel:response' event that is received after requesting to open a panel. It contains the portalId which is essential for rendering content. ```json { type: 'portal:panel:response', correlationId: 'panel-1', portalId: 'aaa-bbb-ccc-ddd-eee-fff', status: 'success', } ``` -------------------------------- ### Example Help Provider Registration Request Source: https://docs.anthology.com/uef-documentation/interfaces/ihelpproviderregistrationrequest An example JSON object representing a request to register a help provider. This structure is used by integrations to send registration details to the Ultra Extension Framework. ```json { "type": "help:register", "id": "integration-id", "displayName": "My New Help Provider", "providerType": "primary", "iconUrl": "https://www.blackboard.com/images/favicon.ico" } ``` -------------------------------- ### Example Registration Response (JSON) Source: https://docs.anthology.com/uef-documentation/interfaces/ioriginalityreportregistrationresponse This snippet demonstrates a successful example registration response for the IOriginalityReportRegistrationRequest. It includes the type of action, the submission service handle, and the status of the operation. ```json { "type": "submission-tool:register", "submissionServicesUniqueHandle": "tool-handle", "status": "success" } ``` -------------------------------- ### Portal Callback Event Example Source: https://docs.anthology.com/uef-documentation/start This is an example of a 'portal:callback' event, which is triggered when a specific event, like the panel closing, occurs. This event is linked via the callbackId provided during panel creation. ```json { type: 'portal:callback', callbackId: 'panel-1-close', event: 'onClose', } ``` -------------------------------- ### Send Integration Handshake Message to Learn Ultra Source: https://docs.anthology.com/uef-documentation/start This JavaScript snippet shows how an integration sends a 'hello' message to Learn Ultra to notify it of the integration's readiness. The message is posted to the parent window, targeting Ultra with a wildcard for the host. ```javascript // (1) Send the integration handshake message to Learn Ultra. This notifies Learn Ultra that the integration has loaded and is ready to communicate. window.parent.postMessage({"type": "integration:hello"}, `${__lmsHost}/*`); ``` -------------------------------- ### GET /learn/api/public/v1/calendars/items Source: https://docs.anthology.com/docs/blackboard/rest-apis/hands-on/calendar-apis Retrieves a list of calendar items. This endpoint can be filtered by calendar type and specific calendar IDs. For example, to get items for a course with ID '_12594_1'. ```APIDOC ## GET /learn/api/public/v1/calendars/items ### Description Retrieves a list of calendar items. You can specify the calendar type and calendar ID to filter the results. For example, to retrieve items for a specific course. ### Method GET ### Endpoint /learn/api/public/v1/calendars/items ### Parameters #### Query Parameters - **calendarType** (string) - Optional - Filters calendar items by type (e.g., 'Course', 'GradebookColumn', 'Institution', 'OfficeHours', 'Personal'). - **calendarId** (string) - Optional - Filters calendar items by a specific calendar ID. ### Request Example ``` GET /learn/api/public/v1/calendars/items?calendarId=_12594_1 ``` ### Response #### Success Response (200) - A list of calendar item objects, each containing details like id, calendarId, type, title, description, location, start, end, disableResizing, and recurrence. #### Response Example ```json [ { "id": "string", "calendarId": "string", "type": "Course", "title": "string", "description": "string", "location": "string", "start": "2022-09-29T20:30:04.346Z", "end": "2022-09-29T20:30:04.346Z", "disableResizing": true, "recurrence": { "count": 0, "frequency": "Monthly", "interval": 0, "monthRepeatDay": 0, "monthPosition": 0, "originalStart": "2022-09-29T20:30:04.346Z", "originalEnd": "2022-09-29T20:30:04.346Z", "repeatBroken": true, "repeatDay": "Sunday", "until": "2022-09-29T20:30:04.346Z", "weekDays": ["Sunday"] } } ] ``` ``` -------------------------------- ### Standard Course Detail Portal Structure Source: https://docs.anthology.com/uef-documentation/pages/CourseDetails This example demonstrates the standard structure for rendering a course detail portal, including a button with associated image and text elements. It utilizes specific class names provided by the Ultra Extension Framework for consistent styling within the 'Details & Actions' section of the course outline. ```json { "tag": "button", "props": { "className": "uef--button--course-details", "onClick": { "callbackId": "integration-name-callback-1" } }, "children": [ { "tag": "div", "props": { "className": "uef--course-details--image" }, "children": [ { "tag": "img", "props": { "alt": "Integration Action's Image", "src": "https://www.blackboard.com/themes/custom/blackboard/images/Blackboard-Logo.png", "height": 24, "width": 24 } }, { "tag": "div", "props": { "className": "uef--course-details--element" }, "children": [ { "tag": "div", "props": { "className": "uef--course-details--name" }, "children": "Interaction Action's Label" }, { "tag": "div", "props": { "className": "uef--course-details--content" }, "children": [ { "tag": "div", "props": { "className": "uef--course-details--link" }, "children": "Interaction Action's detail" } ] } ] } ] } ] } ``` -------------------------------- ### Registering a Course Detail Portal Source: https://docs.anthology.com/uef-documentation/pages/CourseDetails To display a Course Detail portal, you must first register with the Ultra Extension Framework by sending the 'course:detail:register' message. The framework will respond with registration details, including an ID used for subsequent messages. This section is unique as it allows multiple registrations, requiring careful use of 'selectorData' to match event responses. ```json { "message": "course:detail:register" } ``` -------------------------------- ### Example Response for GET Single Column (Assignments and Grades Service) Source: https://docs.anthology.com/docs/blackboard/lti/1.3/lti-subsystems/ags/ags-columns Example JSON response when fetching a single gradebook column that was created directly through the Assignments and Grades service. It includes additional fields like 'tag' and 'resourceId'. ```JSON { "id": "https://{learn_domain}/learn/api/v1/lti/courses/_220_1/lineItems/_1399_1", "scoreMaximum": 90, "label": "AGS Created", "tag": "AGS Created tag", "resourceId": "baaf7da8-f99a-42ca-a72f-292cfd0eb27d", "gradesReleased": true } ``` -------------------------------- ### UEF Analytics Event Payload Example Source: https://docs.anthology.com/docs/blackboard/uef/uef-authentication This is an example JSON payload for analytics events (click and hover) triggered by the Ultra UI. It includes an analytics ID, the event type, and a general event type identifier. ```json { "analyticsId": "course.outline.detailsActionButton", "eventType": "click", "type": "event:event" } ``` -------------------------------- ### Example Response for Get Course TOC Entries Source: https://docs.anthology.com/docs/blackboard/rest-apis/hands-on/course-toc This is an example JSON response when successfully retrieving the Table of Contents entries for a course. It includes details for each TOC item such as ID, course ID, label, target type, position, and configuration options. ```json { "results": [ { "id": "_10223_1", "courseId": "_907_1", "contentId": null, "label": "Home Page", "targetType": "Module", "position": 0, "launchInNewWindow": false, "isEnabled": true, "isEntryPoint": true, "allowGuests": true, "allowObservers": true }, { "id": "_10222_1", "courseId": "_907_1", "contentId": "_6674_1", "label": "Information", "targetType": "Content", "position": 1, "launchInNewWindow": false, "isEnabled": true, "isEntryPoint": false, "internalHandle": "content", "allowGuests": true, "allowObservers": true } ] } ``` -------------------------------- ### Open Course Details Panel - JavaScript Source: https://docs.anthology.com/docs/blackboard/uef/Tutorials/tutorials-course-leftnav The `openPanelCD` function posts a message to Ultra to open a new panel for displaying course details. It sets context in local storage and specifies panel properties like size, title, and close callback. ```javascript // COURSE-LEFTNAV tell Ultra to open our panel. It will send us a message back after // it does. Then we render some content there in panel-3 function openPanelCD(panelSize, data) { localStorage.setItem("context", data); localStorage.setItem("action", "SHOW_PANEL"); messageChannel.postMessage({ type: "portal:panel", correlationId: "panel-3", panelType: panelSize, panelTitle: "UEF Courses Details Demo", attributes: { onClose: { callbackId: "panel-3-close", }, }, }); } ``` -------------------------------- ### Ally Alternative Formats Implementation Example (HTML) Source: https://docs.anthology.com/docs/ally/ui-integration This comprehensive example shows how to implement alternative formats using Ally's UI API. It includes a primary download link annotated with Ally attributes ('data-ally-content-id', 'data-ally-aaas-content-hash', 'data-ally-download-url') and a secondary link that invokes the alternative formats modal using 'data-ally-invoke' and references the primary link via 'data-ally-content-ref'. ```html Original file Alternative Formats ``` -------------------------------- ### Example Response for GET Single Column (Deep Linking/Course Content) Source: https://docs.anthology.com/docs/blackboard/lti/1.3/lti-subsystems/ags/ags-columns Example JSON response when fetching a single gradebook column that was created through Deep Linking or Course Content placements. It includes details like ID, score maximum, label, and grade release status. ```JSON { "id": "https://{learn_domain}/learn/api/v1/lti/courses/_220_1/lineItems/_1398_1", "scoreMaximum": 100, "label": "Anthology Tool - Course Content Tool", "resourceLinkId": "_3713_1", "endDateTime": "2024-10-11T04:59:59.999Z", "gradesReleased": true } ``` -------------------------------- ### Register for Course Detail - JavaScript Source: https://docs.anthology.com/docs/blackboard/uef/Tutorials/tutorials-course-leftnav This snippet shows how to register for course details using the `messageChannel.postMessage` API. It sends a 'course:detail:register' message with a specific registration name. ```javascript messageChannel.postMessage({ type: "course:detail:register", registrationName: "UEF course:detail Test", }); ``` -------------------------------- ### Query Users by DataSource Source: https://docs.anthology.com/docs/blackboard/rest-apis/demo-code/curl-demo This example shows how to retrieve a list of users filtered by a specific dataSourceId using query parameters. It utilizes a GET request with an authorization token. The `fields` parameter can be used to specify which user attributes to return. ```bash curl -k -X GET -H "Authorization: Bearer bsdcojzT9i4qTaNE0T8ugEBcXE2U8jtu" https://bd-partner-a-ultra.blackboard.com/learn/api/public/v1/users?dataSourceId=_2_1 & fields=externalId,userName,studentId ``` ```bash curl -k -X GET -H "Authorization: Bearer bsdcojzT9i4qTaNE0T8ugEBcXE2U8jtu" https://bd-partner-a-ultra.blackboard.com/learn/api/public/v1/users? dataSourceId=_220_1^ & fields=externalId,userName,studentId ``` -------------------------------- ### Initiating OAuth 2.0 Authorization with PKCE (HTTP) Source: https://docs.anthology.com/docs/blackboard/rest-apis/getting-started/3lo This snippet shows how to initiate the OAuth 2.0 authorization flow using the Proof Key for Code Exchange (PKCE) extension. It includes the client ID, response type, redirect URL, and PKCE parameters `code_challenge` and `code_challenge_method`. The `S256` method is required. ```HTTP POST learn/api/public/v1/oauth2/authorizationcode?client_id=YOUR_CLIENT_ID&response_type=code&redirect_url=YOUR_URL&code_challenge=YOUR_CODE_CHALLENGE&code_challenge_method=S256 ``` -------------------------------- ### Get User Information from Names and Roles Provisioning Service Source: https://docs.anthology.com/docs/blackboard/lti/1.3/lti-subsystems/ags/ags-grades Example response object from the Names and Roles Provisioning Service (NRPS) containing user details. The 'user_id' property within the 'members' array is crucial for grade operations. ```json { "id": "https://partner-test3.blackboard.com/learn/api/v1/lti/external/namesandroles/_220_1?groups=true", "context": { "id": "c2d7fe850a8e4af2b7f6d483edea773b", "label": "adv-math-fall24", "title": "Advanced Math - Fall 2024" }, "members": [ { "status": "Active", "name": "Student Account", "given_name": "Student", "family_name": "Account", "middle_name": "", "email": "student@example.com", "user_id": "b317a895e7f64796a3fd01bb18a61d65", "lis_person_sourcedid": "student-acc", "roles": [ "http://purl.imsglobal.org/vocab/lis/v2/membership#Learner", "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Student" ], "group_enrollments": [] } ] } ``` -------------------------------- ### UEF Route Event Payload Example Source: https://docs.anthology.com/docs/blackboard/uef/uef-authentication This JSON object represents the payload for a route event in the Ultra UI. It contains the event type, route-specific data (like course ID), the name of the route, and a general event type identifier. ```json { "eventType": "route", "routeData": { "courseId": "_555_1" }, "routeName": "base.courses.peek.course.outline", "type": "event:event" } ``` -------------------------------- ### Handle Integration Hello and Authorize in JavaScript Source: https://docs.anthology.com/docs/blackboard/uef/uef-authentication This JavaScript code snippet shows how to set up a message event listener to handle the initial 'integration:hello' message from Ultra UI. Upon receiving this, it sends an 'authorization:authorize' message with a user token. It also includes the logic to subscribe to events after successful authorization. ```javascript addEventListener("message", (incomingMessage) => { // Validates if the origin of the message is indeed the learn server you're expecting if (incomingMessage.origin !== "{learn_domain}") return; // Registers the integration if (incomingMessage.data.type === "integration:hello") { // Sends the user OAuth token to be able to properly work with UEF and render information based on the user's roles incomingMessage.ports[0].postMessage({ type: "authorization:authorize", token: "token_received_from_3LO", }); } // Received only when the registration is successful if (incomingMessage.data.type === "authorization:authorize") { // Subscribes to specific events from Ultra incomingMessage.ports[0].postMessage({ type: "event:subscribe", subscriptions: [ "click", "hover", "route", "portal:new", "portal:remove", "lti:launch", ], }); } }); ``` -------------------------------- ### Register Integration with UEF using MessageChannel API Source: https://docs.anthology.com/docs/blackboard/uef/uef-authentication This snippet demonstrates how to register your integration with UEF by sending a 'integration-hello' message to the learn server's domain. It utilizes the parent.postMessage method to broadcast the message and specifies a wildcard for the target origin. ```javascript window.parent.postMessage( { type: 'integration-hello', }, `{learn-domain}/*` ); ``` -------------------------------- ### Get User Information via REST API Source: https://docs.anthology.com/docs/blackboard/lti/1.3/lti-subsystems/ags/ags-grades Example of a REST API request to retrieve user information from Blackboard Learn. This response includes the 'uuid' which is essential for posting grades. It shows fields like id, uuid, userName, and contact details. ```json { "results": [ { "id": "_702_1", "uuid": "b317a895e7f64796a3fd01bb18a61d65", "externalId": "student-acc", "dataSourceId": "_2_1", "userName": "student-acc", "created": "2023-08-04T14:43:09.623Z", "modified": "2024-09-12T15:16:23.925Z", "lastLogin": "2024-09-12T15:16:23.925Z", "institutionRoleIds": ["STUDENT"], "systemRoleIds": ["User"], "availability": { "available": "Yes" }, "name": { "given": "Student", "family": "Account", "preferredDisplayName": "GivenName" }, "contact": { "email": "student@example.com" } } ] } ``` -------------------------------- ### Make Authenticated REST Call using cURL Source: https://docs.anthology.com/docs/blackboard/rest-apis/getting-started/basic-authentication This cURL command demonstrates making an authenticated GET request to the Learn API using a previously obtained access token. The 'authorization' header is set to 'Bearer' followed by the access token. This example fetches user data based on a query parameter. ```bash curl -X GET -H "authorization: Bearer abcdefghijklmnopqrstuvwxyz" \ https://yourserver/learn/api/public/v1/users?query=userName ``` -------------------------------- ### Create a Course Calendar Item via Learn API Source: https://docs.anthology.com/docs/blackboard/rest-apis/hands-on/calendar-apis This example demonstrates how to create a calendar item for a 'Course' type using the Learn API's POST endpoint. It requires a JSON payload specifying details such as title, description, location, start and end times, and recurrence rules. The `calendarType` should be set to 'Course'. ```json { "type": "Course", "calendarId": "string", "title": "string", "description": "string", "location": "string", "start": "2022-09-29T20:30:04.346Z", "end": "2022-09-29T20:30:04.346Z", "disableResizing": true, "recurrence": { "count": 0, "frequency": "Monthly", "interval": 0, "monthRepeatDay": 0, "monthPosition": 0, "originalStart": "2022-09-29T20:30:04.346Z", "originalEnd": "2022-09-29T20:30:04.346Z", "repeatBroken": true, "repeatDay": "Sunday", "until": "2022-09-29T20:30:04.346Z", "weekDays": ["Sunday"] } } ``` -------------------------------- ### ButtonLink Element Example Source: https://docs.anthology.com/uef-documentation/interfaces/ibuttonlinkelement This example demonstrates how to create an instance of a ButtonLink element using a specific structure. It includes the tag name, properties such as the target route and CSS class, and the text content for the button. ```javascript { tag: 'ButtonLink', props: { to: 'base.integration', className: 'uef--button' }, children: 'Click me!' } ``` -------------------------------- ### Calendar Item Payload Example Source: https://docs.anthology.com/docs/blackboard/rest-apis/hands-on/calendar-apis An example JSON payload for updating a calendar item. It demonstrates the structure for various properties including recurrence settings. ```JSON { "type": "Course", "calendarId": "_12594_1", "title": "Study Group 2 Session", "description": "Meeting for Study Group 3", "location": "Castle Room 2-20", "start": "2022-09-30T16:36:40.313Z", "end": "2022-09-30T16:36:40.313Z", "modified": "2022-09-30T16:36:40.313Z", "disableResizing": true, "dynamicCalendarItemProps": { "attemptable": true, "categoryId": "string", "dateRangeLimited": true, "eventType": "string", "gradable": true }, "recurrence": { "count": 0, "frequency": "Monthly", "interval": 0, "monthRepeatDay": 0, "monthPosition": 0, "originalStart": "2022-09-30T16:36:40.313Z", "originalEnd": "2022-09-30T16:36:40.313Z", "repeatBroken": true, "repeatDay": "Sunday", "until": "2022-09-30T16:36:40.313Z", "weekDays": ["Sunday"] } } ``` -------------------------------- ### Example IAuthorizeResponse Object Source: https://docs.anthology.com/uef-documentation/interfaces/iauthorizeresponse This example demonstrates the structure of a successful IAuthorizeResponse. It is a JSON object with a 'type' property indicating the authorization action. ```json { "type": "authorization:authorize" } ``` -------------------------------- ### Listen for Messages from UEF using Event Listener Source: https://docs.anthology.com/docs/blackboard/uef/uef-authentication This code snippet shows how to set up an event listener to receive messages. It is crucial for capturing initial synchronization messages and subsequent communication from UEF after the integration has been registered. ```javascript addEventListener('message', (incomingMessage) => { // Your code here }); ``` -------------------------------- ### Example IPortalNotificationSelector Usage Source: https://docs.anthology.com/uef-documentation/interfaces/iportalnotificationselector This example demonstrates how to construct an IPortalNotificationSelector object. It specifies the type of selector and the associated value, which in this case is an analytics ID. ```json { type: 'notification:analytics:selector', value: 'some.analytics.id' } ```