change course_validation endpoint to support option to get data for only graded assignments and add ability to scroll to elements on the course outline page
This commit is contained in:
@@ -77,11 +77,10 @@ class CourseValidationViewTest(SharedModuleStoreTestCase, APITestCase):
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
expected_data = {
|
||||
'assignments': {
|
||||
'num_with_dates_before_end': 0,
|
||||
'num_with_dates': 0,
|
||||
'total_visible': 1,
|
||||
'num_with_dates_after_start': 0,
|
||||
'total_number': 1,
|
||||
'total_visible': 1,
|
||||
'assignments_with_dates_before_start': [],
|
||||
'assignments_with_dates_after_end': [],
|
||||
},
|
||||
'dates': {
|
||||
'has_start_date': True,
|
||||
@@ -99,4 +98,5 @@ class CourseValidationViewTest(SharedModuleStoreTestCase, APITestCase):
|
||||
},
|
||||
'is_self_paced': True,
|
||||
}
|
||||
|
||||
self.assertDictEqual(resp.data, expected_data)
|
||||
|
||||
@@ -33,6 +33,7 @@ class CourseValidationView(DeveloperErrorViewMixin, GenericAPIView):
|
||||
* grades
|
||||
* certificates
|
||||
* updates
|
||||
* graded_only (boolean) - whether to included graded subsections only in the assignments information.
|
||||
|
||||
**GET Response Values**
|
||||
|
||||
@@ -45,9 +46,8 @@ class CourseValidationView(DeveloperErrorViewMixin, GenericAPIView):
|
||||
* assignments
|
||||
* total_number - total number of assignments in the course.
|
||||
* total_visible - number of assignments visible to learners in the course.
|
||||
* num_with_dates - number of assignments with due dates.
|
||||
* num_with_dates_after_start - number of assignments with due dates after the start date.
|
||||
* num_with_dates_before_end - number of assignments with due dates before the end date.
|
||||
* assignments_with_dates_before_start - assignments with due dates before the start date.
|
||||
* assignments_with_dates_after_end - assignments with due dates after the end date.
|
||||
* grades
|
||||
* sum_of_weights - sum of weights for all assignments in the course (valid ones should equal 1).
|
||||
* certificates
|
||||
@@ -77,7 +77,7 @@ class CourseValidationView(DeveloperErrorViewMixin, GenericAPIView):
|
||||
)
|
||||
if get_bool_param(request, 'assignments', all_requested):
|
||||
response.update(
|
||||
assignments=self._assignments_validation(course)
|
||||
assignments=self._assignments_validation(course, request)
|
||||
)
|
||||
if get_bool_param(request, 'grades', all_requested):
|
||||
response.update(
|
||||
@@ -106,28 +106,54 @@ class CourseValidationView(DeveloperErrorViewMixin, GenericAPIView):
|
||||
has_end_date=course.end is not None,
|
||||
)
|
||||
|
||||
def _assignments_validation(self, course):
|
||||
def _assignments_validation(self, course, request):
|
||||
assignments, visible_assignments = self._get_assignments(course)
|
||||
assignments_with_dates = [a for a in visible_assignments if a.due]
|
||||
assignments_with_dates = [
|
||||
a for a in visible_assignments if a.due
|
||||
]
|
||||
|
||||
num_with_dates = len(assignments_with_dates)
|
||||
num_with_dates_after_start = (
|
||||
len([a for a in assignments_with_dates if a.due > course.start])
|
||||
assignments_with_dates_before_start = (
|
||||
[
|
||||
{'id': unicode(a.location), 'display_name': a.display_name}
|
||||
for a in assignments_with_dates
|
||||
if a.due < course.start
|
||||
]
|
||||
if self._has_start_date(course)
|
||||
else 0
|
||||
else []
|
||||
)
|
||||
num_with_dates_before_end = (
|
||||
len([a for a in assignments_with_dates if a.due < course.end])
|
||||
|
||||
assignments_with_dates_after_end = (
|
||||
[
|
||||
{'id': unicode(a.location), 'display_name': a.display_name}
|
||||
for a in assignments_with_dates
|
||||
if a.due > course.end
|
||||
]
|
||||
if course.end
|
||||
else 0
|
||||
else []
|
||||
)
|
||||
|
||||
if get_bool_param(request, 'graded_only', False):
|
||||
assignments_with_dates = [
|
||||
a
|
||||
for a in visible_assignments
|
||||
if a.due and a.graded
|
||||
]
|
||||
|
||||
assignments_with_dates_before_start = [
|
||||
{'id': unicode(a.location), 'display_name': a.display_name}
|
||||
for a in assignments_with_dates if a.due < course.start
|
||||
]
|
||||
|
||||
assignments_with_dates_after_end = [
|
||||
{'id': unicode(a.location), 'display_name': a.display_name}
|
||||
for a in assignments_with_dates if a.due > course.end
|
||||
]
|
||||
|
||||
return dict(
|
||||
total_number=len(assignments),
|
||||
total_visible=len(visible_assignments),
|
||||
num_with_dates=num_with_dates,
|
||||
num_with_dates_after_start=num_with_dates_after_start,
|
||||
num_with_dates_before_end=num_with_dates_before_end,
|
||||
assignments_with_dates_before_start=assignments_with_dates_before_start,
|
||||
assignments_with_dates_after_end=assignments_with_dates_after_end,
|
||||
)
|
||||
|
||||
def _grades_validation(self, course):
|
||||
@@ -158,7 +184,6 @@ class CourseValidationView(DeveloperErrorViewMixin, GenericAPIView):
|
||||
for section in sections
|
||||
for assignment_usage_key in section.children
|
||||
]
|
||||
|
||||
visible_sections = [
|
||||
s for s in sections
|
||||
if not s.visible_to_staff_only and not s.hide_from_toc
|
||||
|
||||
@@ -18,6 +18,18 @@ define([
|
||||
'click .button-toggle-expand-collapse': 'toggleExpandCollapse'
|
||||
},
|
||||
|
||||
/**
|
||||
* keep a running timeout counter of 5,000 milliseconds
|
||||
* for finding an element; see afterRender and scrollToElement function
|
||||
*/
|
||||
findElementPollingTimeout: 5000,
|
||||
|
||||
/**
|
||||
* used as the delay parameter to setTimeout in scrollToElement
|
||||
* function for polling for an element
|
||||
*/
|
||||
pollingDelay: 100,
|
||||
|
||||
options: {
|
||||
collapsedClass: 'is-collapsed'
|
||||
},
|
||||
@@ -90,6 +102,32 @@ define([
|
||||
return $.Deferred().resolve().promise();
|
||||
},
|
||||
|
||||
afterRender: function() {
|
||||
this.scrollToElement();
|
||||
},
|
||||
|
||||
/**
|
||||
* recursively poll for element specified by the URL fragment
|
||||
* at 100 millisecond intervals until element is found or
|
||||
* Polling is reached
|
||||
*/
|
||||
scrollToElement: function () {
|
||||
this.findElementPollingTimeout -= this.pollingDelay;
|
||||
|
||||
const elementID = window.location.hash.replace("#", "");
|
||||
|
||||
if (this.findElementPollingTimeout > 0) {
|
||||
if (elementID) {
|
||||
const element = document.getElementById(elementID);
|
||||
if (element) {
|
||||
element.scrollIntoView();
|
||||
} else {
|
||||
setTimeout(this.scrollToElement, this.pollingDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hasContent: function() {
|
||||
return this.model.hasChildren();
|
||||
},
|
||||
|
||||
@@ -97,7 +97,7 @@ if (is_proctored_exam) {
|
||||
%>
|
||||
<% if (parentInfo) { %>
|
||||
<li class="outline-item outline-<%- xblockType %> <%- visibilityClass %> is-draggable <%- includesChildren ? 'is-collapsible' : '' %> <%- isCollapsed ? 'is-collapsed' : '' %>"
|
||||
data-parent="<%- parentInfo.get('id') %>" data-locator="<%- xblockInfo.get('id') %>">
|
||||
data-parent="<%- parentInfo.get('id') %>" data-locator="<%- xblockInfo.get('id') %>" id="<%- xblockInfo.get('id') %>">
|
||||
|
||||
<span class="draggable-drop-indicator draggable-drop-indicator-before"><span class="icon fa fa-caret-right" aria-hidden="true"></span></span>
|
||||
<% if (xblockInfo.isHeaderVisible()) { %>
|
||||
|
||||
Reference in New Issue
Block a user