Skip to content

Commit

Permalink
feat: add canvas integration support (#300)
Browse files Browse the repository at this point in the history
(cherry picked from commit 98522f7)
(cherry picked from commit 71b7ca0)
(cherry picked from commit fa70b41a1ce4177cb6d0d0c1e881fbe98cb82d48)
(cherry picked from commit d2e53c92630467444a5036bf2756ec0d0acbea66)
(cherry picked from commit 0f3333f5a3376abb989a74ce7dfe3676db28a83e)
  • Loading branch information
arslanashraf7 authored and blarghmatey committed Aug 7, 2024
1 parent c5d7507 commit c117ac5
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 4 deletions.
6 changes: 6 additions & 0 deletions lms/djangoapps/instructor/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2308,6 +2308,7 @@ def _list_instructor_tasks(request, course_id):
Internal function with common code for both DRF and and tradition views.
"""
include_canvas = request.GET.get('include_canvas') is not None
course_id = CourseKey.from_string(course_id)
params = getattr(request, 'query_params', request.POST)
problem_location_str = strip_if_string(params.get('problem_location_str', False))
Expand All @@ -2331,6 +2332,11 @@ def _list_instructor_tasks(request, course_id):
else:
# Specifying for single problem's history
tasks = task_api.get_instructor_task_history(course_id, module_state_key)
elif include_canvas:
tasks = task_api.get_running_instructor_canvas_tasks(
course_id,
user=request.user
)
else:
# If no problem or student, just get currently running tasks
tasks = task_api.get_running_instructor_tasks(course_id)
Expand Down
28 changes: 28 additions & 0 deletions lms/djangoapps/instructor_task/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,34 @@ def get_running_instructor_tasks(course_id):
return instructor_tasks.order_by('-id')


def _get_filtered_instructor_tasks(course_id, user, task_types):
"""
Returns a filtered query of InstructorTasks based on the course, user, and desired task types
"""
instructor_tasks = get_running_instructor_tasks(course_id)
now = datetime.datetime.now(pytz.utc)
filtered_tasks = InstructorTask.objects.filter(
course_id=course_id,
task_type__in=task_types,
updated__lte=now,
updated__gte=now - datetime.timedelta(days=2),
requester=user
).order_by('-updated')

return (instructor_tasks | filtered_tasks).distinct()[0:3]


def get_running_instructor_canvas_tasks(course_id, user):
"""
Returns a query of InstructorTask objects of running tasks for a given course
including canvas-specific tasks.
"""
# Inline import because we will install the plugin separately
from ol_openedx_canvas_integration.constants import CANVAS_TASK_TYPES # pylint: disable=import-error

return _get_filtered_instructor_tasks(course_id, user, CANVAS_TASK_TYPES)


def get_instructor_task_history(course_id, usage_key=None, student=None, task_type=None):
"""
Returns a query of InstructorTask objects of historical tasks for a given course,
Expand Down
14 changes: 14 additions & 0 deletions lms/djangoapps/instructor_task/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ def get_task_completion_info(instructor_task): # lint-amnesty, pylint: disable=

student = None
problem_url = None
entrance_exam_url = None
email_id = None
course_id = None
try:
task_input = json.loads(instructor_task.task_input)
except ValueError:
Expand All @@ -149,6 +151,7 @@ def get_task_completion_info(instructor_task): # lint-amnesty, pylint: disable=
problem_url = task_input.get('problem_url')
entrance_exam_url = task_input.get('entrance_exam_url')
email_id = task_input.get('email_id')
course_id = task_input.get('course_key')

if instructor_task.task_state == PROGRESS:
# special message for providing progress updates:
Expand Down Expand Up @@ -192,6 +195,17 @@ def get_task_completion_info(instructor_task): # lint-amnesty, pylint: disable=
else: # num_succeeded < num_attempted
# Translators: {action} is a past-tense verb that is localized separately. {succeeded} and {attempted} are counts. # lint-amnesty, pylint: disable=line-too-long
msg_format = _("Problem {action} for {succeeded} of {attempted} students")
elif course_id is not None:
# this reports on actions for a course as a whole
results = task_output.get('results', {})
assignments_count = results.get("assignments", 0)
grades_count = results.get("grades", 0)

msg_format = _("{grades_count} grades and {assignments_count} assignments updated or created").format(
grades_count=grades_count,
assignments_count=assignments_count,
)
succeeded = True
elif email_id is not None:
# this reports on actions on bulk emails
if num_attempted == 0:
Expand Down
3 changes: 3 additions & 0 deletions lms/static/js/instructor_dashboard/instructor_dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ such that the value can be defined later than this assignment (file load order).
}, {
constructor: window.InstructorDashboard.sections.ECommerce,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#e-commerce')
}, {
constructor: window.InstructorDashboard.sections.CanvasIntegration,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#canvas_integration')
}, {
constructor: window.InstructorDashboard.sections.Membership,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#membership')
Expand Down
15 changes: 12 additions & 3 deletions lms/static/js/instructor_dashboard/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
enableColumnReorder: false,
autoHeight: true,
rowHeight: 100,
forceFitColumns: true
forceFitColumns: true,
enableTextSelectionOnCells: true
};
columns = [
{
Expand Down Expand Up @@ -98,7 +99,14 @@
*/

name: gettext('Submitted'),
minWidth: 120
minWidth: 120,
formatter: function(row, cell, value) {
if (!value) {
return value
}
var fromNow = moment(value).fromNow()
return value.concat("<br />(", fromNow, ")")
}
}, {
id: 'duration_sec',
field: 'duration_sec',
Expand Down Expand Up @@ -492,7 +500,8 @@
enableCellNavigation: true,
enableColumnReorder: false,
rowHeight: 30,
forceFitColumns: true
forceFitColumns: true,
enableTextSelectionOnCells: true
};
columns = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<p>
<h2><%- title %></h2>
<table class="stat_table"><tr>
<%_.forEach(header, function (h) {%>
<th><%- h %></th>
<%})%>
</tr>
<%_.forEach(data, function (row) {%>
<tr>
<%_.forEach(row, function (value) {%>
<td><%- value %></td>
<%})%>
</tr>
<%})%>
</table>
</p>
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@

## Include Underscore templates
<%block name="header_extras">
% for template_name in ["cohorts", "discussions", "enrollment-code-lookup-links", "cohort-editor", "cohort-group-header", "cohort-selector", "cohort-form", "notification", "cohort-state", "divided-discussions-inline", "divided-discussions-course-wide", "cohort-discussions-category", "cohort-discussions-subcategory", "certificate-allowlist", "certificate-allowlist-editor", "certificate-bulk-allowlist", "certificate-invalidation", "membership-list-widget"]:
% for template_name in ["cohorts", "discussions", "enrollment-code-lookup-links", "cohort-editor", "cohort-group-header", "cohort-selector", "cohort-form", "notification", "cohort-state", "divided-discussions-inline", "divided-discussions-course-wide", "cohort-discussions-category", "cohort-discussions-subcategory", "certificate-allowlist", "certificate-allowlist-editor", "certificate-bulk-allowlist", "certificate-invalidation", "membership-list-widget", "html-datatable"]:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="instructor/instructor_dashboard_2/${template_name}.underscore" />
</script>
Expand Down
7 changes: 7 additions & 0 deletions xmodule/course_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,13 @@ class CourseFields: # lint-amnesty, pylint: disable=missing-class-docstring
),
scope=Scope.settings
)
canvas_course_id = Integer(
display_name=_("Canvas Course Id"),
help=_(
"The id for the corresponding course on Canvas"
),
scope=Scope.settings
)
enable_ccx = Boolean(
# Translators: Custom Courses for edX (CCX) is an edX feature for re-using course content. CCX Coach is
# a role created by a course Instructor to enable a person (the "Coach") to manage the custom course for
Expand Down

0 comments on commit c117ac5

Please sign in to comment.