Merge "Merge branch 'dev/mgp-v2'"
This commit is contained in:
commit
d9751edf53
|
@ -23,12 +23,9 @@ define [
|
|||
else
|
||||
null
|
||||
|
||||
isInPastGradingPeriodAndNotAdmin = ((assignment) ->
|
||||
GradebookHelpers.gradeIsLocked(assignment, ENV)
|
||||
)(@assignment)
|
||||
|
||||
@url = @options.change_grade_url.replace(":assignment", @assignment.id).replace(":submission", @student.id)
|
||||
@submission = $.extend {}, @student["assignment_#{@assignment.id}"],
|
||||
submission = @student["assignment_#{@assignment.id}"]
|
||||
@submission = $.extend {}, submission,
|
||||
label: "student_grading_#{@assignment.id}"
|
||||
inputName: 'submission[posted_grade]'
|
||||
assignment: @assignment
|
||||
|
@ -36,7 +33,7 @@ define [
|
|||
loading: true
|
||||
showPointsPossible: (@assignment.points_possible || @assignment.points_possible == '0') && @assignment.grading_type != "gpa_scale"
|
||||
shouldShowExcusedOption: true
|
||||
isInPastGradingPeriodAndNotAdmin: isInPastGradingPeriodAndNotAdmin
|
||||
isInPastGradingPeriodAndNotAdmin: submission.gradeLocked
|
||||
@submission["assignment_grading_type_is_#{@assignment.grading_type}"] = true
|
||||
@submission.grade = "EX" if @submission.excused
|
||||
@$el = $('<div class="use-css-transitions-for-show-hide" style="padding:0;"/>')
|
||||
|
|
|
@ -27,6 +27,9 @@ define [
|
|||
title: period.title
|
||||
startDate: new Date(period.start_date)
|
||||
endDate: new Date(period.end_date)
|
||||
# TODO: After the close_date data fixup has run, this can become:
|
||||
# `closeDate: new Date(period.close_date)`
|
||||
closeDate: new Date(period.close_date || period.end_date)
|
||||
}
|
||||
|
||||
baseDeserializeSet = (set) ->
|
||||
|
|
|
@ -14,6 +14,7 @@ define [
|
|||
title: period.title
|
||||
start_date: period.startDate
|
||||
end_date: period.endDate
|
||||
close_date: period.closeDate
|
||||
}
|
||||
grading_periods: serialized
|
||||
|
||||
|
@ -24,6 +25,9 @@ define [
|
|||
title: period.title
|
||||
startDate: new Date(period.start_date)
|
||||
endDate: new Date(period.end_date)
|
||||
# TODO: After the close_date data fixup has run, this can become:
|
||||
# `closeDate: new Date(period.close_date)`
|
||||
closeDate: new Date(period.close_date || period.end_date)
|
||||
}
|
||||
|
||||
batchUpdate: (setId, periods) ->
|
||||
|
|
|
@ -19,9 +19,9 @@ define [
|
|||
isPercent: Ember.computed.equal('assignment.grading_type', 'percent')
|
||||
isLetterGrade: Ember.computed.equal('assignment.grading_type', 'letter_grade')
|
||||
isPassFail: Ember.computed.equal('assignment.grading_type', 'pass_fail')
|
||||
isInPastGradingPeriodAndNotAdmin: ( ->
|
||||
GradebookHelpers.gradeIsLocked(@assignment, ENV)
|
||||
).property('assignment')
|
||||
isInPastGradingPeriodAndNotAdmin: (->
|
||||
@submission?.gradeLocked
|
||||
).property('submission')
|
||||
nilPointsPossible: Ember.computed.none('assignment.points_possible')
|
||||
isGpaScale: Ember.computed.equal('assignment.grading_type', 'gpa_scale')
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ define [
|
|||
'../../shared/components/ic_submission_download_dialog_component'
|
||||
'str/htmlEscape'
|
||||
'compiled/models/grade_summary/CalculationMethodContent'
|
||||
'jsx/gradebook/SubmissionStateMap'
|
||||
'jquery.instructure_date_and_time'
|
||||
], (ajax, round, userSettings, fetchAllPages, parseLinkHeader, I18n, Ember, _, tz, AssignmentDetailsDialog, AssignmentMuter, GradeCalculator, outcomeGrid, ic_submission_download_dialog, htmlEscape, CalculationMethodContent) ->
|
||||
], (ajax, round, userSettings, fetchAllPages, parseLinkHeader, I18n, Ember, _, tz, AssignmentDetailsDialog, AssignmentMuter, GradeCalculator, outcomeGrid, ic_submission_download_dialog, htmlEscape, CalculationMethodContent, SubmissionStateMap) ->
|
||||
|
||||
{get, set, setProperties} = Ember
|
||||
|
||||
|
@ -25,6 +26,9 @@ define [
|
|||
# http://emberjs.com/api/classes/Ember.ArrayController.html
|
||||
# http://emberjs.com/api/classes/Ember.ObjectController.html
|
||||
|
||||
gradingPeriodIsClosed = (gradingPeriod) ->
|
||||
new Date(gradingPeriod.close_date) < new Date()
|
||||
|
||||
studentsUniqByEnrollments = (args...)->
|
||||
hiddenNameCounter = 1
|
||||
options =
|
||||
|
@ -234,23 +238,14 @@ define [
|
|||
Ember.$.subscribe 'submissions_updated', _.bind(@updateSubmissionsFromExternal, this)
|
||||
).on('init')
|
||||
|
||||
setupAssignmentGroupsChange: (->
|
||||
Ember.$.subscribe 'assignment_group_weights_changed', _.bind(@checkWeightingScheme, this)
|
||||
setupAssignmentWeightingScheme: (->
|
||||
@set 'weightingScheme', ENV.GRADEBOOK_OPTIONS.group_weighting_scheme
|
||||
).on('init')
|
||||
|
||||
willDestroy: ->
|
||||
Ember.$.unsubscribe 'submissions_updated'
|
||||
Ember.$.unsubscribe 'assignment_group_weights_changed'
|
||||
@_super()
|
||||
|
||||
checkWeightingScheme: ({assignmentGroups})->
|
||||
ags = @get('assignment_groups')
|
||||
ags.clear()
|
||||
ags.pushObjects assignmentGroups
|
||||
|
||||
@set 'weightingScheme', ENV.GRADEBOOK_OPTIONS.group_weighting_scheme
|
||||
|
||||
updateSubmissionsFromExternal: (submissions) ->
|
||||
subs_proxy = @get('submissions')
|
||||
selected = @get('selectedSubmission')
|
||||
|
@ -308,6 +303,17 @@ define [
|
|||
assignmentSelectDefaultLabel: I18n.t "no_assignment", "No Assignment Selected"
|
||||
outcomeSelectDefaultLabel: I18n.t "no_outcome", "No Outcome Selected"
|
||||
|
||||
submissionStateMap: (
|
||||
periods = _.map get(window, 'ENV.GRADEBOOK_OPTIONS.active_grading_periods'), (gradingPeriod) =>
|
||||
_.extend({}, gradingPeriod, closed: gradingPeriodIsClosed(gradingPeriod))
|
||||
new SubmissionStateMap(
|
||||
gradingPeriodsEnabled: !!get(window, 'ENV.GRADEBOOK_OPTIONS.multiple_grading_periods_enabled')
|
||||
selectedGradingPeriodID: '0'
|
||||
gradingPeriods: periods
|
||||
isAdmin: ENV.current_user_roles && _.contains(ENV.current_user_roles, "admin")
|
||||
)
|
||||
)
|
||||
|
||||
assignment_groups: []
|
||||
|
||||
fetchAssignmentGroups: (->
|
||||
|
@ -607,6 +613,11 @@ define [
|
|||
assignmentsProxy.addObject as
|
||||
).observes('assignment_groups', 'assignment_groups.@each')
|
||||
|
||||
populateSubmissionStateMap: (->
|
||||
return unless @get('enrollments.isLoaded') && @get('assignment_groups.isLoaded')
|
||||
@submissionStateMap.setup(@get('students').toArray(), @get('assignments').toArray())
|
||||
).observes('enrollments.isLoaded', 'assignment_groups.isLoaded')
|
||||
|
||||
includeUngradedAssignments: (->
|
||||
userSettings.contextGet('include_ungraded_assignments') or false
|
||||
).property().volatile()
|
||||
|
@ -672,18 +683,20 @@ define [
|
|||
if arguments.length > 1
|
||||
@set 'selectedStudent', @get('students').findBy('id', selectedSubmission.user_id)
|
||||
@set 'selectedAssignment', @get('assignments').findBy('id', selectedSubmission.assignment_id)
|
||||
selectedSubmission
|
||||
else
|
||||
return null unless @get('selectedStudent')? and @get('selectedAssignment')?
|
||||
student = @get 'selectedStudent'
|
||||
assignment = @get 'selectedAssignment'
|
||||
sub = get student, "assignment_#{assignment.id}"
|
||||
sub or {
|
||||
selectedSubmission = sub or {
|
||||
user_id: student.id
|
||||
assignment_id: assignment.id
|
||||
hidden: !@differentiatedAssignmentVisibleToStudent(assignment, student.id)
|
||||
grade_matches_current_submission: true
|
||||
}
|
||||
submissionState = @submissionStateMap.getSubmissionState(selectedSubmission) || {}
|
||||
selectedSubmission.gradeLocked = submissionState.locked
|
||||
selectedSubmission
|
||||
).property('selectedStudent', 'selectedAssignment')
|
||||
|
||||
selectedSubmissionHidden: (->
|
||||
|
|
|
@ -73,17 +73,6 @@
|
|||
{{!-- Intentionally left empty so this scales to smaller screens --}}
|
||||
</div>
|
||||
<div class="span8">
|
||||
<div class="pad-box bottom-only">
|
||||
<button
|
||||
id="ag_weights"
|
||||
class="btn"
|
||||
{{ action 'openDialog' 'ag_weights' target=view }}
|
||||
{{ bind-attr disabled=assignment_groups.isLoading }}
|
||||
>
|
||||
{{#t 'set_group_weights'}}Set Group Weights{{/t}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pad-box bottom-only">
|
||||
<button class="btn" {{action "exportGradebookCsv"}} id="gradebook-export">
|
||||
<i class="icon-download"></i> {{#t 'download_current_scores'}}Download Current Scores (.csv){{/t}}
|
||||
|
|
|
@ -29,6 +29,7 @@ define [
|
|||
run =>
|
||||
@submission = Ember.Object.create
|
||||
grade: 'A'
|
||||
gradeLocked: false
|
||||
assignment_id: 1
|
||||
user_id: 1
|
||||
@assignment = Ember.Object.create
|
||||
|
@ -48,10 +49,8 @@ define [
|
|||
test "setting value on init", ->
|
||||
component = App.GradingCellComponent.create()
|
||||
equal(component.get('value'), '-')
|
||||
|
||||
equal(@component.get('value'), 'A')
|
||||
|
||||
|
||||
test "saveURL", ->
|
||||
equal(@component.get('saveURL'), "/api/v1/assignment/1/1")
|
||||
|
||||
|
@ -67,36 +66,12 @@ define [
|
|||
setType 'letter_grade'
|
||||
ok @component.get('isLetterGrade')
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is false when multiple grading periods are not enabled", ->
|
||||
ENV.GRADEBOOK_OPTIONS.multiple_grading_periods_enabled = false
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), false
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is false when no grading periods are in the past", ->
|
||||
ENV.GRADEBOOK_OPTIONS.latest_end_date_of_admin_created_grading_periods_in_the_past = null
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), false
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is false when current user roles are undefined", ->
|
||||
ENV.current_user_roles = null
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), false
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is false when the current user is an admin", ->
|
||||
ENV.current_user_roles = ['admin']
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), false
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is true for assignments in the previous grading period", ->
|
||||
run => @assignment.set('due_at', tz.parse("2013-10-01T09:59:00Z"))
|
||||
test "isInPastGradingPeriodAndNotAdmin is true when the submission is gradeLocked", ->
|
||||
run => @submission.set('gradeLocked', true)
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), true
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is true for assignments due exactly at the end of the previous grading period", ->
|
||||
run => @assignment.set('due_at', tz.parse("2013-10-01T10:00:00Z"))
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), true
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is false for assignments after the previous grading period", ->
|
||||
run => @assignment.set('due_at', tz.parse("2013-10-01T10:01:00Z"))
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), false
|
||||
|
||||
test "isInPastGradingPeriodAndNotAdmin is false for assignments without a due date", ->
|
||||
run => @assignment.set('due_at', null)
|
||||
test "isInPastGradingPeriodAndNotAdmin is false when the submission is not gradeLocked", ->
|
||||
run => @submission.set('gradeLocked', false)
|
||||
equal @component.get('isInPastGradingPeriodAndNotAdmin'), false
|
||||
|
||||
test "nilPointsPossible", ->
|
||||
|
|
|
@ -11,14 +11,12 @@ define [
|
|||
|
||||
App = null
|
||||
originalIsDraft = null
|
||||
originalWeightingScheme = null
|
||||
|
||||
clone = (obj) ->
|
||||
Ember.copy obj, true
|
||||
|
||||
setup = (isDraftState=false, sortOrder='assignment_group') ->
|
||||
fixtures.create()
|
||||
originalWeightingScheme = window.ENV.GRADEBOOK_OPTIONS.group_weighting_scheme
|
||||
@contextGetStub = sinon.stub(userSettings, 'contextGet')
|
||||
@contextSetStub = sinon.stub(userSettings, 'contextSet')
|
||||
@contextGetStub.withArgs('sort_grade_columns_by').returns({sortType: sortOrder})
|
||||
|
@ -36,7 +34,6 @@ define [
|
|||
})
|
||||
|
||||
teardown = ->
|
||||
window.ENV.GRADEBOOK_OPTIONS.group_weighting_scheme = originalWeightingScheme
|
||||
@contextGetStub.restore()
|
||||
@contextSetStub.restore()
|
||||
Ember.run App, 'destroy'
|
||||
|
@ -116,14 +113,6 @@ define [
|
|||
equal @srgb.get('assignments.firstObject.name'), 'Z Eats Soup'
|
||||
equal @srgb.get('assignments.lastObject.name'), 'Da Fish and Chips!'
|
||||
|
||||
test 'updates assignment groups and weightingScheme when event is triggered', ->
|
||||
window.ENV.GRADEBOOK_OPTIONS.group_weighting_scheme = 'whoa'
|
||||
Ember.run =>
|
||||
$.publish('assignment_group_weights_changed', assignmentGroups: Ember.copy(fixtures.assignment_groups, true).slice(0,1))
|
||||
|
||||
equal @srgb.get('weightingScheme'), 'whoa', 'weightingScheme was updated'
|
||||
equal @srgb.get('assignment_groups.length'), 1, 'assignment_groups was updated'
|
||||
|
||||
test 'updates assignment_visibility on an assignment', ->
|
||||
assignments = @srgb.get('assignments')
|
||||
assgn = assignments.objectAt(2)
|
||||
|
@ -194,6 +183,17 @@ define [
|
|||
_.each submission, (val, key) =>
|
||||
equal selectedSubmission[key], val, "#{key} is the expected value on selectedSubmission"
|
||||
|
||||
test 'selectedSubmission sets gradeLocked', ->
|
||||
selectedSubmission = @srgb.get('selectedSubmission')
|
||||
equal selectedSubmission.gradeLocked, false
|
||||
|
||||
test 'selectedSubmission sets gradeLocked for unassigned students', ->
|
||||
@student = @srgb.get('students')[1]
|
||||
Ember.run =>
|
||||
@srgb.set('selectedStudent', @student)
|
||||
selectedSubmission = @srgb.get('selectedSubmission')
|
||||
equal selectedSubmission.gradeLocked, true
|
||||
|
||||
module 'screenreader_gradebook_controller: with selected assignment',
|
||||
setup: ->
|
||||
setup.call this
|
||||
|
|
|
@ -247,69 +247,69 @@ define [
|
|||
students = [
|
||||
{
|
||||
user_id: '1'
|
||||
user: { id: '1', name: 'Bob' }
|
||||
user: { id: '1', name: 'Bob', group_ids: [], sections: [] }
|
||||
course_section_id: '1'
|
||||
}
|
||||
{
|
||||
user_id: '2'
|
||||
user: { id: '2', name: 'Fred' }
|
||||
user: { id: '2', name: 'Fred', group_ids: [], sections: [] }
|
||||
course_section_id: '1'
|
||||
}
|
||||
{
|
||||
user_id: '3'
|
||||
user: { id: '3', name: 'Suzy' }
|
||||
user: { id: '3', name: 'Suzy', group_ids: [], sections: [] }
|
||||
course_section_id: '1'
|
||||
}
|
||||
{
|
||||
user_id: '4'
|
||||
user: { id: '4', name: 'Buffy' }
|
||||
user: { id: '4', name: 'Buffy', group_ids: [], sections: [] }
|
||||
course_section_id: '2'
|
||||
}
|
||||
{
|
||||
user_id: '5'
|
||||
user: { id: '5', name: 'Willow' }
|
||||
user: { id: '5', name: 'Willow', group_ids: [], sections: [] }
|
||||
course_section_id: '2'
|
||||
}
|
||||
{
|
||||
user_id: '5'
|
||||
user: { id: '5', name: 'Willow' }
|
||||
user: { id: '5', name: 'Willow', group_ids: [], sections: [] }
|
||||
course_section_id: '1'
|
||||
}
|
||||
{
|
||||
user_id: '6'
|
||||
user: { id: '6', name: 'Giles' }
|
||||
user: { id: '6', name: 'Giles', group_ids: [], sections: [] }
|
||||
course_section_id: '2'
|
||||
}
|
||||
{
|
||||
user_id: '7'
|
||||
user: { id: '7', name: 'Xander' }
|
||||
user: { id: '7', name: 'Xander', group_ids: [], sections: [] }
|
||||
course_section_id: '2'
|
||||
}
|
||||
{
|
||||
user_id: '8'
|
||||
user: { id: '8', name: 'Cordelia' }
|
||||
user: { id: '8', name: 'Cordelia', group_ids: [], sections: [] }
|
||||
course_section_id: '2'
|
||||
}
|
||||
{
|
||||
user_id: '9'
|
||||
user: { id: '9', name: 'Drusilla' }
|
||||
user: { id: '9', name: 'Drusilla', group_ids: [], sections: [] }
|
||||
course_section_id: '1'
|
||||
}
|
||||
{
|
||||
user_id: '10'
|
||||
user: { id: '10', name: 'Spike' }
|
||||
user: { id: '10', name: 'Spike', group_ids: [], sections: [] }
|
||||
course_section_id: '2'
|
||||
}
|
||||
{
|
||||
user_id: '10'
|
||||
user: { id: '10', name: 'Spike' }
|
||||
user: { id: '10', name: 'Spike', group_ids: [], sections: [] }
|
||||
course_section_id: '1'
|
||||
}
|
||||
]
|
||||
|
||||
concludedStudents = [
|
||||
{
|
||||
user: { id: '105', name: 'Lyra' }
|
||||
user: { id: '105', name: 'Lyra', group_ids: [], sections: [] }
|
||||
course_section_id: '1'
|
||||
user_id: '105'
|
||||
workflow_state: 'completed'
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
define [
|
||||
'ember'
|
||||
'compiled/gradebook2/GradebookHeaderMenu'
|
||||
'compiled/gradebook2/AssignmentGroupWeightsDialog'
|
||||
'compiled/SubmissionDetailsDialog'
|
||||
], (Ember, GradebookHeaderMenu, AssignmentGroupWeightsDialog, SubmissionDetailsDialog) ->
|
||||
], (Ember, GradebookHeaderMenu, SubmissionDetailsDialog) ->
|
||||
|
||||
AssignmentsView = Ember.View.extend
|
||||
templateName: 'assignments'
|
||||
|
||||
setupDialog: (->
|
||||
@agDialog = new AssignmentGroupWeightsDialog({context: ENV.GRADEBOOK_OPTIONS, assignmentGroups:[], mergeFunction: @mergeObjects})
|
||||
).on('didInsertElement')
|
||||
|
||||
removeDialog: (->
|
||||
@agDialog.$dialog.dialog('destroy')
|
||||
).on('willDestroyElement')
|
||||
|
||||
mergeObjects: (old_ag, new_ag) ->
|
||||
Ember.setProperties(old_ag, new_ag)
|
||||
|
||||
|
@ -40,12 +31,6 @@ define [
|
|||
'submission': SubmissionDetailsDialog.open
|
||||
|
||||
switch dialogType
|
||||
when 'ag_weights'
|
||||
options =
|
||||
context: ENV.GRADEBOOK_OPTIONS
|
||||
assignmentGroups: con.get('assignment_groups').toArray()
|
||||
@agDialog.update(options)
|
||||
@agDialog.$dialog.dialog('open')
|
||||
when 'submission'
|
||||
dialogs[dialogType]?.call(this, con.get('selectedAssignment'), con.get('selectedStudent'), options)
|
||||
else
|
||||
|
|
|
@ -28,6 +28,7 @@ define [
|
|||
'str/htmlEscape'
|
||||
'jsx/gradebook/SISGradePassback/PostGradesStore'
|
||||
'jsx/gradebook/SISGradePassback/PostGradesApp'
|
||||
'jsx/gradebook/SubmissionStateMap'
|
||||
'jst/gradebook2/column_header'
|
||||
'jst/gradebook2/group_total_cell'
|
||||
'jst/gradebook2/row_student_name'
|
||||
|
@ -56,7 +57,7 @@ InputFilterView, I18n, GRADEBOOK_TRANSLATIONS, GradeCalculator, UserSettings,
|
|||
Spinner, SubmissionDetailsDialog, AssignmentGroupWeightsDialog,
|
||||
GradeDisplayWarningDialog, PostGradesFrameDialog, SubmissionCell,
|
||||
GradebookHeaderMenu, NumberCompare, htmlEscape, PostGradesStore, PostGradesApp,
|
||||
ColumnHeaderTemplate, GroupTotalCellTemplate, RowStudentNameTemplate,
|
||||
SubmissionStateMap, ColumnHeaderTemplate, GroupTotalCellTemplate, RowStudentNameTemplate,
|
||||
SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
||||
|
||||
class Gradebook
|
||||
|
@ -86,7 +87,7 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
@show_attendance = !!UserSettings.contextGet 'show_attendance'
|
||||
@include_ungraded_assignments = UserSettings.contextGet 'include_ungraded_assignments'
|
||||
@userFilterRemovedRows = []
|
||||
# preferenecs serialization causes these to always come
|
||||
# preferences serialization causes these to always come
|
||||
# from the database as strings
|
||||
@showConcludedEnrollments = @options.course_is_concluded ||
|
||||
@options.settings['show_concluded_enrollments'] == "true"
|
||||
|
@ -94,10 +95,15 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
@options.settings['show_inactive_enrollments'] == "true"
|
||||
@totalColumnInFront = UserSettings.contextGet 'total_column_in_front'
|
||||
@numberOfFrozenCols = if @totalColumnInFront then 3 else 2
|
||||
@mgpEnabled = @options.multiple_grading_periods_enabled
|
||||
@gradingPeriods = @options.active_grading_periods
|
||||
@indexedGradingPeriods = _.indexBy @gradingPeriods, 'id'
|
||||
@gradingPeriodsEnabled = @options.multiple_grading_periods_enabled
|
||||
@gradingPeriods = _.map @options.active_grading_periods, (gradingPeriod) =>
|
||||
_.extend({}, gradingPeriod, closed: @gradingPeriodIsClosed(gradingPeriod))
|
||||
@gradingPeriodToShow = @getGradingPeriodToShow()
|
||||
@submissionStateMap = new SubmissionStateMap
|
||||
gradingPeriodsEnabled: @gradingPeriodsEnabled
|
||||
selectedGradingPeriodID: @gradingPeriodToShow
|
||||
gradingPeriods: @gradingPeriods
|
||||
isAdmin: _.contains(ENV.current_user_roles, "admin")
|
||||
@gradebookColumnSizeSettings = @options.gradebook_column_size_settings
|
||||
@gradebookColumnOrderSettings = @options.gradebook_column_order_settings
|
||||
@teacherNotesNotYetLoaded = !@options.teacher_notes? || @options.teacher_notes.hidden
|
||||
|
@ -109,7 +115,7 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
$.subscribe 'currentGradingPeriod/change', @updateCurrentGradingPeriod
|
||||
|
||||
assignmentGroupsParams = { exclude_response_fields: @fieldsToExcludeFromAssignments }
|
||||
if @mgpEnabled && @gradingPeriodToShow && @gradingPeriodToShow != '0' && @gradingPeriodToShow != ''
|
||||
if @gradingPeriodsEnabled && @gradingPeriodToShow && @gradingPeriodToShow != '0' && @gradingPeriodToShow != ''
|
||||
$.extend(assignmentGroupsParams, {grading_period_id: @gradingPeriodToShow})
|
||||
|
||||
$('li.external-tools-dialog > a[data-url], button.external-tools-dialog').on 'click keyclick', (event) ->
|
||||
|
@ -122,7 +128,7 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
submissionParams =
|
||||
response_fields: ['id', 'user_id', 'url', 'score', 'grade', 'submission_type', 'submitted_at', 'assignment_id', 'grade_matches_current_submission', 'attachments', 'late', 'workflow_state', 'excused']
|
||||
exclude_response_fields: ['preview_url']
|
||||
submissionParams['grading_period_id'] = @gradingPeriodToShow if @mgpEnabled && @gradingPeriodToShow && @gradingPeriodToShow != '0' && @gradingPeriodToShow != ''
|
||||
submissionParams['grading_period_id'] = @gradingPeriodToShow if @gradingPeriodsEnabled && @gradingPeriodToShow && @gradingPeriodToShow != '0' && @gradingPeriodToShow != ''
|
||||
dataLoader = DataLoader.loadGradebookData(
|
||||
assignmentGroupsURL: @options.assignment_groups_url
|
||||
assignmentGroupsParams: assignmentGroupsParams
|
||||
|
@ -188,23 +194,8 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
filteredVisibility = assignment.assignment_visibility.filter (id) -> id != hiddenSub.user_id
|
||||
assignment.assignment_visibility = filteredVisibility
|
||||
|
||||
# dependencies - assignmentGroupsLoaded
|
||||
disableAssignmentsInClosedGradingPeriods: () ->
|
||||
closedAdminGradingPeriods = @getClosedAdminGradingPeriods()
|
||||
|
||||
if closedAdminGradingPeriods.length > 0
|
||||
assignments = @getAssignmentsInClosedGradingPeriods()
|
||||
@disabledAssignments = assignments.map (a) -> a.id
|
||||
|
||||
getClosedAdminGradingPeriods: () ->
|
||||
_.select @gradingPeriods, (gradingPeriod) =>
|
||||
@gradingPeriodIsAdmin(gradingPeriod) && @gradingPeriodIsClosed(gradingPeriod)
|
||||
|
||||
gradingPeriodIsAdmin: (gradingPeriod) ->
|
||||
!gradingPeriod.permissions.update
|
||||
|
||||
gradingPeriodIsClosed: (gradingPeriod) ->
|
||||
new Date(gradingPeriod.end_date) < new Date()
|
||||
new Date(gradingPeriod.close_date) < new Date()
|
||||
|
||||
gradingPeriodIsActive: (gradingPeriodId) ->
|
||||
activePeriodIds = _.pluck(@gradingPeriods, 'id')
|
||||
|
@ -217,18 +208,6 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
else
|
||||
@options.current_grading_period_id
|
||||
|
||||
getAssignmentsInClosedGradingPeriods: () ->
|
||||
latestEndDate = new Date(@options.latest_end_date_of_admin_created_grading_periods_in_the_past)
|
||||
#return assignments whose end date is within the latest closed's end date
|
||||
_.select @assignments, (a) =>
|
||||
@assignmentIsDueBeforeEndDate(a, latestEndDate)
|
||||
|
||||
assignmentIsDueBeforeEndDate: (assignment, gradingPeriodEndDate) ->
|
||||
if assignment.due_at
|
||||
new Date(assignment.due_at) <= gradingPeriodEndDate
|
||||
else
|
||||
false
|
||||
|
||||
onShow: ->
|
||||
$(".post-grades-button-placeholder").show()
|
||||
return if @startedInitializing
|
||||
|
@ -275,21 +254,6 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
@assignments[assignment.id] = assignment
|
||||
@postGradesStore.setGradeBookAssignments @assignments
|
||||
|
||||
@disableAssignmentsInClosedGradingPeriods() if @mgpEnabled
|
||||
|
||||
initializeSubmissionsForStudent: (student) =>
|
||||
for assignment_id, assignment of @assignments
|
||||
student["assignment_#{assignment_id}"] ?= { assignment_id: assignment_id, user_id: student.id }
|
||||
submission = student["assignment_#{assignment_id}"]
|
||||
|
||||
if @submissionOutsideOfGradingPeriod(submission, student)
|
||||
submission.hidden = true
|
||||
submission.outsideOfGradingPeriod = true
|
||||
|
||||
student.initialized = true
|
||||
@calculateStudentGrade(student)
|
||||
@grid?.invalidateRow(student.row)
|
||||
|
||||
gotSections: (sections) =>
|
||||
@sections = {}
|
||||
for section in sections
|
||||
|
@ -322,10 +286,17 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
e.type == "StudentEnrollment" || e.type == "StudentViewEnrollment"
|
||||
|
||||
setupGrading: (students) =>
|
||||
# fill in dummy submissions, so there's something there even if the
|
||||
# student didn't submit anything for that assignment
|
||||
@submissionStateMap.setup(students, @assignments)
|
||||
for student in students
|
||||
@initializeSubmissionsForStudent(student)
|
||||
for assignment_id of @assignments
|
||||
student["assignment_#{assignment_id}"] ?=
|
||||
@submissionStateMap.getSubmission student.id, assignment_id
|
||||
submissionState = @submissionStateMap.getSubmissionState(student["assignment_#{assignment_id}"])
|
||||
student["assignment_#{assignment_id}"].gradeLocked = submissionState.locked
|
||||
|
||||
student.initialized = true
|
||||
@calculateStudentGrade(student)
|
||||
@grid?.invalidateRow(student.row)
|
||||
|
||||
@setAssignmentVisibility(_.pluck(students, 'id'))
|
||||
|
||||
|
@ -634,17 +605,11 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
activeCell.row is student.row and
|
||||
activeCell.cell is cell
|
||||
#check for DA visible
|
||||
if submission.assignment_visible?
|
||||
submission.hidden = !submission.assignment_visible
|
||||
|
||||
if @submissionOutsideOfGradingPeriod(submission, student)
|
||||
submission.hidden = true
|
||||
submission.outsideOfGradingPeriod = true
|
||||
|
||||
if submission.hidden
|
||||
@updateAssignmentVisibilities(submission)
|
||||
|
||||
@updateAssignmentVisibilities(submission) unless submission.assignment_visible
|
||||
@updateSubmission(submission)
|
||||
@submissionStateMap.setSubmissionCellState(student, @assignments[submission.assignment_id], submission)
|
||||
submissionState = @submissionStateMap.getSubmissionState(submission)
|
||||
student["assignment_#{submission.assignment_id}"].gradeLocked = submissionState.locked
|
||||
@calculateStudentGrade(student)
|
||||
@grid.updateCell student.row, cell unless thisCellIsActive
|
||||
@updateRowTotals student.row
|
||||
|
@ -658,113 +623,39 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
if !@rows[row].loaded or !@rows[row].initialized
|
||||
@staticCellFormatter(row, col, '')
|
||||
else
|
||||
if submission.outsideOfGradingPeriod
|
||||
@uneditableCellOutsideOfGradingPeriodFormatter(row, col)
|
||||
else if submission.hidden
|
||||
@uneditableCellFormatter(row, col)
|
||||
else if !submission?
|
||||
@staticCellFormatter(row, col, '-')
|
||||
cellAttributes = @submissionStateMap.getSubmissionState(submission)
|
||||
if cellAttributes.hideGrade
|
||||
@lockedAndHiddenGradeCellFormatter(row, col, cellAttributes.tooltip)
|
||||
else
|
||||
assignment = @assignments[submission.assignment_id]
|
||||
student = @students[submission.user_id]
|
||||
formatterOpts =
|
||||
isLocked: cellAttributes.locked
|
||||
tooltip: cellAttributes.tooltip
|
||||
|
||||
if !assignment?
|
||||
@staticCellFormatter(row, col, '')
|
||||
else if submission.workflow_state == 'pending_review'
|
||||
(SubmissionCell[assignment.grading_type] || SubmissionCell).formatter(row, col, submission, assignment, student)
|
||||
(SubmissionCell[assignment.grading_type] || SubmissionCell).formatter(row, col, submission, assignment, student, formatterOpts)
|
||||
else if assignment.grading_type == 'points' && assignment.points_possible
|
||||
SubmissionCell.out_of.formatter(row, col, submission, assignment, student)
|
||||
SubmissionCell.out_of.formatter(row, col, submission, assignment, student, formatterOpts)
|
||||
else
|
||||
(SubmissionCell[assignment.grading_type] || SubmissionCell).formatter(row, col, submission, assignment, student)
|
||||
|
||||
indexedOverrides: =>
|
||||
@_indexedOverrides ||= (=>
|
||||
indexed = {
|
||||
studentOverrides: {},
|
||||
groupOverrides: {},
|
||||
sectionOverrides: {}
|
||||
}
|
||||
|
||||
_.each @assignments, (assignment) ->
|
||||
if assignment.has_overrides && assignment.overrides
|
||||
_.each assignment.overrides, (override) ->
|
||||
if override.student_ids
|
||||
indexed.studentOverrides[assignment.id] ?= {}
|
||||
_.each override.student_ids, (studentId) ->
|
||||
indexed.studentOverrides[assignment.id][studentId] = override
|
||||
else if sectionId = override.course_section_id
|
||||
indexed.sectionOverrides[assignment.id] ?= {}
|
||||
indexed.sectionOverrides[assignment.id][sectionId] = override
|
||||
else if groupId = override.group_id
|
||||
indexed.groupOverrides[assignment.id] ?= {}
|
||||
indexed.groupOverrides[assignment.id][groupId] = override
|
||||
|
||||
indexed
|
||||
)()
|
||||
|
||||
# depedencies: assignmentGroupsLoaded
|
||||
submissionOutsideOfGradingPeriod: (submission, student) ->
|
||||
return false unless @mgpEnabled
|
||||
selectedPeriodId = @gradingPeriodToShow
|
||||
return false if @isAllGradingPeriods(selectedPeriodId)
|
||||
|
||||
assignment = @assignments[submission.assignment_id]
|
||||
gradingPeriod = @indexedGradingPeriods[selectedPeriodId]
|
||||
effectiveDueAt = assignment.due_at
|
||||
|
||||
if assignment.has_overrides && assignment.overrides
|
||||
IDsByOverrideType = {
|
||||
"sectionOverrides": student.sections
|
||||
"groupOverrides": student.group_ids
|
||||
"studentOverrides": [student.id]
|
||||
}
|
||||
|
||||
getOverridesForType = ((typeIds, overrideType) =>
|
||||
_.map typeIds, (typeId) =>
|
||||
@indexedOverrides()[overrideType]?[assignment.id]?[typeId]).bind(this)
|
||||
|
||||
allOverridesForSubmission = _.chain(IDsByOverrideType)
|
||||
.map(getOverridesForType)
|
||||
.flatten()
|
||||
.compact()
|
||||
.value()
|
||||
|
||||
overrideDates = _.chain(allOverridesForSubmission)
|
||||
.pluck('due_at')
|
||||
.map((dateString) -> tz.parse(dateString))
|
||||
.value()
|
||||
|
||||
if overrideDates.length > 0
|
||||
nullDueAtsExist = _.any(overrideDates, (date) -> _.isNull(date))
|
||||
effectiveDueAt = if nullDueAtsExist then null else _.max(overrideDates)
|
||||
else
|
||||
return true if assignment.only_visible_to_overrides
|
||||
|
||||
showSubmission = @lastGradingPeriodAndDueAtNull(gradingPeriod, effectiveDueAt) || @dateIsInGradingPeriod(gradingPeriod, effectiveDueAt)
|
||||
!showSubmission
|
||||
|
||||
lastGradingPeriodAndDueAtNull: (gradingPeriod, dueAt) ->
|
||||
gradingPeriod.is_last && _.isNull(dueAt)
|
||||
|
||||
dateIsInGradingPeriod: (gradingPeriod, date) ->
|
||||
return false if _.isNull(date)
|
||||
startDate = tz.parse(gradingPeriod.start_date)
|
||||
endDate = tz.parse(gradingPeriod.end_date)
|
||||
startDate < date && date <= endDate
|
||||
(SubmissionCell[assignment.grading_type] || SubmissionCell).formatter(row, col, submission, assignment, student, formatterOpts)
|
||||
|
||||
staticCellFormatter: (row, col, val) ->
|
||||
"<div class='cell-content gradebook-cell'>#{htmlEscape(val)}</div>"
|
||||
|
||||
uneditableCellOutsideOfGradingPeriodFormatter: (row, col) ->
|
||||
"""
|
||||
<div class='gradebook-tooltip'>
|
||||
#{htmlEscape(I18n.t("Submission in another grading period"))}
|
||||
</div>
|
||||
<div class='cell-content gradebook-cell grayed-out cannot_edit'></div>
|
||||
"""
|
||||
|
||||
uneditableCellFormatter: (row, col) ->
|
||||
"<div class='cell-content gradebook-cell grayed-out cannot_edit'></div>"
|
||||
lockedAndHiddenGradeCellFormatter: (row, col, tooltipKey) ->
|
||||
if tooltipKey
|
||||
tooltip = GRADEBOOK_TRANSLATIONS["submission_tooltip_#{tooltipKey}"]
|
||||
"""
|
||||
<div class='gradebook-tooltip'>
|
||||
#{htmlEscape(tooltip)}
|
||||
</div>
|
||||
<div class='cell-content gradebook-cell grayed-out cannot_edit'></div>
|
||||
"""
|
||||
else
|
||||
"<div class='cell-content gradebook-cell grayed-out cannot_edit'></div>"
|
||||
|
||||
groupTotalFormatter: (row, col, val, columnDef, student) =>
|
||||
return '' unless val?
|
||||
|
@ -1084,7 +975,7 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
|
||||
initHeader: =>
|
||||
@drawSectionSelectButton() if @sections_enabled
|
||||
@drawGradingPeriodSelectButton() if @mgpEnabled
|
||||
@drawGradingPeriodSelectButton() if @gradingPeriodsEnabled
|
||||
|
||||
$settingsMenu = $('.gradebook_dropdown')
|
||||
showConcludedEnrollmentsEl = $settingsMenu.find("#show_concluded_enrollments")
|
||||
|
@ -1708,7 +1599,7 @@ SectionMenuView, GradingPeriodMenuView, GradebookKeyboardNav, ColumnArranger) ->
|
|||
currentPeriodId == "0"
|
||||
|
||||
hideAggregateColumns: ->
|
||||
return false unless @mgpEnabled
|
||||
return false unless @gradingPeriodsEnabled
|
||||
return false if @options.all_grading_periods_totals
|
||||
selectedPeriodId = @getGradingPeriodToShow()
|
||||
@isAllGradingPeriods(selectedPeriodId)
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
define [
|
||||
'jquery'
|
||||
'underscore'
|
||||
'i18n!gradebook2'
|
||||
'jsx/gradebook/grid/constants'
|
||||
], ($, _, I18n, GradebookConstants) ->
|
||||
], ($, I18n, GradebookConstants) ->
|
||||
FLASH_ERROR_CLASS: '.ic-flash-error'
|
||||
|
||||
flashMaxLengthError: () ->
|
||||
|
@ -23,11 +22,3 @@ define [
|
|||
|
||||
textareaIsLessThanOrEqualToMaxLength: (textareaLength) ->
|
||||
textareaLength <= GradebookConstants.MAX_NOTE_LENGTH
|
||||
|
||||
gradeIsLocked: (assignment, env) ->
|
||||
return false unless env.GRADEBOOK_OPTIONS.multiple_grading_periods_enabled
|
||||
return false unless env.GRADEBOOK_OPTIONS.latest_end_date_of_admin_created_grading_periods_in_the_past
|
||||
return false unless env.current_user_roles
|
||||
return false if _.contains(env.current_user_roles, "admin")
|
||||
latest_end_date = new Date(env.GRADEBOOK_OPTIONS.latest_end_date_of_admin_created_grading_periods_in_the_past)
|
||||
assignment.due_at != null && assignment.due_at <= latest_end_date
|
||||
|
|
|
@ -14,6 +14,9 @@ define ['i18n!gradebook2'], (I18n) ->
|
|||
submission_tooltip_media_recording: I18n.t("Media Recording Submission")
|
||||
submission_tooltip_online_quiz: I18n.t("Quiz Submission")
|
||||
submission_tooltip_turnitin: I18n.t('Has Turnitin score')
|
||||
submission_tooltip_not_in_any_grading_period: I18n.t("This submission is not in any grading period"),
|
||||
submission_tooltip_in_another_grading_period: I18n.t("This submission is in another grading period"),
|
||||
submission_tooltip_in_closed_grading_period: I18n.t("This submission is in a closed grading period"),
|
||||
submission_update_error: I18n.t('There was an error updating this assignment. Please refresh the page and try again.')
|
||||
submission_too_many_points_warning: I18n.t("This student was just awarded an unusually high grade.")
|
||||
submission_negative_points_warning: I18n.t("This student was just awarded negative points.")
|
||||
|
|
|
@ -72,7 +72,7 @@ define [
|
|||
validate: () ->
|
||||
{ valid: true, msg: null }
|
||||
|
||||
@formatter: (row, col, submission, assignment, student) ->
|
||||
@formatter: (row, col, submission, assignment, student, opts = {}) ->
|
||||
if submission.excused
|
||||
grade = "EX"
|
||||
else
|
||||
|
@ -85,7 +85,14 @@ define [
|
|||
if grade && assignment?.grading_type == "percent"
|
||||
grade = grade.toString() + "%"
|
||||
|
||||
this.prototype.cellWrapper(grade, {submission: submission, assignment: assignment, editable: false, student: student})
|
||||
this.prototype.cellWrapper(grade, {
|
||||
submission: submission,
|
||||
assignment: assignment,
|
||||
editable: false,
|
||||
student: student,
|
||||
isLocked: !!opts.isLocked,
|
||||
tooltip: opts.tooltip
|
||||
})
|
||||
|
||||
cellWrapper: (innerContents, options = {}) ->
|
||||
opts = $.extend({}, {
|
||||
|
@ -94,14 +101,16 @@ define [
|
|||
student: {
|
||||
isInactive: false,
|
||||
isConcluded: false,
|
||||
}
|
||||
},
|
||||
isLocked: false
|
||||
}, options)
|
||||
opts.submission ||= @opts.item[@opts.column.field]
|
||||
opts.assignment ||= @opts.column.object
|
||||
submission_type = opts.submission.submission_type if opts.submission?.submission_type || null
|
||||
specialClasses = SubmissionCell.classesBasedOnSubmission(opts.submission, opts.assignment)
|
||||
specialClasses.push("grayed-out") if opts.student.isInactive || opts.student.isConcluded
|
||||
specialClasses.push("cannot_edit") if opts.student.isConcluded
|
||||
specialClasses.push("grayed-out") if opts.student.isInactive || opts.student.isConcluded || opts.isLocked
|
||||
specialClasses.push("cannot_edit") if opts.student.isConcluded || opts.isLocked
|
||||
specialClasses.push(opts.tooltip) if opts.tooltip
|
||||
opts.editable = false if opts.student.isConcluded
|
||||
|
||||
opts.classes += ' no_grade_yet ' unless opts.submission.grade && opts.submission.workflow_state != 'pending_review'
|
||||
|
@ -114,7 +123,7 @@ define [
|
|||
|
||||
tooltipText = $.map(specialClasses, (c)-> GRADEBOOK_TRANSLATIONS["submission_tooltip_#{c}"]).join ', '
|
||||
|
||||
cellCommentHTML = if !opts.student.isConcluded
|
||||
cellCommentHTML = if !opts.student.isConcluded && !opts.isLocked
|
||||
"""
|
||||
<a href="#" data-user-id=#{opts.submission.user_id} data-assignment-id=#{opts.assignment.id} class="gradebook-cell-comment"><span class="gradebook-cell-comment-label">submission comments</span></a>
|
||||
"""
|
||||
|
@ -179,7 +188,7 @@ define [
|
|||
@$input = @$wrapper.find('input').focus().select()
|
||||
|
||||
class SubmissionCell.letter_grade extends SubmissionCell
|
||||
@formatter: (row, col, submission, assignment, student) ->
|
||||
@formatter: (row, col, submission, assignment, student, opts={}) ->
|
||||
innerContents = if submission.excused
|
||||
"EX"
|
||||
else if submission.score?
|
||||
|
@ -187,16 +196,16 @@ define [
|
|||
else
|
||||
submission.grade
|
||||
|
||||
SubmissionCell.prototype.cellWrapper(innerContents, {submission: submission, assignment: assignment, editable: false, student: student})
|
||||
SubmissionCell.prototype.cellWrapper(innerContents, {submission: submission, assignment: assignment, editable: false, student: student, isLocked: !!opts.isLocked, tooltip: opts.tooltip})
|
||||
|
||||
class SubmissionCell.gpa_scale extends SubmissionCell
|
||||
@formatter: (row, col, submission, assignment, student) ->
|
||||
@formatter: (row, col, submission, assignment, student, opts={}) ->
|
||||
innerContents = if submission.excused
|
||||
"EX"
|
||||
else
|
||||
submission.grade
|
||||
|
||||
SubmissionCell.prototype.cellWrapper(innerContents, {submission: submission, assignment: assignment, editable: false, student: student, classes: "gpa_scale_cell"})
|
||||
SubmissionCell.prototype.cellWrapper(innerContents, {submission: submission, assignment: assignment, editable: false, student: student, classes: "gpa_scale_cell", isLocked: !!opts.isLocked, tooltip: opts.tooltip})
|
||||
|
||||
class SubmissionCell.pass_fail extends SubmissionCell
|
||||
|
||||
|
@ -233,9 +242,9 @@ define [
|
|||
aria-label="#{htmlEscape cssClass}"><span class="screenreader-only">#{htmlEscape cssClass}</span>#{checkboxButtonTemplate(iconClass)}</button>
|
||||
""", options)
|
||||
|
||||
@formatter: (row, col, submission, assignment, student) ->
|
||||
@formatter: (row, col, submission, assignment, student, opts={}) ->
|
||||
return SubmissionCell.formatter.apply(this, arguments) unless submission.grade?
|
||||
pass_fail::htmlFromSubmission({ submission, assignment, editable: false})
|
||||
pass_fail::htmlFromSubmission({ submission, assignment, editable: false, isLocked: opts.isLocked, tooltip: opts.tooltip })
|
||||
|
||||
init: () ->
|
||||
@$wrapper = $(@cellWrapper())
|
||||
|
|
|
@ -566,6 +566,8 @@ class GradebooksController < ApplicationController
|
|||
:force_anonymous_grading => force_anonymous_grading?(@assignment),
|
||||
:grading_role => grading_role,
|
||||
:lti_retrieve_url => retrieve_course_external_tools_url(@context.id, assignment_id: @assignment.id, display: 'borderless'),
|
||||
:course_id => @context.id,
|
||||
:assignment_id => @assignment.id,
|
||||
}
|
||||
if [:moderator, :provisional_grader].include?(grading_role)
|
||||
env[:provisional_status_url] = api_v1_course_assignment_provisional_status_path(@context.id, @assignment.id)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
define([
|
||||
"react",
|
||||
"./createStore",
|
||||
"underscore"
|
||||
], function(createStore, _) {
|
||||
], function(React, createStore, _) {
|
||||
|
||||
var { string, shape, arrayOf } = React.PropTypes;
|
||||
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
define([
|
||||
'underscore',
|
||||
'timezone',
|
||||
'i18n!gradebook2'
|
||||
], function(_, tz, I18n) {
|
||||
|
||||
const TOOLTIP_KEYS = {
|
||||
NOT_IN_ANY_GP: "not_in_any_grading_period",
|
||||
IN_ANOTHER_GP: "in_another_grading_period",
|
||||
IN_CLOSED_GP: "in_closed_grading_period",
|
||||
NONE: null
|
||||
};
|
||||
|
||||
function visibleToStudent(assignment, student) {
|
||||
if (!assignment.only_visible_to_overrides) return true;
|
||||
return _.contains(assignment.assignment_visibility, student.id);
|
||||
}
|
||||
|
||||
function assignedToStudent(assignment, overriddenDate) {
|
||||
if (!assignment.only_visible_to_overrides) return true;
|
||||
return overriddenDate !== undefined;
|
||||
}
|
||||
|
||||
function isAllGradingPeriods(periodId) {
|
||||
return periodId === "0";
|
||||
}
|
||||
|
||||
function lastGradingPeriodAndDueAtNull(gradingPeriod, dueAt) {
|
||||
return gradingPeriod.is_last && dueAt === null;
|
||||
}
|
||||
|
||||
function dateIsInGradingPeriod(gradingPeriod, date) {
|
||||
if (date === null) return false;
|
||||
return tz.parse(gradingPeriod.start_date) < date && date <= tz.parse(gradingPeriod.end_date);
|
||||
}
|
||||
|
||||
function addStudentID(student, collection = []) {
|
||||
return collection.concat([student.id]);
|
||||
}
|
||||
|
||||
function studentIDCollections(students) {
|
||||
const sections = {};
|
||||
const groups = {};
|
||||
|
||||
students.forEach(function(student) {
|
||||
student.sections.forEach(sectionID => sections[sectionID] = addStudentID(student, sections[sectionID]));
|
||||
student.group_ids.forEach(groupID => groups[groupID] = addStudentID(student, groups[groupID]));
|
||||
});
|
||||
|
||||
return { studentIDsInSections: sections, studentIDsInGroups: groups };
|
||||
}
|
||||
|
||||
function studentIDsOnOverride(override, sections, groups) {
|
||||
if (override.student_ids) {
|
||||
return override.student_ids;
|
||||
} else if (override.course_section_id && sections[override.course_section_id]) {
|
||||
return sections[override.course_section_id];
|
||||
} else if (override.group_id && groups[override.group_id]) {
|
||||
return groups[override.group_id];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function getLatestDefinedDate(newDate, existingDate) {
|
||||
if (existingDate === undefined || newDate === null) {
|
||||
return newDate;
|
||||
} else if (existingDate !== null && newDate > existingDate) {
|
||||
return newDate;
|
||||
} else {
|
||||
return existingDate;
|
||||
}
|
||||
}
|
||||
|
||||
function indexOverrides(assignments, students) {
|
||||
const { studentIDsInSections, studentIDsInGroups } = studentIDCollections(students);
|
||||
const overrides = students.reduce(function(obj, student) {
|
||||
obj[student.id] = {};
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
_.each(assignments, function(assignment) {
|
||||
if (!assignment.has_overrides || !assignment.overrides) return;
|
||||
|
||||
assignment.overrides.forEach(function(override) {
|
||||
const studentIDs = studentIDsOnOverride(override, studentIDsInSections, studentIDsInGroups);
|
||||
|
||||
studentIDs.forEach(function(studentID) {
|
||||
overrides[studentID] = overrides[studentID] || {};
|
||||
const existingDate = overrides[studentID][assignment.id];
|
||||
const newDate = tz.parse(override.due_at);
|
||||
overrides[studentID][assignment.id] = getLatestDefinedDate(newDate, existingDate);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return overrides;
|
||||
}
|
||||
|
||||
function getGradingPeriodForDueAt(gradingPeriods, dueAt) {
|
||||
return _.find(gradingPeriods, function(period) {
|
||||
return lastGradingPeriodAndDueAtNull(period, dueAt) ||
|
||||
dateIsInGradingPeriod(period, dueAt);
|
||||
});
|
||||
}
|
||||
|
||||
function cellMapForSubmission(assignment, student, overriddenDate, gradingPeriodsEnabled, selectedGradingPeriodID, gradingPeriods, isAdmin) {
|
||||
if (!visibleToStudent(assignment, student)) {
|
||||
return { locked: true, hideGrade: true, tooltip: TOOLTIP_KEYS.NONE };
|
||||
} else if (gradingPeriodsEnabled) {
|
||||
return cellMappingsForMultipleGradingPeriods(assignment, student, overriddenDate, selectedGradingPeriodID, gradingPeriods, isAdmin);
|
||||
} else {
|
||||
return { locked: false, hideGrade: false, tooltip: TOOLTIP_KEYS.NONE };
|
||||
}
|
||||
}
|
||||
|
||||
function cellMappingsForMultipleGradingPeriods(assignment, student, overriddenDate, selectedGradingPeriodID, gradingPeriods, isAdmin) {
|
||||
const specificPeriodSelected = !isAllGradingPeriods(selectedGradingPeriodID);
|
||||
const effectiveDueAt = overriddenDate === undefined ? assignment.due_at : overriddenDate;
|
||||
const gradingPeriodForDueAt = getGradingPeriodForDueAt(gradingPeriods, effectiveDueAt);
|
||||
|
||||
if (specificPeriodSelected && visibleToStudent(assignment, student) && !assignedToStudent(assignment, overriddenDate)) {
|
||||
return { locked: true, hideGrade: true, tooltip: TOOLTIP_KEYS.NOT_IN_ANY_GP };
|
||||
} else if (specificPeriodSelected && !gradingPeriodForDueAt) {
|
||||
return { locked: true, hideGrade: true, tooltip: TOOLTIP_KEYS.NOT_IN_ANY_GP };
|
||||
} else if (specificPeriodSelected && selectedGradingPeriodID !== gradingPeriodForDueAt.id) {
|
||||
return { locked: true, hideGrade: true, tooltip: TOOLTIP_KEYS.IN_ANOTHER_GP };
|
||||
} else if (!isAdmin && (gradingPeriodForDueAt || {}).closed) {
|
||||
return { locked: true, hideGrade: false, tooltip: TOOLTIP_KEYS.IN_CLOSED_GP };
|
||||
} else {
|
||||
return { locked: false, hideGrade: false, tooltip: TOOLTIP_KEYS.NONE };
|
||||
}
|
||||
}
|
||||
|
||||
class SubmissionState {
|
||||
constructor({ gradingPeriodsEnabled, selectedGradingPeriodID, gradingPeriods, isAdmin }) {
|
||||
this.gradingPeriodsEnabled = gradingPeriodsEnabled;
|
||||
this.selectedGradingPeriodID = selectedGradingPeriodID;
|
||||
this.gradingPeriods = gradingPeriods;
|
||||
this.isAdmin = isAdmin;
|
||||
this.overrides = {};
|
||||
this.submissionCellMap = {};
|
||||
this.submissionMap = {};
|
||||
}
|
||||
|
||||
setup(students, assignments) {
|
||||
const newOverrides = indexOverrides(assignments, students);
|
||||
this.overrides = Object.assign(this.overrides, newOverrides);
|
||||
|
||||
students.forEach((student) => {
|
||||
this.submissionCellMap[student.id] = {};
|
||||
this.submissionMap[student.id] = {};
|
||||
_.each(assignments, (assignment) => {
|
||||
this.setSubmissionCellState(student, assignment, student[`assignment_${assignment.id}`]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setSubmissionCellState(student, assignment, submission = { assignment_id: assignment.id, user_id: student.id }) {
|
||||
this.submissionMap[student.id][assignment.id] = submission;
|
||||
const params = [
|
||||
assignment,
|
||||
student,
|
||||
this.overrides[student.id][assignment.id],
|
||||
this.gradingPeriodsEnabled,
|
||||
this.selectedGradingPeriodID,
|
||||
this.gradingPeriods,
|
||||
this.isAdmin
|
||||
];
|
||||
|
||||
this.submissionCellMap[student.id][assignment.id] = cellMapForSubmission(...params);
|
||||
}
|
||||
|
||||
getSubmission(user_id, assignment_id) {
|
||||
return (this.submissionMap[user_id] || {})[assignment_id];
|
||||
}
|
||||
|
||||
getSubmissionState({ user_id, assignment_id }) {
|
||||
return (this.submissionCellMap[user_id] || {})[assignment_id];
|
||||
}
|
||||
};
|
||||
|
||||
return SubmissionState;
|
||||
})
|
|
@ -11,7 +11,7 @@ define(["jquery", "i18n!gradebook_uploads", "vendor/jquery.spin"],
|
|||
dfd.resolve(uploadedGradebook)
|
||||
});
|
||||
} else if (progress.workflow_state == "failed") {
|
||||
dfd.reject(I18n.t("Invalid csv file, grades could not be updated."));
|
||||
dfd.reject(I18n.t("Invalid CSV file. Grades could not be updated."));
|
||||
} else {
|
||||
setTimeout(function() {
|
||||
$.ajaxJSON(`/api/v1/progress/${progress.id}`, "GET")
|
||||
|
|
|
@ -6,27 +6,28 @@ define([
|
|||
'jsx/shared/helpers/dateHelper',
|
||||
'jquery.instructure_misc_helpers'
|
||||
], function(React, $, axios, I18n, DateHelper) {
|
||||
const types = React.PropTypes;
|
||||
const Types = React.PropTypes;
|
||||
|
||||
let AccountGradingPeriod = React.createClass({
|
||||
propTypes: {
|
||||
period: types.shape({
|
||||
id: types.string.isRequired,
|
||||
title: types.string.isRequired,
|
||||
startDate: types.instanceOf(Date).isRequired,
|
||||
endDate: types.instanceOf(Date).isRequired
|
||||
period: Types.shape({
|
||||
id: Types.string.isRequired,
|
||||
title: Types.string.isRequired,
|
||||
startDate: Types.instanceOf(Date).isRequired,
|
||||
endDate: Types.instanceOf(Date).isRequired,
|
||||
closeDate: Types.instanceOf(Date).isRequired
|
||||
}).isRequired,
|
||||
onEdit: types.func.isRequired,
|
||||
actionsDisabled: types.bool,
|
||||
readOnly: types.bool.isRequired,
|
||||
permissions: types.shape({
|
||||
read: types.bool.isRequired,
|
||||
create: types.bool.isRequired,
|
||||
update: types.bool.isRequired,
|
||||
delete: types.bool.isRequired
|
||||
onEdit: Types.func.isRequired,
|
||||
actionsDisabled: Types.bool,
|
||||
readOnly: Types.bool.isRequired,
|
||||
permissions: Types.shape({
|
||||
read: Types.bool.isRequired,
|
||||
create: Types.bool.isRequired,
|
||||
update: Types.bool.isRequired,
|
||||
delete: Types.bool.isRequired
|
||||
}).isRequired,
|
||||
onDelete: types.func.isRequired,
|
||||
deleteGradingPeriodURL: types.string.isRequired
|
||||
onDelete: Types.func.isRequired,
|
||||
deleteGradingPeriodURL: Types.string.isRequired
|
||||
},
|
||||
|
||||
promptDeleteGradingPeriod(event) {
|
||||
|
@ -85,15 +86,18 @@ define([
|
|||
return (
|
||||
<div className="GradingPeriodList__period">
|
||||
<div className="GradingPeriodList__period__attributes grid-row">
|
||||
<div className="GradingPeriodList__period__attribute col-xs-12 col-md-8 col-lg-4">
|
||||
<div className="GradingPeriodList__period__attribute col-xs-12 col-md-8 col-lg-3">
|
||||
<span tabIndex="0" ref="title">{this.props.period.title}</span>
|
||||
</div>
|
||||
<div className="GradingPeriodList__period__attribute col-xs-12 col-md-8 col-lg-4">
|
||||
<div className="GradingPeriodList__period__attribute col-xs-12 col-md-8 col-lg-3">
|
||||
<span tabIndex="0" ref="startDate">{I18n.t("Start Date:")} {DateHelper.formatDatetimeForDisplay(this.props.period.startDate)}</span>
|
||||
</div>
|
||||
<div className="GradingPeriodList__period__attribute col-xs-12 col-md-8 col-lg-4">
|
||||
<div className="GradingPeriodList__period__attribute col-xs-12 col-md-8 col-lg-3">
|
||||
<span tabIndex="0" ref="endDate">{I18n.t("End Date:")} {DateHelper.formatDatetimeForDisplay(this.props.period.endDate)}</span>
|
||||
</div>
|
||||
<div className="GradingPeriodList__period__attribute col-xs-12 col-md-8 col-lg-3">
|
||||
<span tabIndex="0" ref="closeDate">{I18n.t("Close Date:")} {DateHelper.formatDatetimeForDisplay(this.props.period.closeDate)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="GradingPeriodList__period__actions">
|
||||
{this.renderEditButton()}
|
||||
|
|
|
@ -6,33 +6,70 @@ define([
|
|||
'jsx/due_dates/DueDateCalendarPicker',
|
||||
'jsx/shared/helpers/accessibleDateFormat'
|
||||
], function(React, ReactDOM, _, I18n, DueDateCalendarPicker, accessibleDateFormat) {
|
||||
const types = React.PropTypes;
|
||||
const update = React.addons.update;
|
||||
const Types = React.PropTypes;
|
||||
|
||||
const buildPeriod = function(attr) {
|
||||
return {
|
||||
id: attr.id,
|
||||
title: attr.title,
|
||||
startDate: attr.startDate || new Date(''),
|
||||
endDate: attr.endDate || new Date('')
|
||||
startDate: attr.startDate,
|
||||
endDate: attr.endDate,
|
||||
closeDate: attr.closeDate
|
||||
};
|
||||
};
|
||||
|
||||
const hasDistinctCloseDate = ({ endDate, closeDate }) => {
|
||||
return closeDate && !_.isEqual(endDate, closeDate);
|
||||
};
|
||||
|
||||
const mergePeriod = (form, attr) => {
|
||||
return update(form.state.period, {$merge: attr});
|
||||
}
|
||||
|
||||
const changeTitle = function(e) {
|
||||
let period = mergePeriod(this, {title: e.target.value});
|
||||
this.setState({period: period});
|
||||
};
|
||||
|
||||
const changeStartDate = function(date) {
|
||||
let period = mergePeriod(this, {startDate: date});
|
||||
this.setState({period: period});
|
||||
};
|
||||
|
||||
const changeEndDate = function(date) {
|
||||
let attr = {endDate: date};
|
||||
if (!this.state.preserveCloseDate && !hasDistinctCloseDate(this.state.period)) {
|
||||
attr.closeDate = date;
|
||||
}
|
||||
let period = mergePeriod(this, attr);
|
||||
this.setState({period: period});
|
||||
};
|
||||
|
||||
const changeCloseDate = function(date) {
|
||||
let period = mergePeriod(this, {closeDate: date});
|
||||
this.setState({period: period, preserveCloseDate: !!date});
|
||||
};
|
||||
|
||||
let GradingPeriodForm = React.createClass({
|
||||
propTypes: {
|
||||
period: types.shape({
|
||||
id: types.string.isRequired,
|
||||
title: types.string.isRequired,
|
||||
startDate: types.instanceOf(Date).isRequired,
|
||||
endDate: types.instanceOf(Date).isRequired
|
||||
period: Types.shape({
|
||||
id: Types.string.isRequired,
|
||||
title: Types.string.isRequired,
|
||||
startDate: Types.instanceOf(Date).isRequired,
|
||||
endDate: Types.instanceOf(Date).isRequired,
|
||||
closeDate: Types.instanceOf(Date).isRequired
|
||||
}),
|
||||
disabled: types.bool.isRequired,
|
||||
onSave: types.func.isRequired,
|
||||
onCancel: types.func.isRequired
|
||||
disabled: Types.bool.isRequired,
|
||||
onSave: Types.func.isRequired,
|
||||
onCancel: Types.func.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
let period = buildPeriod(this.props.period || {});
|
||||
return {
|
||||
period: buildPeriod(this.props.period || {})
|
||||
period: period,
|
||||
preserveCloseDate: hasDistinctCloseDate(period)
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -56,7 +93,7 @@ define([
|
|||
className='ic-Input'
|
||||
title={I18n.t('Grading Period Title')}
|
||||
defaultValue={this.state.period.title}
|
||||
onChange={this.changeTitle}
|
||||
onChange={changeTitle.bind(this)}
|
||||
type='text'/>
|
||||
</div>
|
||||
|
||||
|
@ -73,7 +110,7 @@ define([
|
|||
<DueDateCalendarPicker dateValue = {this.state.period.startDate}
|
||||
ref = "startDate"
|
||||
dateType = "due_at"
|
||||
handleUpdate = {this.changeStartDate}
|
||||
handleUpdate = {changeStartDate.bind(this)}
|
||||
rowKey = "start-date"
|
||||
labelledBy = "start-date" />
|
||||
</div>
|
||||
|
@ -87,12 +124,24 @@ define([
|
|||
<DueDateCalendarPicker dateValue = {this.state.period.endDate}
|
||||
ref = "endDate"
|
||||
dateType = "due_at"
|
||||
handleUpdate = {this.changeEndDate}
|
||||
handleUpdate = {changeEndDate.bind(this)}
|
||||
rowKey = "end-date"
|
||||
labelledBy = "end-date" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ic-Form-control">
|
||||
<label className="ic-Label" htmlFor="close-date">
|
||||
{I18n.t("Close Date")}
|
||||
</label>
|
||||
<DueDateCalendarPicker dateValue = {this.state.period.closeDate}
|
||||
ref = "closeDate"
|
||||
dateType = "due_at"
|
||||
handleUpdate = {changeCloseDate.bind(this)}
|
||||
rowKey = "close-date"
|
||||
labelledBy = "close-date" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -124,24 +173,6 @@ define([
|
|||
);
|
||||
},
|
||||
|
||||
changeTitle: function(e) {
|
||||
let period = _.clone(this.state.period);
|
||||
period.title = e.target.value;
|
||||
this.setState({period: period});
|
||||
},
|
||||
|
||||
changeStartDate: function(date) {
|
||||
let period = _.clone(this.state.period);
|
||||
period.startDate = date;
|
||||
this.setState({period: period});
|
||||
},
|
||||
|
||||
changeEndDate: function(date) {
|
||||
let period = _.clone(this.state.period);
|
||||
period.endDate = date;
|
||||
this.setState({period: period});
|
||||
},
|
||||
|
||||
triggerSave: function() {
|
||||
if (this.props.onSave) {
|
||||
this.props.onSave(this.state.period);
|
||||
|
|
|
@ -38,21 +38,31 @@ define([
|
|||
}
|
||||
|
||||
let validDates = _.all(periods, (period) => {
|
||||
return isValidDate(period.startDate) && isValidDate(period.endDate);
|
||||
return isValidDate(period.startDate) &&
|
||||
isValidDate(period.endDate) &&
|
||||
isValidDate(period.closeDate);
|
||||
});
|
||||
|
||||
if (!validDates) {
|
||||
return [I18n.t('All dates fields must be present and formatted correctly')];
|
||||
}
|
||||
|
||||
let orderedDates = _.all(periods, (period) => {
|
||||
let orderedStartAndEndDates = _.all(periods, (period) => {
|
||||
return period.startDate < period.endDate;
|
||||
});
|
||||
|
||||
if (!orderedDates) {
|
||||
if (!orderedStartAndEndDates) {
|
||||
return [I18n.t('All start dates must be before the end date')];
|
||||
}
|
||||
|
||||
let orderedEndAndCloseDates = _.all(periods, (period) => {
|
||||
return period.endDate <= period.closeDate;
|
||||
});
|
||||
|
||||
if (!orderedEndAndCloseDates) {
|
||||
return [I18n.t('All close dates must be on or after the end date')];
|
||||
}
|
||||
|
||||
if (anyPeriodsOverlap(periods)) {
|
||||
return [I18n.t('Grading periods must not overlap')];
|
||||
}
|
||||
|
|
|
@ -7,21 +7,22 @@ define([
|
|||
'jsx/grading/gradingPeriodTemplate',
|
||||
'jsx/shared/helpers/dateHelper'
|
||||
], function(tz, React, $, I18n, _, GradingPeriodTemplate, DateHelper) {
|
||||
var types = React.PropTypes;
|
||||
var Types = React.PropTypes;
|
||||
|
||||
var GradingPeriod = React.createClass({
|
||||
propTypes: {
|
||||
title: types.string.isRequired,
|
||||
startDate: types.instanceOf(Date).isRequired,
|
||||
endDate: types.instanceOf(Date).isRequired,
|
||||
id: types.string.isRequired,
|
||||
updateGradingPeriodCollection: types.func.isRequired,
|
||||
onDeleteGradingPeriod: types.func.isRequired,
|
||||
disabled: types.bool.isRequired,
|
||||
readOnly: types.bool.isRequired,
|
||||
permissions: types.shape({
|
||||
update: types.bool.isRequired,
|
||||
delete: types.bool.isRequired,
|
||||
title: Types.string.isRequired,
|
||||
startDate: Types.instanceOf(Date).isRequired,
|
||||
endDate: Types.instanceOf(Date).isRequired,
|
||||
closeDate: Types.instanceOf(Date).isRequired,
|
||||
id: Types.string.isRequired,
|
||||
updateGradingPeriodCollection: Types.func.isRequired,
|
||||
onDeleteGradingPeriod: Types.func.isRequired,
|
||||
disabled: Types.bool.isRequired,
|
||||
readOnly: Types.bool.isRequired,
|
||||
permissions: Types.shape({
|
||||
update: Types.bool.isRequired,
|
||||
delete: Types.bool.isRequired,
|
||||
}).isRequired
|
||||
},
|
||||
|
||||
|
@ -82,6 +83,7 @@ define([
|
|||
title={this.props.title}
|
||||
startDate={this.props.startDate}
|
||||
endDate={this.props.endDate}
|
||||
closeDate={this.props.closeDate || this.props.endDate}
|
||||
permissions={this.props.permissions}
|
||||
disabled={this.props.disabled}
|
||||
readOnly={this.props.readOnly}
|
||||
|
|
|
@ -14,10 +14,6 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
return state.periods !== null;
|
||||
};
|
||||
|
||||
const canAddPeriods = (state) => {
|
||||
return !state.readOnly && state.canAddNewPeriods;
|
||||
};
|
||||
|
||||
let GradingPeriodCollection = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
|
@ -30,7 +26,6 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
readOnly: false,
|
||||
disabled: false,
|
||||
saveDisabled: true,
|
||||
canAddNewPeriods: false,
|
||||
canChangeGradingPeriodsSetting: false
|
||||
};
|
||||
},
|
||||
|
@ -46,7 +41,6 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
self.setState({
|
||||
periods: self.deserializePeriods(periods),
|
||||
readOnly: periods.grading_periods_read_only,
|
||||
canAddNewPeriods: periods.can_create_grading_periods,
|
||||
canChangeGradingPeriodsSetting: periods.can_toggle_grading_periods,
|
||||
disabled: false,
|
||||
saveDisabled: _.isEmpty(periods.grading_periods)
|
||||
|
@ -62,17 +56,11 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
let newPeriod = ConvertCase.camelize(period);
|
||||
newPeriod.startDate = new Date(period.start_date);
|
||||
newPeriod.endDate = new Date(period.end_date);
|
||||
newPeriod.closeDate = new Date(period.close_date || period.end_date);
|
||||
return newPeriod;
|
||||
});
|
||||
},
|
||||
|
||||
componentDidUpdate: function(prevProps, prevState) {
|
||||
if (prevState.periods) {
|
||||
let removedAGradingPeriod = this.state.periods.length < prevState.periods.length;
|
||||
if (removedAGradingPeriod && this.refs.addPeriodButton) this.refs.addPeriodButton.focus();
|
||||
}
|
||||
},
|
||||
|
||||
deleteGradingPeriod: function(id) {
|
||||
if (id.indexOf('new') > -1) {
|
||||
this.removeDeletedGradingPeriod(id);
|
||||
|
@ -105,29 +93,6 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
this.setState({periods: newPeriods});
|
||||
},
|
||||
|
||||
getCreateGradingPeriodCSS: function() {
|
||||
let cssClasses = 'center-md new-grading-period pad-box border border-round';
|
||||
if (!this.state.periods || this.state.periods.length === 0) {
|
||||
cssClasses += ' no-active-grading-periods';
|
||||
}
|
||||
|
||||
return cssClasses;
|
||||
},
|
||||
|
||||
createNewGradingPeriod: function() {
|
||||
if (!this.state.readOnly && this.state.canAddNewPeriods) {
|
||||
let newPeriod = {
|
||||
title: '',
|
||||
startDate: new Date(''),
|
||||
endDate: new Date(''),
|
||||
id: _.uniqueId('new'),
|
||||
permissions: { read: true, update: true, delete: true}
|
||||
};
|
||||
let periods = update(this.state.periods, {$push: [newPeriod]});
|
||||
this.setState({periods: periods, saveDisabled: false});
|
||||
}
|
||||
},
|
||||
|
||||
getPeriodById: function(id) {
|
||||
return _.find(this.state.periods, period => period.id === id);
|
||||
},
|
||||
|
@ -246,7 +211,7 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
},
|
||||
|
||||
renderSaveButton: function() {
|
||||
if (periodsAreLoaded(this.state) && !this.state.readOnly && _.all(this.state.periods, period => period.permissions.update || period.permissions.create)) {
|
||||
if (periodsAreLoaded(this.state) && !this.state.readOnly && _.all(this.state.periods, period => period.permissions.update)) {
|
||||
let buttonText = this.state.disabled ? I18n.t('Updating') : I18n.t('Save');
|
||||
return (
|
||||
<div className='form-actions'>
|
||||
|
@ -271,6 +236,7 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
title={period.title}
|
||||
startDate={period.startDate}
|
||||
endDate={period.endDate}
|
||||
closeDate={period.closeDate}
|
||||
permissions={period.permissions}
|
||||
readOnly={this.state.readOnly}
|
||||
disabled={this.state.disabled}
|
||||
|
@ -281,20 +247,6 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
});
|
||||
},
|
||||
|
||||
renderAddPeriodButton: function() {
|
||||
if (periodsAreLoaded(this.state) && canAddPeriods(this.state)) {
|
||||
return (
|
||||
<div className={this.getCreateGradingPeriodCSS()}>
|
||||
<button id='add-period-button' className='Button--link' ref='addPeriodButton'
|
||||
onClick={this.createNewGradingPeriod} disabled={this.state.disabled}>
|
||||
<i className='icon-plus grading-period-add-icon'/>
|
||||
{I18n.t('Add Grading Period')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return (
|
||||
<div>
|
||||
|
@ -304,7 +256,6 @@ function(React, GradingPeriod, $, I18n, _, ConvertCase) {
|
|||
<div id='grading_periods' className='content-box'>
|
||||
{this.renderGradingPeriods()}
|
||||
</div>
|
||||
{this.renderAddPeriodButton()}
|
||||
{this.renderSaveButton()}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -8,23 +8,52 @@ define([
|
|||
'jsx/shared/helpers/dateHelper',
|
||||
'jquery.instructure_date_and_time'
|
||||
], function(tz, React, ReactDOM, $, I18n, _, DateHelper) {
|
||||
const types = React.PropTypes;
|
||||
const Types = React.PropTypes;
|
||||
|
||||
const postfixId = (text, { props }) => {
|
||||
return text + props.id;
|
||||
};
|
||||
|
||||
const isEditable = ({ props }) => {
|
||||
return props.permissions.update && !props.readOnly;
|
||||
};
|
||||
|
||||
const tabbableDate = (ref, date) => {
|
||||
let formattedDate = DateHelper.formatDatetimeForDisplay(date);
|
||||
return <span ref={ref} className="GradingPeriod__Action" tabIndex="0">{ formattedDate }</span>;
|
||||
};
|
||||
|
||||
const renderActions = ({ props, onDeleteGradingPeriod }) => {
|
||||
if (props.permissions.delete && !props.readOnly) {
|
||||
let cssClasses = "Button Button--icon-action icon-delete-grading-period";
|
||||
if (props.disabled) cssClasses += " disabled";
|
||||
return (
|
||||
<div className="GradingPeriod__Actions content-box">
|
||||
<button ref="deleteButton"
|
||||
role="button"
|
||||
className={cssClasses}
|
||||
aria-disabled={props.disabled}
|
||||
onClick={onDeleteGradingPeriod}>
|
||||
<i className="icon-x icon-delete-grading-period"/>
|
||||
<span className="screenreader-only">{I18n.t("Delete grading period")}</span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let GradingPeriodTemplate = React.createClass({
|
||||
propTypes: {
|
||||
title: types.string.isRequired,
|
||||
startDate: types.instanceOf(Date).isRequired,
|
||||
endDate: types.instanceOf(Date).isRequired,
|
||||
id: types.string.isRequired,
|
||||
permissions: types.shape({
|
||||
update: types.bool.isRequired,
|
||||
delete: types.bool.isRequired,
|
||||
title: Types.string.isRequired,
|
||||
startDate: Types.instanceOf(Date).isRequired,
|
||||
endDate: Types.instanceOf(Date).isRequired,
|
||||
closeDate: Types.instanceOf(Date).isRequired,
|
||||
id: Types.string.isRequired,
|
||||
permissions: Types.shape({
|
||||
update: Types.bool.isRequired,
|
||||
delete: Types.bool.isRequired,
|
||||
}).isRequired,
|
||||
readOnly: types.bool.isRequired,
|
||||
readOnly: Types.bool.isRequired,
|
||||
requiredPropsIfEditable: function(props) {
|
||||
if (!props.permissions.update && !props.permissions.delete) return;
|
||||
|
||||
|
@ -68,34 +97,17 @@ define([
|
|||
},
|
||||
|
||||
onDeleteGradingPeriod: function() {
|
||||
this.props.onDeleteGradingPeriod(this.props.id);
|
||||
},
|
||||
|
||||
renderDeleteButton: function() {
|
||||
if (!this.props.permissions.delete || this.props.readOnly) return null;
|
||||
let cssClasses = "Button Button--icon-action icon-delete-grading-period";
|
||||
if (this.props.disabled) cssClasses += " disabled";
|
||||
return (
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3 manage-buttons-container">
|
||||
<div className="content-box">
|
||||
<div className="buttons-grid-row grid-row">
|
||||
<div className="col-xs">
|
||||
<button ref="deleteButton" role="button" className={cssClasses} onClick={this.onDeleteGradingPeriod}>
|
||||
<i className="icon-x icon-delete-grading-period"/>
|
||||
<span className="screenreader-only">{I18n.t("Delete grading period")}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
if (!this.props.disabled) {
|
||||
this.props.onDeleteGradingPeriod(this.props.id);
|
||||
}
|
||||
},
|
||||
|
||||
renderTitle: function() {
|
||||
if (this.props.permissions.update && !this.props.readOnly) {
|
||||
if (isEditable(this)) {
|
||||
return (
|
||||
<input id={postfixId("period_title_", this)}
|
||||
type="text"
|
||||
className="GradingPeriod__Detail ic-Input"
|
||||
onChange={this.props.onTitleChange}
|
||||
value={this.props.title}
|
||||
disabled={this.props.disabled}
|
||||
|
@ -103,38 +115,40 @@ define([
|
|||
);
|
||||
} else {
|
||||
return (
|
||||
<div id={postfixId("period_title_", this)} ref="title">
|
||||
{this.props.title}
|
||||
<div>
|
||||
<span className="screenreader-only">{I18n.t("Grading Period Name")}</span>
|
||||
<span ref="title" tabIndex="0">{this.props.title}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
renderStartDate: function() {
|
||||
if (this.props.permissions.update && !this.props.readOnly) {
|
||||
if (isEditable(this)) {
|
||||
return (
|
||||
<input id={postfixId("period_start_date_", this)}
|
||||
type="text"
|
||||
ref="startDate"
|
||||
name="startDate"
|
||||
className="input-grading-period-date date_field"
|
||||
className="GradingPeriod__Detail ic-Input input-grading-period-date date_field"
|
||||
defaultValue={DateHelper.formatDatetimeForDisplay(this.props.startDate)}
|
||||
disabled={this.props.disabled}/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div id={postfixId("period_start_date_", this)} ref="startDate">
|
||||
{DateHelper.formatDatetimeForDisplay(this.props.startDate)}
|
||||
<div>
|
||||
<span className="screenreader-only">{I18n.t("Start Date")}</span>
|
||||
{ tabbableDate("startDate", this.props.startDate) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
renderEndDate: function() {
|
||||
if (this.props.permissions.update && !this.props.readOnly) {
|
||||
if (isEditable(this)) {
|
||||
return (
|
||||
<input id={postfixId("period_end_date_", this)} type="text"
|
||||
className="input-grading-period-date date_field"
|
||||
className="GradingPeriod__Detail ic-Input input-grading-period-date date_field"
|
||||
ref="endDate"
|
||||
name="endDate"
|
||||
defaultValue={DateHelper.formatDatetimeForDisplay(this.props.endDate)}
|
||||
|
@ -142,37 +156,57 @@ define([
|
|||
);
|
||||
} else {
|
||||
return (
|
||||
<div id={postfixId("period_end_date_", this)} ref="endDate">
|
||||
{DateHelper.formatDatetimeForDisplay(this.props.endDate)}
|
||||
<div>
|
||||
<span className="screenreader-only">{I18n.t("End Date")}</span>
|
||||
{ tabbableDate("endDate", this.props.endDate) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
renderCloseDate: function() {
|
||||
let closeDate = isEditable(this) ? this.props.endDate : this.props.closeDate;
|
||||
return (
|
||||
<div>
|
||||
<span className="screenreader-only">{I18n.t("Close Date")}</span>
|
||||
{ tabbableDate("closeDate", closeDate || this.props.endDate) }
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return (
|
||||
<div id={postfixId("grading-period-", this)} className="grading-period pad-box-mini border border-trbl border-round">
|
||||
<div className="grid-row pad-box-micro">
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3">
|
||||
<label htmlFor={postfixId("period_title_", this)}>
|
||||
{I18n.t("Grading Period Name")}
|
||||
</label>
|
||||
{this.renderTitle()}
|
||||
<div className="GradingPeriod__Details pad-box-micro">
|
||||
<div className="grid-row">
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3">
|
||||
<label className="ic-Label" htmlFor={postfixId("period_title_", this)}>
|
||||
{I18n.t("Grading Period Name")}
|
||||
</label>
|
||||
{this.renderTitle()}
|
||||
</div>
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3">
|
||||
<label className="ic-Label" htmlFor={postfixId("period_start_date_", this)}>
|
||||
{I18n.t("Start Date")}
|
||||
</label>
|
||||
{this.renderStartDate()}
|
||||
</div>
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3">
|
||||
<label className="ic-Label" htmlFor={postfixId("period_end_date_", this)}>
|
||||
{I18n.t("End Date")}
|
||||
</label>
|
||||
{this.renderEndDate()}
|
||||
</div>
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3">
|
||||
<label className="ic-Label" id={postfixId("period_close_date_", this)}>
|
||||
{I18n.t("Close Date")}
|
||||
</label>
|
||||
{this.renderCloseDate()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3">
|
||||
<label htmlFor={postfixId("period_start_date_", this)}>
|
||||
{I18n.t("Start Date")}
|
||||
</label>
|
||||
{this.renderStartDate()}
|
||||
</div>
|
||||
<div className="col-xs-12 col-sm-6 col-lg-3">
|
||||
<label htmlFor={postfixId("period_end_date_", this)}>
|
||||
{I18n.t("End Date")}
|
||||
</label>
|
||||
{this.renderEndDate()}
|
||||
</div>
|
||||
{this.renderDeleteButton()}
|
||||
</div>
|
||||
|
||||
{renderActions(this)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
define(["underscore"], (_) => {
|
||||
const assignmentClosedForStudent = (student, {due_at, only_visible_to_overrides, gradingPeriods, assignmentOverrides}) => {
|
||||
const potentialDueDates = only_visible_to_overrides ?
|
||||
assignmentOverrides :
|
||||
[{default: true, due_at: due_at}, ...assignmentOverrides];
|
||||
const dueDate = dueDateForStudent(student, potentialDueDates);
|
||||
const gp = gradingPeriodForDate(dueDate, gradingPeriods);
|
||||
return gp && new Date(gp.close_date) < new Date();
|
||||
}
|
||||
|
||||
const gradingPeriodForDate = (date, gradingPeriods) => {
|
||||
if (date == null) {
|
||||
return _.last(gradingPeriods);
|
||||
} else {
|
||||
return gradingPeriods.find((gp) => {
|
||||
return date >= gp.start_date && date < gp.end_date;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const dueDateForStudent = (student, dueDates) => {
|
||||
const applicableDueDates = dueDates.filter(function(o) {
|
||||
if (o.default) {
|
||||
return true;
|
||||
}
|
||||
if (o.student_ids && _.include(o.student_ids, student.id)) {
|
||||
return true;
|
||||
}
|
||||
if (o.course_section_id != null &&
|
||||
_.include(student.section_ids, o.course_section_id)) {
|
||||
return true;
|
||||
}
|
||||
}).map(o => o.due_at);
|
||||
|
||||
return _.last(applicableDueDates.sort());
|
||||
};
|
||||
|
||||
return {assignmentClosedForStudent, gradingPeriodForDate, dueDateForStudent};
|
||||
});
|
|
@ -24,11 +24,12 @@ class GradingPeriod < ActiveRecord::Base
|
|||
belongs_to :grading_period_group, inverse_of: :grading_periods
|
||||
has_many :grading_period_grades, dependent: :destroy
|
||||
|
||||
validates :title, :start_date, :end_date, :grading_period_group_id, presence: true
|
||||
validates :title, :start_date, :end_date, :close_date, :grading_period_group_id, presence: true
|
||||
validate :start_date_is_before_end_date
|
||||
validate :close_date_is_not_before_end_date
|
||||
validate :close_date_is_on_or_after_end_date
|
||||
validate :not_overlapping, unless: :skip_not_overlapping_validator?
|
||||
|
||||
before_validation :adjust_close_date_for_course_period
|
||||
before_validation :ensure_close_date
|
||||
|
||||
scope :current, -> do
|
||||
|
@ -104,6 +105,10 @@ class GradingPeriod < ActiveRecord::Base
|
|||
end
|
||||
alias_method :is_last, :last?
|
||||
|
||||
def closed?
|
||||
Time.zone.now > close_date
|
||||
end
|
||||
|
||||
def overlapping?
|
||||
overlaps.active.exists?
|
||||
end
|
||||
|
@ -125,7 +130,7 @@ class GradingPeriod < ActiveRecord::Base
|
|||
|
||||
def as_json_with_user_permissions(user)
|
||||
as_json(
|
||||
only: [:id, :title, :start_date, :end_date],
|
||||
only: [:id, :title, :start_date, :end_date, :close_date],
|
||||
permissions: { user: user },
|
||||
methods: :is_last
|
||||
).fetch(:grading_period)
|
||||
|
@ -166,18 +171,21 @@ class GradingPeriod < ActiveRecord::Base
|
|||
|
||||
def start_date_is_before_end_date
|
||||
if start_date && end_date && end_date < start_date
|
||||
errors.add(:end_date, t('errors.invalid_grading_period_end_date',
|
||||
'Grading period end date precedes start date'))
|
||||
errors.add(:end_date, t('must be after start date'))
|
||||
end
|
||||
end
|
||||
|
||||
def adjust_close_date_for_course_period
|
||||
self.close_date = self.end_date if grading_period_group.present? && course_group?
|
||||
end
|
||||
|
||||
def ensure_close_date
|
||||
self.close_date = self.end_date
|
||||
self.close_date ||= self.end_date
|
||||
end
|
||||
|
||||
def close_date_is_not_before_end_date
|
||||
if close_date && end_date && close_date < end_date
|
||||
errors.add(:close_date, t('Grading period close date precedes end date'))
|
||||
def close_date_is_on_or_after_end_date
|
||||
if close_date.present? && end_date.present? && close_date < end_date
|
||||
errors.add(:close_date, t('must be on or after end date'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -217,9 +217,28 @@ class Submission < ActiveRecord::Base
|
|||
given { |user| user && user.id == self.user_id && !self.assignment.muted? }
|
||||
can :read_grade
|
||||
|
||||
given {|user, session| self.assignment.published? && self.assignment.context.grants_right?(user, session, :manage_grades) }
|
||||
given do |user, session|
|
||||
!context.feature_enabled?(:multiple_grading_periods) &&
|
||||
assignment.published? &&
|
||||
context.grants_right?(user, session, :manage_grades)
|
||||
end
|
||||
can :read and can :comment and can :make_group_comment and can :read_grade and can :grade
|
||||
|
||||
given do |user, session|
|
||||
context.feature_enabled?(:multiple_grading_periods) &&
|
||||
assignment.published? &&
|
||||
context.grants_right?(user, session, :manage_grades)
|
||||
end
|
||||
can :read and can :comment and can :make_group_comment and can :read_grade
|
||||
|
||||
given do |user, session|
|
||||
context.feature_enabled?(:multiple_grading_periods) &&
|
||||
assignment.published? &&
|
||||
context.grants_right?(user, session, :manage_grades) &&
|
||||
(user.admin_of_root_account?(assignment.root_account) || !in_closed_grading_period?)
|
||||
end
|
||||
can :grade
|
||||
|
||||
given {|user, session| self.assignment.user_can_read_grades?(user, session) }
|
||||
can :read and can :read_grade
|
||||
|
||||
|
@ -249,6 +268,17 @@ class Submission < ActiveRecord::Base
|
|||
can :view_turnitin_report
|
||||
end
|
||||
|
||||
def in_closed_grading_period?
|
||||
return false unless self.assignment.context.feature_enabled?(:multiple_grading_periods)
|
||||
|
||||
grading_period = GradingPeriod.
|
||||
for(self.assignment.context).
|
||||
where(":due_at >= start_date AND :due_at <= end_date", due_at: self.cached_due_date).
|
||||
first
|
||||
return false unless grading_period.present?
|
||||
grading_period.closed?
|
||||
end
|
||||
|
||||
def user_can_read_grade?(user, session=nil)
|
||||
# improves performance by checking permissions on the assignment before the submission
|
||||
self.assignment.user_can_read_grades?(user, session) || self.grants_right?(user, session, :read_grade)
|
||||
|
|
|
@ -2277,7 +2277,6 @@ class User < ActiveRecord::Base
|
|||
roles << 'student' unless (enrollment_types & %w[StudentEnrollment StudentViewEnrollment]).empty?
|
||||
roles << 'teacher' unless (enrollment_types & %w[TeacherEnrollment TaEnrollment DesignerEnrollment]).empty?
|
||||
roles << 'observer' unless (enrollment_types & %w[ObserverEnrollment]).empty?
|
||||
|
||||
account_users = root_account.all_account_users_for(self)
|
||||
if account_users.any?
|
||||
roles << 'admin'
|
||||
|
@ -2288,6 +2287,10 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def admin_of_root_account?(root_account)
|
||||
root_account.all_account_users_for(self).any?
|
||||
end
|
||||
|
||||
def eportfolios_enabled?
|
||||
accounts = associated_root_accounts.reject(&:site_admin?)
|
||||
accounts.size == 0 || accounts.any?{ |a| a.settings[:enable_eportfolios] != false }
|
||||
|
|
|
@ -14,9 +14,7 @@
|
|||
.grading-period:nth-child(n+2) {
|
||||
border-top: none;
|
||||
}
|
||||
.input-grading-period-date {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.icon-delete-grading-period::before {
|
||||
padding: 9px 0px;
|
||||
cursor: pointer;
|
||||
|
@ -26,34 +24,30 @@
|
|||
.icon-delete-grading-period {
|
||||
width: 20px;
|
||||
}
|
||||
.buttons-grid-row {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.new-grading-period {
|
||||
border-right-style: dashed;
|
||||
border-bottom-style: dashed;
|
||||
border-left-style: dashed;
|
||||
border-top-style: none;
|
||||
border-width: 2px;
|
||||
@include fontSize(16px);
|
||||
.grading-period {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#add-period-button {
|
||||
@include fontSize(16px);
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.grading-period-add-icon {
|
||||
margin-right: 4px;
|
||||
.GradingPeriod__Details {
|
||||
flex: 1 1;
|
||||
}
|
||||
|
||||
.GradingPeriod__Detail {
|
||||
width: 100%;
|
||||
|
||||
&.ic-Input.hasDatepicker {
|
||||
display: inline-block;
|
||||
width: calc(100% - 46px);
|
||||
}
|
||||
}
|
||||
|
||||
.no-active-grading-periods {
|
||||
border-top-style: dashed;
|
||||
.GradingPeriod__Actions {
|
||||
flex: 0 0;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
|
|
@ -244,14 +244,7 @@ $icon-size: 1.4rem;
|
|||
}
|
||||
}
|
||||
|
||||
#enrollment_inactive_notice {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid $ic-border-light;
|
||||
border-radius: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#enrollment_concluded_notice {
|
||||
#enrollment_inactive_notice, #enrollment_concluded_notice, #closed_gp_notice {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid $ic-border-light;
|
||||
border-radius: 0;
|
||||
|
|
|
@ -86,8 +86,12 @@
|
|||
</div>
|
||||
<% end -%>
|
||||
|
||||
<div id="assignments_outside_current_periods" class="hidden">
|
||||
<h4><%= t('headers.past_grading_periods_prevent_editing', "The following assignments cannot be edited because they are not in a current grading period:") %></h4>
|
||||
<div id="prevented-new-assignment-in-closed-period" style="display:none;">
|
||||
<h4><%= t("Some assignments could not be created because they would fall in a closed grading period.") %></h4>
|
||||
</div>
|
||||
|
||||
<div id="prevented-grading-ungradeable-submission" style="display:none;">
|
||||
<h4><%= t("Some submissions are not gradeable; grade changes for those submissions have been ignored.") %></h4>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -109,9 +109,6 @@
|
|||
<%= t('Publish grades to SIS') %>
|
||||
</a></li>
|
||||
<% end %>
|
||||
<% if @gradebook_is_editable %>
|
||||
<li><a class="dialog_opener" role="button" aria-controls="assignment_group_weights_dialog" href="<%= context_url(@context, :context_assignments_url) %>"><%= t('Set Group Weights') %></a></li>
|
||||
<% end %>
|
||||
<li><a class="student_names_toggle" href="#" role="button"><%= t('Hide Student Names') %></a></li>
|
||||
<li><a data-arrange-columns-by="due_date" href="#"><label><%= t('Arrange columns by due date') %><input type="radio" name="arrange-columns-by" /></label></a></li>
|
||||
<li><a data-arrange-columns-by="assignment_group" href="#"><label><%= t('Arrange columns by assignment group') %><input type="radio" name="arrange-columns-by" /></label></a></li>
|
||||
|
|
|
@ -140,6 +140,9 @@
|
|||
<div id="enrollment_concluded_notice" class="alert alert-info" style="display: none;">
|
||||
<span><%= t "Notice: Concluded Student" %></span>
|
||||
</div>
|
||||
<div id="closed_gp_notice" class="alert alert-info" style="display:none">
|
||||
<span><%= t "Notice: The grading period is closed for this student" %></span>
|
||||
</div>
|
||||
<div id="full_width_container" style="display:none">
|
||||
<div id="left_side" class="full_height">
|
||||
<div id="left_side_inner">
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
<form class="submission_details_grade_form form-inline">
|
||||
<strong><label for="{{label}}">{{#t 'grade_form_label'}}Grade:{{/t}}</label></strong>
|
||||
{{> grading_box}}
|
||||
<button style="float: right;" class="btn" type="submit">{{#t "update_grade"}}Update Grade{{/t}}</button>
|
||||
{{#unless isInPastGradingPeriodAndNotAdmin}}
|
||||
<button style="float: right;" class="btn" type="submit">{{#t "update_grade"}}Update Grade{{/t}}</button>
|
||||
{{/unless}}
|
||||
</form>
|
||||
{{#if speedGraderUrl }}
|
||||
<a class="more-details-link" target="_blank" href="{{speedGraderUrl}}">{{#t "more_details_in_the_speedgrader"}}More details in the SpeedGrader{{/t}}</a>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
class PopulateGradingPeriodCloseDates < ActiveRecord::Migration
|
||||
tag :postdeploy
|
||||
|
||||
def up
|
||||
DataFixup::PopulateGradingPeriodCloseDates.run
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
module DataFixup::PopulateGradingPeriodCloseDates
|
||||
def self.run
|
||||
GradingPeriod.
|
||||
where(close_date: nil).
|
||||
where.not(end_date: nil).
|
||||
update_all("close_date=end_date")
|
||||
end
|
||||
end
|
|
@ -73,10 +73,10 @@ class GradebookImporter
|
|||
@all_assignments = @context.assignments
|
||||
.published
|
||||
.gradeable
|
||||
.select([:id, :title, :points_possible, :grading_type, :due_at])
|
||||
.select([:id, :title, :points_possible, :grading_type, :updated_at, :context_id, :context_type, :group_category_id, :created_at, :due_at])
|
||||
.index_by(&:id)
|
||||
@all_students = @context.all_students
|
||||
.select(['users.id', :name, :sortable_name])
|
||||
.select(['users.id', :name, :sortable_name, 'users.updated_at'])
|
||||
.index_by(&:id)
|
||||
|
||||
@assignments = nil
|
||||
|
@ -85,6 +85,10 @@ class GradebookImporter
|
|||
@pseudonyms_by_login_id = {}
|
||||
@students = []
|
||||
@pp_row = []
|
||||
@warning_messages = {
|
||||
prevented_new_assignment_creation_in_closed_period: false,
|
||||
prevented_grading_ungradeable_submission: false
|
||||
}
|
||||
|
||||
csv_stream do |row|
|
||||
already_processed = check_for_non_student_row(row)
|
||||
|
@ -94,47 +98,54 @@ class GradebookImporter
|
|||
end
|
||||
end
|
||||
|
||||
@assignments_outside_current_periods = []
|
||||
if @context.feature_enabled? :multiple_grading_periods
|
||||
current_period = GradingPeriod.for(@context).current.first
|
||||
|
||||
if current_period.present?
|
||||
with_due_at = @assignments.select(&:due_at)
|
||||
in_current_period = select_in_grading_period(with_due_at, @context, current_period)
|
||||
|
||||
@assignments_outside_current_periods = with_due_at - in_current_period
|
||||
@assignments = @assignments - @assignments_outside_current_periods
|
||||
end
|
||||
end
|
||||
|
||||
@missing_assignments = []
|
||||
@missing_assignments = @all_assignments.values - @assignments if @missing_assignment
|
||||
@missing_students = []
|
||||
@missing_students = @all_students.values - @students if @missing_student
|
||||
|
||||
# look up existing score for everything that was provided
|
||||
assignment_ids = @missing_assignment ? @all_assignments.values : @assignments
|
||||
user_ids = @missing_student ? @all_students.values : @students
|
||||
|
||||
@original_submissions = @context.submissions
|
||||
.select([:assignment_id, :user_id, :score, :excused])
|
||||
.where(:assignment_id => (@missing_assignment ? @all_assignments.values : @assignments),
|
||||
:user_id => (@missing_student ? @all_students.values : @students))
|
||||
.preload(:assignment)
|
||||
.select(['submissions.id', :assignment_id, :user_id, :score, :excused, :cached_due_date, 'submissions.updated_at'])
|
||||
.where(assignment_id: assignment_ids, user_id: user_ids)
|
||||
.map do |submission|
|
||||
{
|
||||
:user_id => submission.user_id,
|
||||
:assignment_id => submission.assignment_id,
|
||||
:score => submission.excused? ? "EX" : submission.score.to_s
|
||||
user_id: submission.user_id,
|
||||
assignment_id: submission.assignment_id,
|
||||
score: submission.excused? ? "EX" : submission.score.to_s,
|
||||
gradeable: submission.grants_right?(@user, :grade)
|
||||
}
|
||||
end
|
||||
|
||||
# cache the score on the existing object
|
||||
original_submissions_by_student = @original_submissions.inject({}) do |r, s|
|
||||
r[s[:user_id]] ||= {}
|
||||
r[s[:user_id]][s[:assignment_id]] = s[:score]
|
||||
r[s[:user_id]][s[:assignment_id]] ||= {}
|
||||
r[s[:user_id]][s[:assignment_id]][:score] = s[:score]
|
||||
r[s[:user_id]][s[:assignment_id]][:gradeable] = s[:gradeable]
|
||||
r
|
||||
end
|
||||
|
||||
@students.each do |student|
|
||||
student.gradebook_importer_submissions.each do |submission|
|
||||
submission['original_grade'] = original_submissions_by_student[student.id]
|
||||
.try(:[], submission['assignment_id'].to_i)
|
||||
submission_assignment_id = submission.fetch('assignment_id').to_i
|
||||
assignment = original_submissions_by_student
|
||||
.fetch(student.id, {})
|
||||
.fetch(submission_assignment_id, {})
|
||||
submission['original_grade'] = assignment.fetch(:score, nil)
|
||||
submission['gradeable'] = assignment.fetch(:gradable, nil)
|
||||
|
||||
if submission.fetch('gradeable').nil?
|
||||
assignment = @all_assignments[submission['assignment_id']] || @context.assignments.build
|
||||
new_submission = Submission.new
|
||||
new_submission.user = student
|
||||
new_submission.assignment = assignment
|
||||
new_submission.cache_due_date
|
||||
submission['gradeable'] = new_submission.grants_right?(@user, :grade)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -151,19 +162,29 @@ class GradebookImporter
|
|||
# Have potentially mixed case excused in grade match case
|
||||
# expectations for the compare so it doesn't look changed
|
||||
submission['grade'] = 'EX' if submission['grade'].to_s.upcase == 'EX'
|
||||
|
||||
|
||||
submission['grade'] == submission['original_grade'] ||
|
||||
no_change = submission['grade'] == submission['original_grade'] ||
|
||||
(submission['original_grade'].present? && submission['grade'].present? && submission['original_grade'].to_f == submission['grade'].to_f) ||
|
||||
(submission['original_grade'].blank? && submission['grade'].blank?)
|
||||
|
||||
if !submission['gradeable'] && !no_change
|
||||
@warning_messages[:prevented_grading_ungradeable_submission] = true
|
||||
end
|
||||
|
||||
no_change || !submission['gradeable']
|
||||
end
|
||||
end
|
||||
|
||||
indexes_to_delete.reverse_each do |idx|
|
||||
@assignments.delete_at(idx)
|
||||
@students.each do |student|
|
||||
student.gradebook_importer_submissions.delete_at(idx)
|
||||
end
|
||||
end
|
||||
|
||||
@students.each do |student|
|
||||
student.gradebook_importer_submissions.select! { |sub| sub['gradeable'] }
|
||||
end
|
||||
|
||||
@unchanged_assignments = !indexes_to_delete.empty?
|
||||
@students = [] if @assignments.empty?
|
||||
end
|
||||
|
@ -175,8 +196,18 @@ class GradebookImporter
|
|||
@students.delete_if { |s| prior_enrollment_ids.include? s.id }
|
||||
|
||||
@original_submissions = [] unless @missing_student || @missing_assignment
|
||||
@upload.gradebook = self.as_json
|
||||
|
||||
if prevent_new_assignment_creation?
|
||||
@assignments.delete_if do |assignment|
|
||||
new_assignment = assignment.new_record?
|
||||
if new_assignment
|
||||
@warning_messages[:prevented_new_assignment_creation_in_closed_period] = true
|
||||
end
|
||||
new_assignment
|
||||
end
|
||||
end
|
||||
|
||||
@upload.gradebook = self.as_json
|
||||
@upload.save!
|
||||
end
|
||||
|
||||
|
@ -243,8 +274,7 @@ class GradebookImporter
|
|||
|
||||
def strip_non_assignment_columns(row)
|
||||
drop_student_information_columns(row)
|
||||
|
||||
while row.last =~ /Current Score|Current Points|Final Score|Final Points|Final Grade/
|
||||
while row.last =~ /Current Score|Current Points|Current Grade|Final Score|Final Points|Final Grade/
|
||||
row.pop
|
||||
end
|
||||
|
||||
|
@ -266,9 +296,18 @@ class GradebookImporter
|
|||
assignment ||= Assignment.new(:title => title || name_and_id)
|
||||
assignment.previous_id = assignment.id
|
||||
assignment.id ||= NegativeId.generate
|
||||
|
||||
@missing_assignment ||= assignment.new_record?
|
||||
assignment
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
|
||||
def prevent_new_assignment_creation?
|
||||
return false unless context.feature_enabled?(:multiple_grading_periods)
|
||||
return false if @user.admin_of_root_account?(@context.root_account)
|
||||
|
||||
last_period = GradingPeriod.for(@context).sort_by(&:end_date).last
|
||||
last_period.present? && last_period.closed?
|
||||
end
|
||||
|
||||
def process_pp(row)
|
||||
|
@ -312,20 +351,20 @@ class GradebookImporter
|
|||
end
|
||||
|
||||
def process_submissions(row, student)
|
||||
l = []
|
||||
importer_submissions = []
|
||||
@assignments.each_with_index do |assignment, idx|
|
||||
assignment_id = assignment.new_record? ? assignment.id : assignment.previous_id
|
||||
grade = row[idx + @student_columns]
|
||||
unless assignment_visible_to_student(student, assignment, assignment_id, @visible_assignments)
|
||||
if !assignment_visible_to_student(student, assignment, assignment_id, @visible_assignments)
|
||||
grade = ''
|
||||
end
|
||||
new_submission = {
|
||||
'grade' => grade,
|
||||
'assignment_id' => assignment_id
|
||||
}
|
||||
l << new_submission
|
||||
importer_submissions << new_submission
|
||||
end
|
||||
student.gradebook_importer_submissions = l
|
||||
student.gradebook_importer_submissions = importer_submissions
|
||||
end
|
||||
|
||||
def assignment_visible_to_student(student, assignment, assignment_id, visible_assignments)
|
||||
|
@ -346,8 +385,7 @@ class GradebookImporter
|
|||
},
|
||||
:original_submissions => @original_submissions,
|
||||
:unchanged_assignments => @unchanged_assignments,
|
||||
:assignments_outside_current_periods =>
|
||||
@assignments_outside_current_periods.map { |a| assignment_to_hash(a) }
|
||||
:warning_messages => @warning_messages
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -420,8 +458,7 @@ class GradebookImporter
|
|||
:previous_id => assignment.previous_id,
|
||||
:title => assignment.title,
|
||||
:points_possible => assignment.points_possible,
|
||||
:grading_type => assignment.grading_type,
|
||||
:due_at => assignment.due_at
|
||||
:grading_type => assignment.grading_type
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -184,17 +184,12 @@ define([
|
|||
$("#no_changes_detected").show();
|
||||
}
|
||||
|
||||
if ( uploadedGradebook.assignments_outside_current_periods.length > 0 ) {
|
||||
var $assignment_list = $("<ul></ul>");
|
||||
var assignments = uploadedGradebook.assignments_outside_current_periods;
|
||||
if (uploadedGradebook.warning_messages.prevented_new_assignment_creation_in_closed_period) {
|
||||
$("#prevented-new-assignment-in-closed-period").show();
|
||||
}
|
||||
|
||||
_.each(assignments, function(assignment) {
|
||||
var $li = $("<li></li>");
|
||||
$li.text(assignment.title);
|
||||
$assignment_list.append($li);
|
||||
});
|
||||
$("#assignments_outside_current_periods").removeClass("hidden");
|
||||
$("#assignments_outside_current_periods").append($assignment_list);
|
||||
if (uploadedGradebook.warning_messages.prevented_grading_ungradeable_submission) {
|
||||
$("#prevented-grading-ungradeable-submission").show();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
define([
|
||||
'jsx/speed_grader/mgp',
|
||||
'jsx/grading/helpers/OutlierScoreHelper',
|
||||
'jst/speed_grader/student_viewed_at',
|
||||
'jst/speed_grader/submissions_dropdown',
|
||||
|
@ -53,7 +54,7 @@ define([
|
|||
'vendor/jquery.getScrollbarWidth' /* getScrollbarWidth */,
|
||||
'vendor/jquery.scrollTo' /* /\.scrollTo/ */,
|
||||
'vendor/ui.selectmenu' /* /\.selectmenu/ */
|
||||
], function(OutlierScoreHelper, studentViewedAtTemplate, submissionsDropdownTemplate, speechRecognitionTemplate, round, _, INST, I18n, $, tz, userSettings, htmlEscape, rubricAssessment, SpeedgraderSelectMenu, SpeedgraderHelpers, turnitinInfoTemplate, turnitinScoreTemplate) {
|
||||
], function(MGP, OutlierScoreHelper, studentViewedAtTemplate, submissionsDropdownTemplate, speechRecognitionTemplate, round, _, INST, I18n, $, tz, userSettings, htmlEscape, rubricAssessment, SpeedgraderSelectMenu, SpeedgraderHelpers, turnitinInfoTemplate, turnitinScoreTemplate) {
|
||||
|
||||
// PRIVATE VARIABLES AND FUNCTIONS
|
||||
// all of the $ variables here are to speed up access to dom nodes,
|
||||
|
@ -119,6 +120,7 @@ define([
|
|||
$submission_not_newest_notice = $("#submission_not_newest_notice"),
|
||||
$enrollment_inactive_notice = $("#enrollment_inactive_notice"),
|
||||
$enrollment_concluded_notice = $("#enrollment_concluded_notice"),
|
||||
$closed_gp_notice = $("#closed_gp_notice"),
|
||||
$submission_files_container = $("#submission_files_container"),
|
||||
$submission_files_list = $("#submission_files_list"),
|
||||
$submission_attachment_viewed_at = $("#submission_attachment_viewed_at_container"),
|
||||
|
@ -146,7 +148,8 @@ define([
|
|||
groupLabel = I18n.t("group", "Group"),
|
||||
gradeeLabel = studentLabel,
|
||||
utils,
|
||||
crocodocSessionTimer;
|
||||
crocodocSessionTimer,
|
||||
isAdmin = _.include(ENV.current_user_roles, "admin");
|
||||
|
||||
utils = {
|
||||
getParam: function(name){
|
||||
|
@ -1149,6 +1152,7 @@ define([
|
|||
$full_width_container.removeClass("with_enrollment_notice");
|
||||
$enrollment_inactive_notice.hide();
|
||||
$enrollment_concluded_notice.hide();
|
||||
$closed_gp_notice.hide();
|
||||
|
||||
EG.setGradeReadOnly(true); // disabling now will keep it from getting undisabled unintentionally by disableWhileLoading
|
||||
if (ENV.grading_role == 'moderator' && this.currentStudent.submission_state == 'not_graded') {
|
||||
|
@ -1506,15 +1510,14 @@ define([
|
|||
var $submission_to_view = $("#submission_to_view"),
|
||||
submissionToViewVal = $submission_to_view.val(),
|
||||
currentSelectedIndex = currentIndex(this, submissionToViewVal),
|
||||
isMostRecent = this.currentStudent &&
|
||||
this.currentStudent.submission &&
|
||||
this.currentStudent.submission.submission_history &&
|
||||
this.currentStudent.submission.submission_history.length - 1 === currentSelectedIndex,
|
||||
submission = this.currentStudent &&
|
||||
this.currentStudent.submission &&
|
||||
this.currentStudent.submission.submission_history &&
|
||||
this.currentStudent.submission.submission_history[currentSelectedIndex] &&
|
||||
this.currentStudent.submission.submission_history[currentSelectedIndex].submission
|
||||
submissionHolder = this.currentStudent &&
|
||||
this.currentStudent.submission,
|
||||
submissionHistory = submissionHolder && submissionHolder.submission_history,
|
||||
isMostRecent = submissionHistory &&
|
||||
submissionHistory.length - 1 === currentSelectedIndex,
|
||||
submission = submissionHistory &&
|
||||
submissionHistory[currentSelectedIndex] &&
|
||||
submissionHistory[currentSelectedIndex].submission
|
||||
|| {},
|
||||
inlineableAttachments = [],
|
||||
browserableAttachments = [];
|
||||
|
@ -1611,9 +1614,16 @@ define([
|
|||
);
|
||||
|
||||
var isConcluded = EG.isStudentConcluded(this.currentStudent.id);
|
||||
var isClosedForStudent = MGP.assignmentClosedForStudent(this.currentStudent, jsonData);
|
||||
$enrollment_concluded_notice.showIf(isConcluded);
|
||||
$closed_gp_notice.showIf(isClosedForStudent);
|
||||
SpeedgraderHelpers.setRightBarDisabled(isConcluded);
|
||||
if (isConcluded) {
|
||||
EG.setGradeReadOnly((typeof submissionHolder != "undefined" &&
|
||||
submissionHolder.submission_type === "online_quiz") ||
|
||||
isConcluded ||
|
||||
(isClosedForStudent && !isAdmin));
|
||||
|
||||
if (isConcluded || isClosedForStudent) {
|
||||
$full_width_container.addClass("with_enrollment_notice");
|
||||
}
|
||||
},
|
||||
|
@ -2204,9 +2214,6 @@ define([
|
|||
var grade = EG.getGradeToShow(submission, ENV.grading_role);
|
||||
|
||||
$grade.val(grade);
|
||||
EG.setGradeReadOnly((typeof submission != "undefined" &&
|
||||
submission.submission_type === 'online_quiz') ||
|
||||
EG.isStudentConcluded(EG.currentStudent.id));
|
||||
|
||||
$('#submit_same_score').hide();
|
||||
if (typeof submission != "undefined" && submission.score !== null) {
|
||||
|
@ -2323,14 +2330,43 @@ define([
|
|||
}
|
||||
};
|
||||
|
||||
function getAssignmentOverrides() {
|
||||
return $.getJSON("/api/v1/courses/" + ENV.course_id +
|
||||
"/assignments/" + ENV.assignment_id + "/overrides");
|
||||
}
|
||||
|
||||
function getGradingPeriods() {
|
||||
var dfd = $.Deferred();
|
||||
// treating failure as a success here since grading periods 404 when not
|
||||
// enabled
|
||||
$.ajaxJSON("/api/v1/courses/" + ENV.course_id + "/grading_periods",
|
||||
"GET", {},
|
||||
function(response) { dfd.resolve(response.grading_periods); },
|
||||
function() { dfd.resolve([]); },
|
||||
{skipDefaultError: true}
|
||||
);
|
||||
|
||||
return dfd;
|
||||
}
|
||||
|
||||
function gotData(assignmentOverridesResponse, gradingPeriods, speedGraderJsonResponse) {
|
||||
var speedGraderJSON = speedGraderJsonResponse[0];
|
||||
var assignmentOverrides = assignmentOverridesResponse[0];
|
||||
|
||||
speedGraderJSON.gradingPeriods = gradingPeriods;
|
||||
speedGraderJSON.assignmentOverrides = assignmentOverrides;
|
||||
|
||||
window.jsonData = speedGraderJSON;
|
||||
EG.jsonReady();
|
||||
}
|
||||
|
||||
return {
|
||||
setup: function() {
|
||||
// fire off the request to get the jsonData
|
||||
window.jsonData = {};
|
||||
$.ajaxJSON(window.location.pathname+ '.json' + window.location.search, 'GET', {}, function(json) {
|
||||
jsonData = json;
|
||||
$(EG.jsonReady);
|
||||
});
|
||||
var speedGraderJsonDfd = $.getJSON(window.location.pathname+ '.json' + window.location.search);
|
||||
|
||||
$.when(getAssignmentOverrides(), getGradingPeriods(), speedGraderJsonDfd).then(gotData);
|
||||
|
||||
//run the stuff that just attaches event handlers and dom stuff, but does not need the jsonData
|
||||
$(document).ready(function() {
|
||||
|
|
|
@ -12,12 +12,14 @@ define [
|
|||
id: "1",
|
||||
title: "Q1",
|
||||
startDate: new Date("2015-09-01T12:00:00Z"),
|
||||
endDate: new Date("2015-10-31T12:00:00Z")
|
||||
endDate: new Date("2015-10-31T12:00:00Z"),
|
||||
closeDate: new Date("2015-11-07T12:00:00Z")
|
||||
},{
|
||||
id: "2",
|
||||
title: "Q2",
|
||||
startDate: new Date("2015-11-01T12:00:00Z"),
|
||||
endDate: new Date("2015-12-31T12:00:00Z")
|
||||
endDate: new Date("2015-12-31T12:00:00Z"),
|
||||
closeDate: new Date("2016-01-07T12:00:00Z")
|
||||
}
|
||||
],
|
||||
permissions: { read: true, create: true, update: true, delete: true },
|
||||
|
@ -41,12 +43,14 @@ define [
|
|||
id: "1",
|
||||
title: "Q1",
|
||||
start_date: new Date("2015-09-01T12:00:00Z"),
|
||||
end_date: new Date("2015-10-31T12:00:00Z")
|
||||
end_date: new Date("2015-10-31T12:00:00Z"),
|
||||
close_date: new Date("2015-11-07T12:00:00Z")
|
||||
},{
|
||||
id: "2",
|
||||
title: "Q2",
|
||||
start_date: new Date("2015-11-01T12:00:00Z"),
|
||||
end_date: new Date("2015-12-31T12:00:00Z")
|
||||
end_date: new Date("2015-12-31T12:00:00Z"),
|
||||
close_date: new Date("2016-01-07T12:00:00Z")
|
||||
}
|
||||
],
|
||||
permissions: { read: true, create: true, update: true, delete: true },
|
||||
|
@ -86,7 +90,7 @@ define [
|
|||
start()
|
||||
@server.respond()
|
||||
|
||||
asyncTest "uses the creation date as the title if the grading period set does not have a title", ->
|
||||
asyncTest "creates a title from the creation date when the set has no title", ->
|
||||
untitledSets =
|
||||
grading_period_sets: [
|
||||
id: "1"
|
||||
|
@ -95,21 +99,44 @@ define [
|
|||
permissions: { read: true, create: true, update: true, delete: true }
|
||||
created_at: "2015-11-29T12:00:00Z"
|
||||
]
|
||||
|
||||
@server.respondWith "GET", /grading_period_sets/, [200, { "Content-Type":"application/json", "Link": @fakeHeaders }, JSON.stringify untitledSets]
|
||||
jsonString = JSON.stringify(untitledSets)
|
||||
@server.respondWith(
|
||||
"GET",
|
||||
/grading_period_sets/,
|
||||
[200, { "Content-Type":"application/json", "Link": @fakeHeaders }, jsonString]
|
||||
)
|
||||
api.list()
|
||||
.then (sets) =>
|
||||
equal sets[0].title, "Set created Nov 29, 2015"
|
||||
start()
|
||||
@server.respond()
|
||||
|
||||
# no fail for CheatDepaginator
|
||||
# asyncTest "SKIPPED: rejects the promise upon errors", ->
|
||||
# @server.respondWith "GET", /grading_period_sets/, [500, {"Content-Type":"application/json"}, "FAIL"]
|
||||
# api.list().catch (error) =>
|
||||
# equal error, "FAIL"
|
||||
# start()
|
||||
# @server.respond()
|
||||
asyncTest "uses the endDate as the closeDate when a period has no closeDate", ->
|
||||
setsWithoutPeriodCloseDate =
|
||||
grading_period_sets: [
|
||||
id: "1"
|
||||
title: "Fall 2015"
|
||||
grading_periods: [{
|
||||
id: "1",
|
||||
title: "Q1",
|
||||
start_date: new Date("2015-09-01T12:00:00Z"),
|
||||
end_date: new Date("2015-10-31T12:00:00Z"),
|
||||
close_date: null
|
||||
}]
|
||||
permissions: { read: true, create: true, update: true, delete: true }
|
||||
created_at: "2015-11-29T12:00:00Z"
|
||||
]
|
||||
jsonString = JSON.stringify(setsWithoutPeriodCloseDate)
|
||||
@server.respondWith(
|
||||
"GET",
|
||||
/grading_period_sets/,
|
||||
[200, { "Content-Type":"application/json", "Link": @fakeHeaders }, jsonString]
|
||||
)
|
||||
api.list()
|
||||
.then (sets) =>
|
||||
deepEqual sets[0].gradingPeriods[0].closeDate, new Date("2015-10-31T12:00:00Z")
|
||||
start()
|
||||
@server.respond()
|
||||
|
||||
deserializedSetCreating = {
|
||||
title: "Fall 2015",
|
||||
|
@ -190,12 +217,14 @@ define [
|
|||
id: "1",
|
||||
title: "Q1",
|
||||
start_date: new Date("2015-09-01T12:00:00Z"),
|
||||
end_date: new Date("2015-10-31T12:00:00Z")
|
||||
end_date: new Date("2015-10-31T12:00:00Z"),
|
||||
close_date: new Date("2015-11-07T12:00:00Z")
|
||||
},{
|
||||
id: "2",
|
||||
title: "Q2",
|
||||
start_date: new Date("2015-11-01T12:00:00Z"),
|
||||
end_date: new Date("2015-12-31T12:00:00Z")
|
||||
end_date: new Date("2015-12-31T12:00:00Z"),
|
||||
close_date: null
|
||||
}
|
||||
],
|
||||
permissions: { read: true, create: true, update: true, delete: true }
|
||||
|
|
|
@ -9,12 +9,14 @@ define [
|
|||
id: "1",
|
||||
title: "Q1",
|
||||
startDate: new Date("2015-09-01T12:00:00Z"),
|
||||
endDate: new Date("2015-10-31T12:00:00Z")
|
||||
endDate: new Date("2015-10-31T12:00:00Z"),
|
||||
closeDate: new Date("2015-11-07T12:00:00Z")
|
||||
},{
|
||||
id: "2",
|
||||
title: "Q2",
|
||||
startDate: new Date("2015-11-01T12:00:00Z"),
|
||||
endDate: new Date("2015-12-31T12:00:00Z")
|
||||
endDate: new Date("2015-12-31T12:00:00Z"),
|
||||
closeDate: new Date("2016-01-07T12:00:00Z")
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -24,12 +26,14 @@ define [
|
|||
id: "1",
|
||||
title: "Q1",
|
||||
start_date: new Date("2015-09-01T12:00:00Z"),
|
||||
end_date: new Date("2015-10-31T12:00:00Z")
|
||||
end_date: new Date("2015-10-31T12:00:00Z"),
|
||||
close_date: new Date("2015-11-07T12:00:00Z")
|
||||
},{
|
||||
id: "2",
|
||||
title: "Q2",
|
||||
start_date: new Date("2015-11-01T12:00:00Z"),
|
||||
end_date: new Date("2015-12-31T12:00:00Z")
|
||||
end_date: new Date("2015-12-31T12:00:00Z"),
|
||||
close_date: new Date("2016-01-07T12:00:00Z")
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -54,6 +58,25 @@ define [
|
|||
deepEqual periods, deserializedPeriods
|
||||
start()
|
||||
|
||||
asyncTest "uses the endDate as the closeDate when a period has no closeDate", ->
|
||||
periodsWithoutCloseDate = {
|
||||
grading_periods: [
|
||||
{
|
||||
id: "1",
|
||||
title: "Q1",
|
||||
start_date: new Date("2015-09-01T12:00:00Z"),
|
||||
end_date: new Date("2015-10-31T12:00:00Z"),
|
||||
close_date: null
|
||||
}
|
||||
]
|
||||
}
|
||||
successPromise = new Promise (resolve) => resolve({ data: periodsWithoutCloseDate })
|
||||
@stub(axios, "patch").returns(successPromise)
|
||||
api.batchUpdate(123, deserializedPeriods)
|
||||
.then (periods) =>
|
||||
deepEqual periods[0].closeDate, new Date("2015-10-31T12:00:00Z")
|
||||
start()
|
||||
|
||||
asyncTest "rejects the promise upon errors", ->
|
||||
failurePromise = new Promise (_, reject) => reject("FAIL")
|
||||
@stub(axios, "patch").returns(failurePromise)
|
||||
|
|
|
@ -112,42 +112,12 @@ define [
|
|||
excusedOptionText = $('.grading_value option')[3].text
|
||||
deepEqual excusedOptionText, 'Excused'
|
||||
|
||||
test "is enabled when multiple grading periods are not enabled", ->
|
||||
ENV.GRADEBOOK_OPTIONS.multiple_grading_periods_enabled = false
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), false
|
||||
|
||||
test "is enabled when no grading periods are in the past", ->
|
||||
ENV.GRADEBOOK_OPTIONS.latest_end_date_of_admin_created_grading_periods_in_the_past = null
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), false
|
||||
|
||||
test "is enabled when current user roles are undefined", ->
|
||||
ENV.current_user_roles = null
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), false
|
||||
|
||||
test "is enabled when the current user is an admin", ->
|
||||
ENV.current_user_roles = ['admin']
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), false
|
||||
|
||||
test "is disabled for assignments in the previous grading period", ->
|
||||
@assignment.due_at = tz.parse("2013-10-01T09:59:00Z")
|
||||
test "is disabled for assignments locked for the given student", ->
|
||||
@user.assignment_1.gradeLocked = true
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), true
|
||||
|
||||
test "is disabled for assignments due exactly at the end of the previous grading period", ->
|
||||
@assignment.due_at = tz.parse("2013-10-01T10:00:00Z")
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), true
|
||||
|
||||
test "is enabled for assignments after the previous grading period", ->
|
||||
@assignment.due_at = tz.parse("2013-10-01T10:01:00Z")
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), false
|
||||
|
||||
test "is enabled for assignments without a due date", ->
|
||||
@assignment.due_at = null
|
||||
test "is enabled for assignments not locked for the given student", ->
|
||||
@user.assignment_1.gradeLocked = false
|
||||
new SubmissionDetailsDialog(@assignment, @user, @options).open()
|
||||
equal $('#student_grading_1').prop('disabled'), false
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
define [
|
||||
'compiled/gradebook2/GradebookHelpers'
|
||||
'jsx/gradebook/grid/constants'
|
||||
'timezone'
|
||||
'compiled/models/Assignment'
|
||||
], (GradebookHelpers, GradebookConstants, tz, Assignment) ->
|
||||
|
||||
], (GradebookHelpers, GradebookConstants) ->
|
||||
module "GradebookHelpers#noErrorsOnPage",
|
||||
setup: ->
|
||||
@mockFind = @mock($, "find")
|
||||
|
@ -42,48 +39,3 @@ define [
|
|||
"the max allowed length AND there are no DOM errors", ->
|
||||
@mockFind.expects("find").once().returns([])
|
||||
ok GradebookHelpers.maxLengthErrorShouldBeShown(GradebookConstants.MAX_NOTE_LENGTH + 1)
|
||||
|
||||
module "GradebookHelpers#gradeIsLocked",
|
||||
setup: ->
|
||||
@env =
|
||||
current_user_roles: []
|
||||
GRADEBOOK_OPTIONS:
|
||||
multiple_grading_periods_enabled: true
|
||||
latest_end_date_of_admin_created_grading_periods_in_the_past: "2013-10-01T10:00:00Z"
|
||||
@assignment = new Assignment(id: 1)
|
||||
@assignment.due_at = tz.parse("2013-10-01T10:00:00Z")
|
||||
@assignment.grading_type = 'points'
|
||||
|
||||
test "gradeIsLocked is false when multiple grading periods are not enabled", ->
|
||||
@env.GRADEBOOK_OPTIONS.multiple_grading_periods_enabled = false
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), false
|
||||
|
||||
test "gradeIsLocked is false when no grading periods are in the past", ->
|
||||
@env.GRADEBOOK_OPTIONS.latest_end_date_of_admin_created_grading_periods_in_the_past = null
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), false
|
||||
|
||||
test "gradeIsLocked is false when current user roles are undefined", ->
|
||||
@env.current_user_roles = null
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), false
|
||||
@env.current_user_roles = undefined
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), false
|
||||
|
||||
test "gradeIsLocked is false when the current user is an admin", ->
|
||||
@env.current_user_roles = ['admin']
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), false
|
||||
|
||||
test "gradeIsLocked is true for assignments in the previous grading period", ->
|
||||
@assignment.due_at = tz.parse("2013-10-01T09:59:00Z")
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), true
|
||||
|
||||
test "gradeIsLocked is true for assignments due exactly at the end of the previous grading period", ->
|
||||
@assignment.due_at = tz.parse("2013-10-01T10:00:00Z")
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), true
|
||||
|
||||
test "gradeIsLocked is false for assignments after the previous grading period", ->
|
||||
@assignment.due_at = tz.parse("2013-10-01T10:01:00Z")
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), false
|
||||
|
||||
test "gradeIsLocked is false for assignments without a due date", ->
|
||||
@assignment.due_at = null
|
||||
equal GradebookHelpers.gradeIsLocked(@assignment, @env), false
|
||||
|
|
|
@ -43,514 +43,11 @@ define [
|
|||
indexedOverrides: Gradebook.prototype.indexedOverrides
|
||||
indexedGradingPeriods: _.indexBy(@gradingPeriods, 'id')
|
||||
|
||||
module "Gradebook2#submissionOutsideOfGradingPeriod - assignment with no overrides",
|
||||
setupThis: (options) ->
|
||||
customOptions = options || {}
|
||||
defaults =
|
||||
mgpEnabled: true
|
||||
isAllGradingPeriods: -> false
|
||||
gradingPeriodToShow: '8'
|
||||
lastGradingPeriodAndDueAtNull: -> false
|
||||
dateIsInGradingPeriod: -> false
|
||||
|
||||
_.defaults customOptions, defaults, gradebookStubs()
|
||||
|
||||
setup: ->
|
||||
@subOutsideOfPeriod = Gradebook.prototype.submissionOutsideOfGradingPeriod
|
||||
@submission = { assignment_id: '1' }
|
||||
@student = { id: '5', sections: ['101','102','103'] }
|
||||
@gradingPeriods = {
|
||||
'8': { id: '8', start_date: '2015-04-01T06:00:00Z', end_date: '2015-05-01T05:59:59Z', is_last: false }
|
||||
'10': { id: '10', start_date: '2015-05-05T06:00:00Z', end_date: '2015-06-01T05:59:59Z', is_last: true }
|
||||
}
|
||||
@overrides = { studentOverrides: {}, sectionOverrides: {} }
|
||||
teardown: ->
|
||||
|
||||
test 'returns false if multiple grading periods is not enabled', ->
|
||||
self = @setupThis(mgpEnabled: false)
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns false if "All Grading Periods" is selected', ->
|
||||
self = @setupThis(mgpEnabled: true, isAllGradingPeriods: -> true)
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns false if the assignment has a null due_at and the last grading period is selected', ->
|
||||
assignments = { '1': { id: '1', has_overrides: false, due_at: null } }
|
||||
self = @setupThis(assignments: assignments, gradingPeriodToShow: '10', lastGradingPeriodAndDueAtNull: -> true)
|
||||
lastGradingPeriodAndDueAtNullSpy = @spy(self, 'lastGradingPeriodAndDueAtNull')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok lastGradingPeriodAndDueAtNullSpy.called
|
||||
ok _.isNull(lastGradingPeriodAndDueAtNullSpy.args[0][1])
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if the assignment has a null due_at and the last grading period is not selected', ->
|
||||
assignments = { '1': { id: '1', has_overrides: false, due_at: null } }
|
||||
self = @setupThis(assignments: assignments)
|
||||
lastGradingPeriodAndDueAtNullSpy = @spy(self, 'lastGradingPeriodAndDueAtNull')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok lastGradingPeriodAndDueAtNullSpy.called
|
||||
ok _.isNull(lastGradingPeriodAndDueAtNullSpy.args[0][1])
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns false if the assignment due_at falls in the selected grading period', ->
|
||||
assignments = { '1': { id: '1', has_overrides: false, due_at: tz.parse('2015-04-15T06:00:00Z') } }
|
||||
self = @setupThis(assignments: assignments, dateIsInGradingPeriod: -> true)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-04-15T06:00:00Z')
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if the assignment due_at falls outside of the selected grading period', ->
|
||||
assignments = { '1': { id: '1', has_overrides: false, due_at: tz.parse('2015-05-15T06:00:00Z') } }
|
||||
self = @setupThis(assignments: assignments, dateIsInGradingPeriod: -> false)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-05-15T06:00:00Z')
|
||||
deepEqual result, true
|
||||
|
||||
module "Gradebook2#submissionOutsideOfGradingPeriod - assignment with one student override that applies to the student",
|
||||
setupThis: (options, overrides) ->
|
||||
customOptions = options || {}
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: tz.parse('2015-05-15T06:00:00Z'), overrides: overrides } }
|
||||
defaults =
|
||||
mgpEnabled: true
|
||||
assignments: assignments
|
||||
isAllGradingPeriods: -> false
|
||||
gradingPeriodToShow: '8'
|
||||
lastGradingPeriodAndDueAtNull: -> false
|
||||
dateIsInGradingPeriod: -> false
|
||||
|
||||
_.defaults customOptions, defaults, gradebookStubs()
|
||||
|
||||
generateOverrides: (dueAt) ->
|
||||
[
|
||||
{ student_ids: ['5'], due_at: dueAt }
|
||||
]
|
||||
|
||||
setup: ->
|
||||
@subOutsideOfPeriod = Gradebook.prototype.submissionOutsideOfGradingPeriod
|
||||
@submission = { assignment_id: '1' }
|
||||
@student = { id: '5', sections: ['101','102','103'] }
|
||||
@gradingPeriods = {
|
||||
'8': { id: '8', start_date: '2015-04-01T06:00:00Z', end_date: '2015-05-01T05:59:59Z', is_last: false }
|
||||
'10': { id: '10', start_date: '2015-05-05T06:00:00Z', end_date: '2015-06-01T05:59:59Z', is_last: true }
|
||||
}
|
||||
teardown: ->
|
||||
|
||||
test 'returns false if the due_at on the override falls within the grading period', ->
|
||||
overrides = @generateOverrides('2015-04-15T06:00:00Z')
|
||||
self = @setupThis({ dateIsInGradingPeriod: -> true }, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-04-15T06:00:00Z')
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if the due_at on the override falls outside of the grading period', ->
|
||||
overrides = @generateOverrides('2015-06-15T06:00:00Z')
|
||||
self = @setupThis({}, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-06-15T06:00:00Z')
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns true if the due_at on the override is null and the grading period is not the last', ->
|
||||
overrides = @generateOverrides(null)
|
||||
self = @setupThis({}, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok _.isNull(dateIsInGradingPeriodSpy.args[0][1])
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns false if the due_at on the override is null and the grading period is the last', ->
|
||||
overrides = @generateOverrides(null)
|
||||
self = @setupThis({ gradingPeriodToShow: '10', lastGradingPeriodAndDueAtNull: -> true }, overrides)
|
||||
lastGradingPeriodAndDueAtNullSpy = @spy(self, 'lastGradingPeriodAndDueAtNull')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok lastGradingPeriodAndDueAtNullSpy.called
|
||||
ok _.isNull(lastGradingPeriodAndDueAtNullSpy.args[0][1])
|
||||
deepEqual result, false
|
||||
|
||||
module "Gradebook2#submissionOutsideOfGradingPeriod - assignment with one section override that applies to the student",
|
||||
setupThis: (options, overrides) ->
|
||||
customOptions = options || {}
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: tz.parse('2015-05-15T06:00:00Z'), overrides: overrides } }
|
||||
defaults =
|
||||
mgpEnabled: true
|
||||
assignments: assignments
|
||||
isAllGradingPeriods: -> false
|
||||
gradingPeriodToShow: '8'
|
||||
lastGradingPeriodAndDueAtNull: -> false
|
||||
dateIsInGradingPeriod: -> false
|
||||
|
||||
_.defaults customOptions, defaults, gradebookStubs()
|
||||
|
||||
generateOverrides: (dueAt) ->
|
||||
[
|
||||
{ student_ids: ['5'], due_at: dueAt }
|
||||
]
|
||||
|
||||
setup: ->
|
||||
@subOutsideOfPeriod = Gradebook.prototype.submissionOutsideOfGradingPeriod
|
||||
@submission = { assignment_id: '1' }
|
||||
@student = { id: '5', sections: ['101','102','103'] }
|
||||
@gradingPeriods = {
|
||||
'8': { id: '8', start_date: '2015-04-01T06:00:00Z', end_date: '2015-05-01T05:59:59Z', is_last: false }
|
||||
'10': { id: '10', start_date: '2015-05-05T06:00:00Z', end_date: '2015-06-01T05:59:59Z', is_last: true }
|
||||
}
|
||||
teardown: ->
|
||||
|
||||
test 'returns false if the due_at on the override falls within the grading period', ->
|
||||
overrides = @generateOverrides('2015-04-15T06:00:00Z')
|
||||
self = @setupThis({ dateIsInGradingPeriod: -> true }, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-04-15T06:00:00Z')
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if the due_at on the override falls outside of the grading period', ->
|
||||
overrides = @generateOverrides('2015-06-15T06:00:00Z')
|
||||
self = @setupThis({}, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-06-15T06:00:00Z')
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns true if the due_at on the override is null and the grading period is not the last', ->
|
||||
overrides = @generateOverrides(null)
|
||||
self = @setupThis({}, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok _.isNull(dateIsInGradingPeriodSpy.args[0][1])
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns false if the due_at on the override is null and the grading period is the last', ->
|
||||
overrides = @generateOverrides(null)
|
||||
self = @setupThis({ gradingPeriodToShow: '10', lastGradingPeriodAndDueAtNull: -> true }, overrides)
|
||||
lastGradingPeriodAndDueAtNullSpy = @spy(self, 'lastGradingPeriodAndDueAtNull')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok lastGradingPeriodAndDueAtNullSpy.called
|
||||
ok _.isNull(lastGradingPeriodAndDueAtNullSpy.args[0][1])
|
||||
deepEqual result, false
|
||||
|
||||
|
||||
module "Gradebook2#submissionOutsideOfGradingPeriod - assignment with one group that applies to the student",
|
||||
setupThis: (options, overrides) ->
|
||||
customOptions = options || {}
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: tz.parse('2015-05-15T06:00:00Z'), overrides: overrides } }
|
||||
defaults =
|
||||
mgpEnabled: true
|
||||
assignments: assignments
|
||||
isAllGradingPeriods: -> false
|
||||
gradingPeriodToShow: '8'
|
||||
lastGradingPeriodAndDueAtNull: -> false
|
||||
dateIsInGradingPeriod: -> false
|
||||
|
||||
_.defaults customOptions, defaults, gradebookStubs()
|
||||
|
||||
generateOverrides: (dueAt) ->
|
||||
[
|
||||
{ group_id: '202', due_at: dueAt }
|
||||
]
|
||||
|
||||
setup: ->
|
||||
@subOutsideOfPeriod = Gradebook.prototype.submissionOutsideOfGradingPeriod
|
||||
@submission = { assignment_id: '1' }
|
||||
@student = { id: '5', sections: ['101','102','103'], group_ids: ['202'] }
|
||||
@gradingPeriods = {
|
||||
'8': { id: '8', start_date: '2015-04-01T06:00:00Z', end_date: '2015-05-01T05:59:59Z', is_last: false }
|
||||
'10': { id: '10', start_date: '2015-05-05T06:00:00Z', end_date: '2015-06-01T05:59:59Z', is_last: true }
|
||||
}
|
||||
teardown: ->
|
||||
|
||||
test 'returns false if the due_at on the override falls within the grading period', ->
|
||||
overrides = @generateOverrides('2015-04-15T06:00:00Z')
|
||||
self = @setupThis({ dateIsInGradingPeriod: -> true }, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-04-15T06:00:00Z')
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if the due_at on the override falls outside of the grading period', ->
|
||||
overrides = @generateOverrides('2015-06-15T06:00:00Z')
|
||||
self = @setupThis({}, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-06-15T06:00:00Z')
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns true if the due_at on the override is null and the grading period is not the last', ->
|
||||
overrides = @generateOverrides(null)
|
||||
self = @setupThis({}, overrides)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok _.isNull(dateIsInGradingPeriodSpy.args[0][1])
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns false if the due_at on the override is null and the grading period is the last', ->
|
||||
overrides = @generateOverrides(null)
|
||||
self = @setupThis({ gradingPeriodToShow: '10', lastGradingPeriodAndDueAtNull: -> true }, overrides)
|
||||
lastGradingPeriodAndDueAtNullSpy = @spy(self, 'lastGradingPeriodAndDueAtNull')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok lastGradingPeriodAndDueAtNullSpy.called
|
||||
ok _.isNull(lastGradingPeriodAndDueAtNullSpy.args[0][1])
|
||||
deepEqual result, false
|
||||
|
||||
module "Gradebook2#submissionOutsideOfGradingPeriod - assignment with one override that does not apply to the student",
|
||||
setupThis: (options) ->
|
||||
customOptions = options || {}
|
||||
defaults =
|
||||
mgpEnabled: true
|
||||
isAllGradingPeriods: -> false
|
||||
gradingPeriodToShow: '8'
|
||||
lastGradingPeriodAndDueAtNull: -> false
|
||||
dateIsInGradingPeriod: -> false
|
||||
|
||||
_.defaults customOptions, defaults, gradebookStubs()
|
||||
|
||||
setup: ->
|
||||
@subOutsideOfPeriod = Gradebook.prototype.submissionOutsideOfGradingPeriod
|
||||
@submission = { assignment_id: '1' }
|
||||
@student = { id: '5', sections: ['101','102','103'] }
|
||||
@gradingPeriods = {
|
||||
'8': { id: '8', start_date: '2015-04-01T06:00:00Z', end_date: '2015-05-01T05:59:59Z', is_last: false }
|
||||
'10': { id: '10', start_date: '2015-05-05T06:00:00Z', end_date: '2015-06-01T05:59:59Z', is_last: true }
|
||||
}
|
||||
@overrides = {
|
||||
studentOverrides: { '1': { '18': { student_ids: ['18'], due_at: '2015-04-15T06:00:00Z' } } }
|
||||
sectionOverrides: {}
|
||||
}
|
||||
teardown: ->
|
||||
|
||||
test 'returns true if the assignment is only visible to overrides', ->
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: null, only_visible_to_overrides: true } }
|
||||
self = @setupThis( assignments: assignments)
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns true if the assignment due_at is outside of the grading period', ->
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: tz.parse('2015-05-15T06:00:00Z') } }
|
||||
self = @setupThis(assignments: assignments)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-05-15T06:00:00Z')
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns false if the assignment due_at is within the grading period', ->
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: tz.parse('2015-04-15T06:00:00Z') } }
|
||||
self = @setupThis(assignments: assignments, dateIsInGradingPeriod: -> true)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-04-15T06:00:00Z')
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if the assignment due_at is null and the grading period is not the last', ->
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: null } }
|
||||
self = @setupThis(assignments: assignments)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok _.isNull(dateIsInGradingPeriodSpy.args[0][1])
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns false if the assignment due_at is null and the grading period is the last', ->
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: null } }
|
||||
self = @setupThis(assignments: assignments, gradingPeriodToShow: '10', lastGradingPeriodAndDueAtNull: -> true)
|
||||
lastGradingPeriodAndDueAtNullSpy = @spy(self, 'lastGradingPeriodAndDueAtNull')
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, @overrides)
|
||||
|
||||
ok lastGradingPeriodAndDueAtNullSpy.called
|
||||
ok _.isNull(lastGradingPeriodAndDueAtNullSpy.args[0][1])
|
||||
deepEqual result, false
|
||||
|
||||
module "Gradebook2#submissionOutsideOfGradingPeriod - assignment with two overrides that apply to the student",
|
||||
setupThis: (options, overrides) ->
|
||||
customOptions = options || {}
|
||||
assignments = { '1': { id: '1', has_overrides: true, due_at: tz.parse('2015-05-15T06:00:00Z'), overrides: overrides } }
|
||||
defaults =
|
||||
mgpEnabled: true
|
||||
assignments: assignments
|
||||
isAllGradingPeriods: -> false
|
||||
gradingPeriodToShow: '8'
|
||||
lastGradingPeriodAndDueAtNull: -> false
|
||||
dateIsInGradingPeriod: -> false
|
||||
|
||||
_.defaults customOptions, defaults, gradebookStubs()
|
||||
|
||||
generateOverrides: (date1, date2) ->
|
||||
[
|
||||
{ student_ids: ['5'], due_at: date1 }
|
||||
{ course_section_id: '101', assignment_id: '1', due_at: date2 }
|
||||
]
|
||||
|
||||
setup: ->
|
||||
@subOutsideOfPeriod = Gradebook.prototype.submissionOutsideOfGradingPeriod
|
||||
@submission = { assignment_id: '1' }
|
||||
@student = { id: '5', sections: ['101','102','103'] }
|
||||
@gradingPeriods = {
|
||||
'8': { id: '8', start_date: '2015-04-01T06:00:00Z', end_date: '2015-05-01T05:59:59Z', is_last: false }
|
||||
'10': { id: '10', start_date: '2015-05-05T06:00:00Z', end_date: '2015-06-01T05:59:59Z', is_last: true }
|
||||
}
|
||||
teardown: ->
|
||||
|
||||
test 'returns false if the latest date of the two overrides falls within the grading period', ->
|
||||
overrides = @generateOverrides('2015-03-01T06:00:00Z', '2015-04-15T06:00:00Z')
|
||||
self = @setupThis({ dateIsInGradingPeriod: -> true }, overrides)
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-04-15T06:00:00Z')
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if the latest date of the two overrides falls outside the grading period' +
|
||||
'(even if the earlier date falls within the grading period)', ->
|
||||
overrides = @generateOverrides('2015-04-15T06:00:00Z', '2015-05-15T06:00:00Z')
|
||||
self = @setupThis({}, overrides)
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok +dateIsInGradingPeriodSpy.args[0][1] == +tz.parse('2015-05-15T06:00:00Z')
|
||||
deepEqual result, true
|
||||
|
||||
test 'returns false if either date is null and the last grading period is selected', ->
|
||||
overrides = @generateOverrides(null, '2015-05-15T06:00:00Z')
|
||||
self = @setupThis({ gradingPeriodToShow: '10', lastGradingPeriodAndDueAtNull: -> true }, overrides)
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
lastGradingPeriodAndDueAtNullSpy = @spy(self, 'lastGradingPeriodAndDueAtNull')
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok lastGradingPeriodAndDueAtNullSpy.called
|
||||
ok _.isNull(lastGradingPeriodAndDueAtNullSpy.args[0][1])
|
||||
deepEqual result, false
|
||||
|
||||
test 'returns true if either date is null and the last grading period is not selected', ->
|
||||
overrides = @generateOverrides(null, '2015-05-15T06:00:00Z')
|
||||
self = @setupThis({}, overrides)
|
||||
isOutsidePeriod = @subOutsideOfPeriod.bind(self)
|
||||
dateIsInGradingPeriodSpy = @spy(self, 'dateIsInGradingPeriod')
|
||||
result = isOutsidePeriod(@submission, @student, @gradingPeriods, overrides)
|
||||
|
||||
ok dateIsInGradingPeriodSpy.called
|
||||
ok _.isNull(dateIsInGradingPeriodSpy.args[0][1])
|
||||
deepEqual result, true
|
||||
|
||||
module "Gradebook2#lastGradingPeriodAndDueAtNull",
|
||||
setup: ->
|
||||
@lastGradingPeriodAndDueAtNull = Gradebook.prototype.lastGradingPeriodAndDueAtNull
|
||||
teardown: ->
|
||||
|
||||
test 'returns true if it is the last grading period and the due at is null', ->
|
||||
gradingPeriod = { is_last: true }
|
||||
dueAt = null
|
||||
ok @lastGradingPeriodAndDueAtNull(gradingPeriod, dueAt)
|
||||
|
||||
test 'returns false if it is not the last grading period', ->
|
||||
gradingPeriod = { is_last: false }
|
||||
dueAt = null
|
||||
notOk @lastGradingPeriodAndDueAtNull(gradingPeriod, dueAt)
|
||||
|
||||
test 'returns false if the dueAt is something other than null', ->
|
||||
gradingPeriod = { is_last: true }
|
||||
dueAt = tz.parse('2015-05-15T06:00:00Z')
|
||||
notOk @lastGradingPeriodAndDueAtNull(gradingPeriod, dueAt)
|
||||
|
||||
module "Gradebook2#dateIsInGradingPeriod",
|
||||
setup: ->
|
||||
@dateIsInGradingPeriod = Gradebook.prototype.dateIsInGradingPeriod
|
||||
@gradingPeriod = { start_date: tz.parse('2015-04-01T06:00:00Z'), end_date: tz.parse('2015-05-01T06:00:00Z') }
|
||||
teardown: ->
|
||||
|
||||
test 'returns false if the date is null', ->
|
||||
date = null
|
||||
notOk @dateIsInGradingPeriod(@gradingPeriod, date)
|
||||
|
||||
test 'returns true if the date falls between the grading period start date and end date', ->
|
||||
date = tz.parse('2015-04-15T06:00:00Z')
|
||||
ok @dateIsInGradingPeriod(@gradingPeriod, date)
|
||||
|
||||
test 'returns false if the date is before the grading period start date', ->
|
||||
date = tz.parse('2015-03-15T06:00:00Z')
|
||||
notOk @dateIsInGradingPeriod(@gradingPeriod, date)
|
||||
|
||||
test 'returns false if the date is after the grading period end date', ->
|
||||
date = tz.parse('2015-05-15T06:00:00Z')
|
||||
notOk @dateIsInGradingPeriod(@gradingPeriod, date)
|
||||
|
||||
test 'returns false if the date is the same as the grading period start date', ->
|
||||
date = tz.parse('2015-04-01T06:00:00Z')
|
||||
notOk @dateIsInGradingPeriod(@gradingPeriod, date)
|
||||
|
||||
test 'returns true if the date is the same as the grading period end date', ->
|
||||
date = tz.parse('2015-05-01T06:00:00Z')
|
||||
ok @dateIsInGradingPeriod(@gradingPeriod, date)
|
||||
|
||||
module "Gradebook2#hideAggregateColumns",
|
||||
setupThis: (options) ->
|
||||
customOptions = options || {}
|
||||
defaults =
|
||||
mgpEnabled: true
|
||||
gradingPeriodsEnabled: true
|
||||
getGradingPeriodToShow: -> '1'
|
||||
options:
|
||||
all_grading_periods_totals: false
|
||||
|
@ -562,12 +59,12 @@ define [
|
|||
teardown: ->
|
||||
|
||||
test 'returns false if multiple grading periods is disabled', ->
|
||||
self = @setupThis(mgpEnabled: false, isAllGradingPeriods: -> false)
|
||||
self = @setupThis(gradingPeriodsEnabled: false, isAllGradingPeriods: -> false)
|
||||
notOk @hideAggregateColumns.call(self)
|
||||
|
||||
test 'returns false if multiple grading periods is disabled, even if isAllGradingPeriods is true', ->
|
||||
self = @setupThis
|
||||
mgpEnabled: false
|
||||
gradingPeriodsEnabled: false
|
||||
getGradingPeriodToShow: -> '0'
|
||||
isAllGradingPeriods: -> true
|
||||
|
||||
|
|
|
@ -59,19 +59,47 @@ define [
|
|||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 'happy'}, { }, student)
|
||||
notEqual submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#class.formatter, isLocked: true adds grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 73 }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("grayed-out") > -1
|
||||
|
||||
test "#class.formatter, isLocked: true adds cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 73 }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("cannot_edit") > -1
|
||||
|
||||
test "#class.formatter, isLocked: true does not include the cell comment bubble", ->
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 73 }, {}, {}, { isLocked: true })
|
||||
equal submissionCellResponse.indexOf("gradebook-cell-comment"), -1
|
||||
|
||||
test "#class.formatter, isLocked: false doesn't add grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 73 }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#class.formatter, isLocked: false doesn't add cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 73 }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("cannot_edit"), -1
|
||||
|
||||
test "#class.formatter, isLocked: false includes the cell comment bubble", ->
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 73 }, {}, {}, { isLocked: false })
|
||||
ok submissionCellResponse.indexOf("gradebook-cell-comment") > -1
|
||||
|
||||
test "#class.formatter, tooltip adds your text to the special classes", ->
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 73 }, {}, {}, { tooltip: "dora_the_explorer" })
|
||||
ok submissionCellResponse.indexOf("dora_the_explorer") > -1
|
||||
|
||||
test "#class.formatter, isInactive: false doesn't add grayed-out", ->
|
||||
student = { isInactive: false }
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 10}, { }, student)
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 10 }, { }, student)
|
||||
equal submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#class.formatter, isConcluded adds grayed-out", ->
|
||||
student = { isConcluded: true }
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 10}, { }, student)
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 10 }, { }, student)
|
||||
notEqual submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#class.formatter, isConcluded doesn't have grayed-out", ->
|
||||
student = { isConcluded: false }
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 10}, { }, student)
|
||||
submissionCellResponse = SubmissionCell.formatter(0, 0, { grade: 10 }, { }, student)
|
||||
equal submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#letter_grade.formatter, shows EX when submission is excused", ->
|
||||
|
@ -88,3 +116,63 @@ define [
|
|||
@stub(SubmissionCell.prototype, 'cellWrapper').withArgs('B').returns('ok')
|
||||
formattedResponse = SubmissionCell.letter_grade.formatter(0, 0, {grade: 'B'}, {}, {})
|
||||
equal formattedResponse, 'ok'
|
||||
|
||||
test "#letter_grade.formatter, isLocked: true adds grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.letter_grade.formatter(0, 0, { grade: "A" }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("grayed-out") > -1
|
||||
|
||||
test "#letter_grade.formatter, isLocked: true adds cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.letter_grade.formatter(0, 0, { grade: "A" }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("cannot_edit") > -1
|
||||
|
||||
test "#letter_grade.formatter, isLocked: false doesn't add grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.letter_grade.formatter(0, 0, { grade: "A" }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#letter_grade.formatter, isLocked: false doesn't add cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.letter_grade.formatter(0, 0, { grade: "A" }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("cannot_edit"), -1
|
||||
|
||||
test "#letter_grade.formatter, tooltip adds your text to the special classes", ->
|
||||
submissionCellResponse = SubmissionCell.letter_grade.formatter(0, 0, { grade: "A" }, {}, {}, { tooltip: "dora_the_explorer" })
|
||||
ok submissionCellResponse.indexOf("dora_the_explorer") > -1
|
||||
|
||||
test "#gpa_scale.formatter, isLocked: true adds grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.gpa_scale.formatter(0, 0, { grade: 3.2 }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("grayed-out") > -1
|
||||
|
||||
test "#gpa_scale.formatter, isLocked: true adds cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.gpa_scale.formatter(0, 0, { grade: 3.2 }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("cannot_edit") > -1
|
||||
|
||||
test "#gpa_scale.formatter, isLocked: false doesn't add grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.gpa_scale.formatter(0, 0, { grade: 3.2 }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#gpa_scale.formatter, isLocked: false doesn't add cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.gpa_scale.formatter(0, 0, { grade: 3.2 }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("cannot_edit"), -1
|
||||
|
||||
test "#gpa_scale.formatter, tooltip adds your text to the special classes", ->
|
||||
submissionCellResponse = SubmissionCell.gpa_scale.formatter(0, 0, { grade: 3.2 }, {}, {}, { tooltip: "dora_the_explorer" })
|
||||
ok submissionCellResponse.indexOf("dora_the_explorer") > -1
|
||||
|
||||
test "#pass_fail.formatter, isLocked: true adds grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.pass_fail.formatter(0, 0, { grade: "complete" }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("grayed-out") > -1
|
||||
|
||||
test "#pass_fail.formatter, isLocked: true adds cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.pass_fail.formatter(0, 0, { grade: "complete" }, {}, {}, { isLocked: true })
|
||||
ok submissionCellResponse.indexOf("cannot_edit") > -1
|
||||
|
||||
test "#pass_fail.formatter, isLocked: false doesn't add grayed-out", ->
|
||||
submissionCellResponse = SubmissionCell.pass_fail.formatter(0, 0, { grade: "complete" }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("grayed-out"), -1
|
||||
|
||||
test "#pass_fail.formatter, isLocked: false doesn't add cannot_edit", ->
|
||||
submissionCellResponse = SubmissionCell.pass_fail.formatter(0, 0, { grade: "complete" }, {}, {}, { isLocked: false })
|
||||
equal submissionCellResponse.indexOf("cannot_edit"), -1
|
||||
|
||||
test "#pass_fail.formatter, tooltip adds your text to the special classes", ->
|
||||
submissionCellResponse = SubmissionCell.pass_fail.formatter(0, 0, { grade: "complete" }, {}, {}, { tooltip: "dora_the_explorer" })
|
||||
ok submissionCellResponse.indexOf("dora_the_explorer") > -1
|
||||
|
|
|
@ -9,7 +9,6 @@ define [
|
|||
], (React, $, _, GradingPeriodCollection, fakeENV) ->
|
||||
|
||||
TestUtils = React.addons.TestUtils
|
||||
Simulate = TestUtils.Simulate
|
||||
|
||||
module 'GradingPeriodCollection',
|
||||
setup: ->
|
||||
|
@ -23,12 +22,22 @@ define [
|
|||
@indexData =
|
||||
"grading_periods":[
|
||||
{
|
||||
"id":"1", "start_date":"2015-03-01T06:00:00Z", "end_date":"2015-05-31T05:00:00Z",
|
||||
"weight":null, "title":"Spring", "permissions": { "update":true, "delete":true }
|
||||
"id":"1",
|
||||
"title":"Spring",
|
||||
"start_date":"2015-03-01T06:00:00Z",
|
||||
"end_date":"2015-05-31T05:00:00Z",
|
||||
"close_date":"2015-06-07T05:00:00Z",
|
||||
"weight":null,
|
||||
"permissions": { "update":true, "delete":true }
|
||||
},
|
||||
{
|
||||
"id":"2", "start_date":"2015-06-01T05:00:00Z", "end_date":"2015-08-31T05:00:00Z",
|
||||
"weight":null, "title":"Summer", "permissions": { "update":true, "delete":true }
|
||||
"id":"2",
|
||||
"title":"Summer",
|
||||
"start_date":"2015-06-01T05:00:00Z",
|
||||
"end_date":"2015-08-31T05:00:00Z",
|
||||
"close_date":"2015-09-07T05:00:00Z",
|
||||
"weight":null,
|
||||
"permissions": { "update":true, "delete":true }
|
||||
}
|
||||
]
|
||||
"grading_periods_read_only": false,
|
||||
|
@ -38,12 +47,22 @@ define [
|
|||
@formattedIndexData =
|
||||
"grading_periods":[
|
||||
{
|
||||
"id":"1", "startDate": new Date("2015-03-01T06:00:00Z"), "endDate": new Date("2015-05-31T05:00:00Z"),
|
||||
"weight":null, "title":"Spring", "permissions": { "update":true, "delete":true }
|
||||
"id":"1",
|
||||
"title":"Spring",
|
||||
"startDate": new Date("2015-03-01T06:00:00Z"),
|
||||
"endDate": new Date("2015-05-31T05:00:00Z"),
|
||||
"closeDate": new Date("2015-06-07T05:00:00Z"),
|
||||
"weight":null,
|
||||
"permissions": { "update":true, "delete":true }
|
||||
},
|
||||
{
|
||||
"id":"2", "startDate": new Date("2015-06-01T05:00:00Z"), "endDate": new Date("2015-08-31T05:00:00Z"),
|
||||
"weight":null, "title":"Summer", "permissions": { "update":true, "delete":true }
|
||||
"id":"2",
|
||||
"title":"Summer",
|
||||
"startDate": new Date("2015-06-01T05:00:00Z"),
|
||||
"endDate": new Date("2015-08-31T05:00:00Z"),
|
||||
"closeDate": new Date("2015-09-07T05:00:00Z"),
|
||||
"weight":null,
|
||||
"permissions": { "update":true, "delete":true }
|
||||
}
|
||||
]
|
||||
"grading_periods_read_only": false,
|
||||
|
@ -52,8 +71,13 @@ define [
|
|||
|
||||
@createdPeriodData = "grading_periods":[
|
||||
{
|
||||
"id":"3", "start_date":"2015-04-20T05:00:00Z", "end_date":"2015-04-21T05:00:00Z",
|
||||
"weight":null, "title":"New Period!", "permissions": { "update":true, "delete":true }
|
||||
"id":"3",
|
||||
"title":"New Period!",
|
||||
"start_date":"2015-04-20T05:00:00Z",
|
||||
"end_date":"2015-04-21T05:00:00Z",
|
||||
"close_date":"2015-04-28T05:00:00Z",
|
||||
"weight":null,
|
||||
"permissions": { "update":true, "delete":true }
|
||||
}
|
||||
]
|
||||
@server.respondWith "GET", ENV.GRADING_PERIODS_URL, [200, {"Content-Type":"application/json"}, JSON.stringify @indexData]
|
||||
|
@ -80,30 +104,9 @@ define [
|
|||
equal @gradingPeriodCollection.refs.grading_period_1.props.readOnly, false
|
||||
equal @gradingPeriodCollection.refs.grading_period_2.props.readOnly, false
|
||||
|
||||
test 'createNewGradingPeriod adds a new period', ->
|
||||
deepEqual @gradingPeriodCollection.state.periods.length, 2
|
||||
@gradingPeriodCollection.createNewGradingPeriod()
|
||||
deepEqual @gradingPeriodCollection.state.periods.length, 3
|
||||
|
||||
test 'createNewGradingPeriod adds the new period with a blank title, start date, and end date', ->
|
||||
@gradingPeriodCollection.createNewGradingPeriod()
|
||||
newPeriod = _.find(@gradingPeriodCollection.state.periods, (p) => p.id.indexOf('new') > -1)
|
||||
deepEqual newPeriod.title, ''
|
||||
deepEqual newPeriod.startDate.getTime(), new Date('').getTime()
|
||||
deepEqual newPeriod.endDate.getTime(), new Date('').getTime()
|
||||
|
||||
test 'deleteGradingPeriod does not call confirmDelete if the grading period is not saved', ->
|
||||
unsavedPeriod = [
|
||||
{
|
||||
"id":"new1", "startDate": new Date("2029-03-01T06:00:00Z"), "endDate": new Date("2030-05-31T05:00:00Z"),
|
||||
"weight":null, "title":"New Period. I'm not saved yet!",
|
||||
"permissions": { "update":true, "delete":true }
|
||||
}
|
||||
]
|
||||
@gradingPeriodCollection.setState({periods: unsavedPeriod})
|
||||
confirmDelete = @stub($.fn, 'confirmDelete')
|
||||
@gradingPeriodCollection.deleteGradingPeriod('new1')
|
||||
ok confirmDelete.notCalled
|
||||
test "renders grading periods with their individual 'closeDate'", ->
|
||||
deepEqual @gradingPeriodCollection.refs.grading_period_1.props.closeDate, new Date("2015-06-07T05:00:00Z")
|
||||
deepEqual @gradingPeriodCollection.refs.grading_period_2.props.closeDate, new Date("2015-09-07T05:00:00Z")
|
||||
|
||||
test 'deleteGradingPeriod calls confirmDelete if the period being deleted is not new (it is saved server side)', ->
|
||||
confirmDelete = @stub($.fn, 'confirmDelete')
|
||||
|
@ -238,13 +241,6 @@ define [
|
|||
ok @gradingPeriodCollection.areDatesOverlapping(periodOne)
|
||||
ok @gradingPeriodCollection.areDatesOverlapping(periodTwo)
|
||||
|
||||
test 'renderAddPeriodButton does not render a button if canAddNewPeriods is false (based on permissions)', ->
|
||||
@gradingPeriodCollection.setState({ canAddNewPeriods: false })
|
||||
notOk @gradingPeriodCollection.renderAddPeriodButton()
|
||||
|
||||
test 'renderAddPeriodButton renders a button if canAddNewPeriods is true (based on permissions)', ->
|
||||
ok @gradingPeriodCollection.renderAddPeriodButton()
|
||||
|
||||
test 'renderSaveButton does not render a button if the user cannot update any of the periods on the page', ->
|
||||
uneditable = [{
|
||||
"id":"12", "startDate": new Date("2015-03-01T06:00:00Z"), "endDate": new Date("2015-05-31T05:00:00Z"),
|
||||
|
|
|
@ -11,6 +11,7 @@ define [
|
|||
], (React, ReactDOM, $, _, GradingPeriod, fakeENV, DateHelper) ->
|
||||
|
||||
TestUtils = React.addons.TestUtils
|
||||
wrapper = document.getElementById('fixtures')
|
||||
|
||||
module 'GradingPeriod',
|
||||
setup: ->
|
||||
|
@ -20,25 +21,27 @@ define [
|
|||
fakeENV.setup()
|
||||
ENV.GRADING_PERIODS_URL = "api/v1/courses/1/grading_periods"
|
||||
|
||||
@createdPeriodData = "grading_periods":[
|
||||
{
|
||||
"id":"3", "start_date":"2015-04-20T05:00:00Z", "end_date":"2015-04-21T05:00:00Z",
|
||||
"weight":null, "title":"New Period!", "permissions": { "update":true, "delete":true }
|
||||
}
|
||||
]
|
||||
@updatedPeriodData = "grading_periods":[
|
||||
{
|
||||
"id":"1", "startDate":"2015-03-01T06:00:00Z", "endDate":"2015-05-31T05:00:00Z",
|
||||
"weight":null, "title":"Updated Grading Period!", "permissions": { "update":true, "delete":true }
|
||||
"id":"1",
|
||||
"title":"Updated Grading Period!",
|
||||
"startDate":"2015-03-01T06:00:00Z",
|
||||
"endDate":"2015-05-31T05:00:00Z",
|
||||
"closeDate":"2015-06-07T05:00:00Z",
|
||||
"weight":null,
|
||||
"permissions": { "update":true, "delete":true }
|
||||
}
|
||||
]
|
||||
@server.respondWith "POST", ENV.GRADING_PERIODS_URL, [200, {"Content-Type":"application/json"}, JSON.stringify @createdPeriodData]
|
||||
@server.respondWith "PUT", ENV.GRADING_PERIODS_URL + "/1", [200, {"Content-Type":"application/json"}, JSON.stringify @updatedPeriodData]
|
||||
@props =
|
||||
@server.respond()
|
||||
|
||||
renderComponent: (opts = {}) ->
|
||||
exampleProps =
|
||||
id: "1"
|
||||
title: "Spring"
|
||||
startDate: new Date("2015-03-01T00:00:00Z")
|
||||
endDate: new Date("2015-05-31T00:00:00Z")
|
||||
closeDate: new Date("2015-06-07T00:00:00Z")
|
||||
weight: null
|
||||
disabled: false
|
||||
readOnly: false
|
||||
|
@ -46,57 +49,64 @@ define [
|
|||
onDeleteGradingPeriod: ->
|
||||
updateGradingPeriodCollection: sinon.spy()
|
||||
|
||||
@server.respond()
|
||||
renderComponent: ->
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, @props)
|
||||
@gradingPeriod = TestUtils.renderIntoDocument(GradingPeriodElement)
|
||||
props = _.defaults(opts, exampleProps)
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, props)
|
||||
ReactDOM.render(GradingPeriodElement, wrapper)
|
||||
|
||||
teardown: ->
|
||||
ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(@gradingPeriod).parentNode)
|
||||
ReactDOM.unmountComponentAtNode(wrapper)
|
||||
ENV.GRADING_PERIODS_URL = null
|
||||
@server.restore()
|
||||
|
||||
test 'sets initial state properly', ->
|
||||
@renderComponent()
|
||||
equal @gradingPeriod.state.title, @props.title
|
||||
equal @gradingPeriod.state.startDate, @props.startDate
|
||||
equal @gradingPeriod.state.endDate, @props.endDate
|
||||
equal @gradingPeriod.state.weight, @props.weight
|
||||
gradingPeriod = @renderComponent()
|
||||
equal gradingPeriod.state.title, "Spring"
|
||||
deepEqual gradingPeriod.state.startDate, new Date("2015-03-01T00:00:00Z")
|
||||
deepEqual gradingPeriod.state.endDate, new Date("2015-05-31T00:00:00Z")
|
||||
equal gradingPeriod.state.weight, null
|
||||
|
||||
test 'onDateChange calls replaceInputWithDate', ->
|
||||
@renderComponent()
|
||||
replaceInputWithDate = @stub(@gradingPeriod, 'replaceInputWithDate')
|
||||
@gradingPeriod.onDateChange("startDate", "period_start_date_1")
|
||||
gradingPeriod = @renderComponent()
|
||||
replaceInputWithDate = @stub(gradingPeriod, 'replaceInputWithDate')
|
||||
gradingPeriod.onDateChange("startDate", "period_start_date_1")
|
||||
ok replaceInputWithDate.calledOnce
|
||||
|
||||
test 'onDateChange calls updateGradingPeriodCollection', ->
|
||||
@renderComponent()
|
||||
@gradingPeriod.onDateChange("startDate", "period_start_date_1")
|
||||
ok @gradingPeriod.props.updateGradingPeriodCollection.calledOnce
|
||||
gradingPeriod = @renderComponent()
|
||||
gradingPeriod.onDateChange("startDate", "period_start_date_1")
|
||||
ok gradingPeriod.props.updateGradingPeriodCollection.calledOnce
|
||||
|
||||
test 'onTitleChange changes the title state', ->
|
||||
@renderComponent()
|
||||
gradingPeriod = @renderComponent()
|
||||
fakeEvent = { target: { name: "title", value: "MXP: Most Xtreme Primate" } }
|
||||
@gradingPeriod.onTitleChange(fakeEvent)
|
||||
deepEqual @gradingPeriod.state.title, "MXP: Most Xtreme Primate"
|
||||
gradingPeriod.onTitleChange(fakeEvent)
|
||||
equal gradingPeriod.state.title, "MXP: Most Xtreme Primate"
|
||||
|
||||
test 'onTitleChange calls updateGradingPeriodCollection', ->
|
||||
@renderComponent()
|
||||
gradingPeriod = @renderComponent()
|
||||
fakeEvent = { target: { name: "title", value: "MXP: Most Xtreme Primate" } }
|
||||
@gradingPeriod.onTitleChange(fakeEvent)
|
||||
ok @gradingPeriod.props.updateGradingPeriodCollection.calledOnce
|
||||
gradingPeriod.onTitleChange(fakeEvent)
|
||||
ok gradingPeriod.props.updateGradingPeriodCollection.calledOnce
|
||||
|
||||
test 'replaceInputWithDate calls formatDatetimeForDisplay', ->
|
||||
@renderComponent()
|
||||
gradingPeriod = @renderComponent()
|
||||
formatDatetime = @stub(DateHelper, 'formatDatetimeForDisplay')
|
||||
fakeDateElement = { val: -> }
|
||||
@gradingPeriod.replaceInputWithDate("startDate", fakeDateElement)
|
||||
gradingPeriod.replaceInputWithDate("startDate", fakeDateElement)
|
||||
ok formatDatetime.calledOnce
|
||||
|
||||
test "assigns the 'readOnly' property on the template when false", ->
|
||||
@renderComponent()
|
||||
equal @gradingPeriod.refs.template.props.readOnly, false
|
||||
gradingPeriod = @renderComponent()
|
||||
equal gradingPeriod.refs.template.props.readOnly, false
|
||||
|
||||
test "assigns the 'readOnly' property on the template when true", ->
|
||||
@props.readOnly = true
|
||||
@renderComponent()
|
||||
equal @gradingPeriod.refs.template.props.readOnly, true
|
||||
gradingPeriod = @renderComponent(readOnly: true)
|
||||
equal gradingPeriod.refs.template.props.readOnly, true
|
||||
|
||||
test "assigns the 'closeDate' property", ->
|
||||
gradingPeriod = @renderComponent()
|
||||
deepEqual gradingPeriod.refs.template.props.closeDate, new Date("2015-06-07T00:00:00Z")
|
||||
|
||||
test "assigns 'endDate' as 'closeDate' when 'closeDate' is not defined", ->
|
||||
gradingPeriod = @renderComponent(closeDate: null)
|
||||
deepEqual gradingPeriod.refs.template.props.closeDate, new Date("2015-05-31T00:00:00Z")
|
||||
|
|
|
@ -5,25 +5,35 @@ define [
|
|||
'jsx/grading/gradingPeriodTemplate'
|
||||
], (React, ReactDOM, _, GradingPeriod) ->
|
||||
|
||||
TestUtils = React.addons.TestUtils
|
||||
defaultProps =
|
||||
title: "Spring"
|
||||
startDate: new Date("2015-03-01T00:00:00Z")
|
||||
endDate: new Date("2015-05-31T00:00:00Z")
|
||||
closeDate: new Date("2015-06-07T00:00:00Z")
|
||||
id: "1"
|
||||
permissions: {
|
||||
update: true
|
||||
delete: true
|
||||
}
|
||||
disabled: false
|
||||
readOnly: false
|
||||
onDeleteGradingPeriod: ->
|
||||
onDateChange: ->
|
||||
onTitleChange: ->
|
||||
|
||||
Simulate = React.addons.TestUtils.Simulate
|
||||
wrapper = document.getElementById('fixtures')
|
||||
|
||||
module 'GradingPeriod with read-only permissions',
|
||||
renderComponent: (opts) ->
|
||||
defaultProps =
|
||||
title: "Spring"
|
||||
startDate: new Date("2015-03-01T00:00:00Z")
|
||||
endDate: new Date("2015-05-31T00:00:00Z")
|
||||
id: "1"
|
||||
readOnly: false
|
||||
renderComponent: (opts = {}) ->
|
||||
readOnlyProps =
|
||||
permissions: {
|
||||
update: false
|
||||
delete: false
|
||||
}
|
||||
onDeleteGradingPeriod: ->
|
||||
|
||||
@props = _.defaults(opts || {}, defaultProps)
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, @props)
|
||||
props = _.defaults(opts, readOnlyProps, defaultProps)
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, props)
|
||||
ReactDOM.render(GradingPeriodElement, wrapper)
|
||||
|
||||
teardown: ->
|
||||
|
@ -41,52 +51,33 @@ define [
|
|||
gradingPeriod = @renderComponent()
|
||||
notOk gradingPeriod.refs.deleteButton
|
||||
|
||||
test 'renderTitle returns a non-input element (since the grading period is readonly)', ->
|
||||
test 'renders attributes as read-only', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
notEqual gradingPeriod.renderTitle().type, "input"
|
||||
notEqual gradingPeriod.refs.title.type, "INPUT"
|
||||
notEqual gradingPeriod.refs.startDate.type, "INPUT"
|
||||
notEqual gradingPeriod.refs.endDate.type, "INPUT"
|
||||
|
||||
test 'renderStartDate returns a non-input element (since the grading period is readonly)', ->
|
||||
test 'displays the correct attributes', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
notEqual gradingPeriod.renderStartDate().type, "input"
|
||||
equal gradingPeriod.refs.title.textContent, "Spring"
|
||||
equal gradingPeriod.refs.startDate.textContent, "Mar 1, 2015 at 12am"
|
||||
equal gradingPeriod.refs.endDate.textContent, "May 31, 2015 at 12am"
|
||||
|
||||
test 'renderEndDate returns a non-input element (since the grading period is readonly)', ->
|
||||
test 'displays the assigned close date', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
notEqual gradingPeriod.renderEndDate().type, "input"
|
||||
equal gradingPeriod.refs.closeDate.textContent, "Jun 7, 2015 at 12am"
|
||||
|
||||
test 'displays the correct title', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
titleNode = gradingPeriod.refs.title
|
||||
equal titleNode.textContent, "Spring"
|
||||
|
||||
test 'displays the correct start date', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
startDateNode = gradingPeriod.refs.startDate
|
||||
equal startDateNode.textContent, "Mar 1, 2015 at 12am"
|
||||
|
||||
test 'displays the correct end date', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
endDateNode = gradingPeriod.refs.endDate
|
||||
equal endDateNode.textContent, "May 31, 2015 at 12am"
|
||||
test 'uses the end date when close date is not defined', ->
|
||||
gradingPeriod = @renderComponent(closeDate: null)
|
||||
equal gradingPeriod.refs.closeDate.textContent, "May 31, 2015 at 12am"
|
||||
|
||||
module "GradingPeriod with 'readOnly' set to true",
|
||||
renderComponent: (opts) ->
|
||||
defaultProps =
|
||||
title: "Spring"
|
||||
startDate: new Date("2015-03-01T00:00:00Z")
|
||||
endDate: new Date("2015-05-31T00:00:00Z")
|
||||
id: "1"
|
||||
renderComponent: (opts = {}) ->
|
||||
readOnlyProps =
|
||||
readOnly: true
|
||||
permissions: {
|
||||
update: true
|
||||
delete: true
|
||||
}
|
||||
disabled: false
|
||||
onDeleteGradingPeriod: ->
|
||||
onDateChange: ->
|
||||
onTitleChange: ->
|
||||
|
||||
@props = _.defaults(opts || {}, defaultProps)
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, @props)
|
||||
props = _.defaults(opts, readOnlyProps, defaultProps)
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, props)
|
||||
ReactDOM.render(GradingPeriodElement, wrapper)
|
||||
|
||||
teardown: ->
|
||||
|
@ -104,108 +95,87 @@ define [
|
|||
gradingPeriod = @renderComponent()
|
||||
notOk gradingPeriod.refs.deleteButton
|
||||
|
||||
test 'renderTitle returns a non-input element (since the grading period is readonly)', ->
|
||||
test 'renders attributes as read-only', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
notEqual gradingPeriod.renderTitle().type, "input"
|
||||
notEqual gradingPeriod.refs.title.type, "INPUT"
|
||||
notEqual gradingPeriod.refs.startDate.type, "INPUT"
|
||||
notEqual gradingPeriod.refs.endDate.type, "INPUT"
|
||||
|
||||
test 'renderStartDate returns a non-input element (since the grading period is readonly)', ->
|
||||
test 'displays the correct attributes', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
notEqual gradingPeriod.renderStartDate().type, "input"
|
||||
equal gradingPeriod.refs.title.textContent, "Spring"
|
||||
equal gradingPeriod.refs.startDate.textContent, "Mar 1, 2015 at 12am"
|
||||
equal gradingPeriod.refs.endDate.textContent, "May 31, 2015 at 12am"
|
||||
|
||||
test 'renderEndDate returns a non-input element (since the grading period is readonly)', ->
|
||||
test 'displays the assigned close date', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
notEqual gradingPeriod.renderEndDate().type, "input"
|
||||
equal gradingPeriod.refs.closeDate.textContent, "Jun 7, 2015 at 12am"
|
||||
|
||||
test 'displays the correct title', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
titleNode = gradingPeriod.refs.title
|
||||
equal titleNode.textContent, "Spring"
|
||||
|
||||
test 'displays the correct start date', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
startDateNode = gradingPeriod.refs.startDate
|
||||
equal startDateNode.textContent, "Mar 1, 2015 at 12am"
|
||||
|
||||
test 'displays the correct end date', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
endDateNode = gradingPeriod.refs.endDate
|
||||
equal endDateNode.textContent, "May 31, 2015 at 12am"
|
||||
test 'uses the end date when close date is not defined', ->
|
||||
gradingPeriod = @renderComponent(closeDate: null)
|
||||
equal gradingPeriod.refs.closeDate.textContent, "May 31, 2015 at 12am"
|
||||
|
||||
module 'editable GradingPeriod',
|
||||
setup: ->
|
||||
@props =
|
||||
title: "Spring"
|
||||
startDate: new Date("2015-03-01T00:00:00Z")
|
||||
endDate: new Date("2015-05-31T00:00:00Z")
|
||||
id: "1"
|
||||
permissions: {
|
||||
update: true
|
||||
delete: true
|
||||
}
|
||||
disabled: false
|
||||
readOnly: false
|
||||
onDeleteGradingPeriod: ->
|
||||
onDateChange: ->
|
||||
onTitleChange: ->
|
||||
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, @props)
|
||||
@gradingPeriod = ReactDOM.render(GradingPeriodElement, wrapper)
|
||||
renderComponent: (opts = {}) ->
|
||||
props = _.defaults(opts, defaultProps)
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, props)
|
||||
ReactDOM.render(GradingPeriodElement, wrapper)
|
||||
|
||||
teardown: ->
|
||||
ReactDOM.unmountComponentAtNode(wrapper)
|
||||
|
||||
test 'renders a delete button', ->
|
||||
ok @gradingPeriod.renderDeleteButton()
|
||||
gradingPeriod = @renderComponent()
|
||||
ok gradingPeriod.refs.deleteButton
|
||||
|
||||
test 'renderTitle returns an input element (since the grading period is editable)', ->
|
||||
equal @gradingPeriod.renderTitle().type, "input"
|
||||
test 'renders with input fields', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
equal gradingPeriod.refs.title.tagName, "INPUT"
|
||||
equal gradingPeriod.refs.startDate.tagName, "INPUT"
|
||||
equal gradingPeriod.refs.endDate.tagName, "INPUT"
|
||||
|
||||
test 'renderStartDate returns an input element (since the grading period is editable)', ->
|
||||
equal @gradingPeriod.renderStartDate().type, "input"
|
||||
test 'displays the correct attributes', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
equal gradingPeriod.refs.title.value, "Spring"
|
||||
equal gradingPeriod.refs.startDate.value, "Mar 1, 2015 at 12am"
|
||||
equal gradingPeriod.refs.endDate.value, "May 31, 2015 at 12am"
|
||||
|
||||
test 'renderEndDate returns an input element (since the grading period is editable)', ->
|
||||
equal @gradingPeriod.renderEndDate().type, "input"
|
||||
test 'uses the end date for close date', ->
|
||||
gradingPeriod = @renderComponent()
|
||||
equal gradingPeriod.refs.closeDate.textContent, "May 31, 2015 at 12am"
|
||||
|
||||
test 'displays the correct title', ->
|
||||
titleNode = @gradingPeriod.refs.title
|
||||
equal titleNode.value, "Spring"
|
||||
test "calls onClick handler for clicks on 'delete grading period'", ->
|
||||
deleteSpy = sinon.spy()
|
||||
gradingPeriod = @renderComponent(onDeleteGradingPeriod: deleteSpy)
|
||||
Simulate.click(gradingPeriod.refs.deleteButton)
|
||||
ok deleteSpy.calledOnce
|
||||
|
||||
test 'displays the correct start date', ->
|
||||
startDateNode = @gradingPeriod.refs.startDate
|
||||
equal startDateNode.value, "Mar 1, 2015 at 12am"
|
||||
|
||||
test 'displays the correct end date', ->
|
||||
endDateNode = @gradingPeriod.refs.endDate
|
||||
equal endDateNode.value, "May 31, 2015 at 12am"
|
||||
test "ignores clicks on 'delete grading period' when disabled", ->
|
||||
deleteSpy = sinon.spy()
|
||||
gradingPeriod = @renderComponent(onDeleteGradingPeriod: deleteSpy, disabled: true)
|
||||
Simulate.click(gradingPeriod.refs.deleteButton)
|
||||
notOk deleteSpy.called
|
||||
|
||||
module 'custom prop validation for editable periods',
|
||||
renderComponent: (opts = {}) ->
|
||||
props = _.defaults(opts, defaultProps)
|
||||
GradingPeriodElement = React.createElement(GradingPeriod, props)
|
||||
ReactDOM.render(GradingPeriodElement, wrapper)
|
||||
|
||||
setup: ->
|
||||
@consoleError = @stub(console, 'error')
|
||||
@props =
|
||||
title: "Spring"
|
||||
startDate: new Date("2015-03-01T00:00:00Z")
|
||||
endDate: new Date("2015-05-31T00:00:00Z")
|
||||
id: "1"
|
||||
permissions: {
|
||||
update: true
|
||||
delete: true
|
||||
}
|
||||
disabled: false
|
||||
readOnly: false
|
||||
onDeleteGradingPeriod: ->
|
||||
onDateChange: ->
|
||||
onTitleChange: ->
|
||||
|
||||
teardown: ->
|
||||
ReactDOM.unmountComponentAtNode(wrapper)
|
||||
|
||||
test 'does not warn of invalid props if all required props are present and of the correct type', ->
|
||||
React.createElement(GradingPeriod, @props)
|
||||
@renderComponent()
|
||||
ok @consoleError.notCalled
|
||||
|
||||
test 'warns if required props are missing', ->
|
||||
delete @props.disabled
|
||||
React.createElement(GradingPeriod, @props)
|
||||
@renderComponent(disabled: null)
|
||||
ok @consoleError.calledOnce
|
||||
|
||||
test 'warns if required props are of the wrong type', ->
|
||||
@props.onDeleteGradingPeriod = "a/s/l?"
|
||||
React.createElement(GradingPeriod, @props)
|
||||
@renderComponent(onDeleteGradingPeriod: "invalid-type")
|
||||
ok @consoleError.calledOnce
|
||||
|
|
|
@ -0,0 +1,679 @@
|
|||
define([
|
||||
'underscore',
|
||||
'timezone',
|
||||
'jsx/gradebook/SubmissionStateMap'
|
||||
], (_, tz, SubmissionStateMap) => {
|
||||
const student = {
|
||||
id: '1',
|
||||
group_ids: ['1'],
|
||||
sections: ['1']
|
||||
};
|
||||
|
||||
const tooltipKeys = {
|
||||
NOT_IN_ANY_GP: "not_in_any_grading_period",
|
||||
IN_ANOTHER_GP: "in_another_grading_period",
|
||||
IN_CLOSED_GP: "in_closed_grading_period",
|
||||
NONE: null
|
||||
};
|
||||
|
||||
function createMap(opts={}) {
|
||||
const defaults = {
|
||||
gradingPeriodsEnabled: false,
|
||||
selectedGradingPeriodID: '0',
|
||||
isAdmin: false,
|
||||
gradingPeriods: []
|
||||
};
|
||||
|
||||
const params = Object.assign(defaults, opts);
|
||||
return new SubmissionStateMap(params);
|
||||
}
|
||||
|
||||
function createAndSetupMap(assignment, opts={}) {
|
||||
const map = createMap(opts);
|
||||
const assignments = {};
|
||||
assignments[assignment.id] = assignment;
|
||||
map.setup([student], assignments);
|
||||
return map;
|
||||
}
|
||||
|
||||
function createGradingPeriod(opts={}) {
|
||||
const defaults = {
|
||||
id: '1',
|
||||
is_last: false,
|
||||
closed: false
|
||||
};
|
||||
|
||||
return Object.assign(defaults, opts);
|
||||
}
|
||||
|
||||
function createOverride({ type, id, dueAt }={}) {
|
||||
const override = {
|
||||
assignment_id: '1',
|
||||
due_at: dueAt,
|
||||
};
|
||||
|
||||
if (type === 'student') {
|
||||
override.student_ids = [id];
|
||||
} else if (type === 'section') {
|
||||
override.course_section_id = id;
|
||||
} else {
|
||||
override.group_id = id;
|
||||
}
|
||||
|
||||
return override;
|
||||
}
|
||||
|
||||
function createAssignment({ dueAt, overrides, gradedButNotAssigned }={}) {
|
||||
const assignment = {
|
||||
id: '1',
|
||||
only_visible_to_overrides: false,
|
||||
assignment_visibility: [],
|
||||
due_at: null,
|
||||
has_overrides: false
|
||||
};
|
||||
|
||||
if (dueAt === undefined) {
|
||||
assignment.only_visible_to_overrides = true;
|
||||
} else {
|
||||
assignment.due_at = tz.parse(dueAt);
|
||||
}
|
||||
|
||||
if (overrides) {
|
||||
assignment.has_overrides = true;
|
||||
assignment.overrides = overrides;
|
||||
|
||||
const overrideForStudent = _.any(overrides, function(override) {
|
||||
const includesStudent = override.student_ids && _.contains(override.student_ids, student.id);
|
||||
const includesSection = _.contains(student.sections, override.course_section_id);
|
||||
const includesGroup = _.contains(student.group_ids, override.group_id);
|
||||
return includesStudent || includesSection || includesGroup;
|
||||
});
|
||||
|
||||
const studentGradedButNotAssigned = gradedButNotAssigned && _.contains(gradedButNotAssigned, student.id);
|
||||
|
||||
if (overrideForStudent || studentGradedButNotAssigned) assignment.assignment_visibility.push(student.id);
|
||||
}
|
||||
|
||||
return assignment;
|
||||
}
|
||||
|
||||
// TODO: the spec setup above should live in a spec helper -- at the
|
||||
// time this is being written a significant amount of work is needed
|
||||
// to be able to require javascript files that live in the spec directory
|
||||
|
||||
const OTHER_STUDENT_ID = '2';
|
||||
|
||||
module('SubmissionStateMap with MGP disabled');
|
||||
|
||||
test('submission has grade hidden for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, { gradingPeriodsEnabled: false });
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, { gradingPeriodsEnabled: false });
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and all grading periods selected', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02' });
|
||||
const lastPeriod = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: '0', gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment due in a closed grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment due in a non-closed grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment due outside of any grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment due in a closed grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment due in a non-closed grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment due outside of any grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in a closed grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in a non-closed grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const mapOptions = Object.assign(this.mapOptions);
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with multiple applicable overrides with the latest due date due outside of any grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const mapOptions = Object.assign(this.mapOptions);
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: null });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const mapOptions = Object.assign(this.mapOptions);
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and a non-closed grading period selected that is not the last grading period', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02' });
|
||||
const lastPeriod = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-08-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: openPeriod.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and a closed grading period selected that is not the last grading period', {
|
||||
setup() {
|
||||
const firstClosedPeriod = createGradingPeriod({ id: '1', start_date: '2015-06-01', end_date: '2015-06-30', close_date: '2015-07-02', closed: true });
|
||||
const secondClosedPeriod = createGradingPeriod({ id: '2', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '3', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02'});
|
||||
const lastPeriod = createGradingPeriod({ id: '4', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-05-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [firstClosedPeriod, secondClosedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: secondClosedPeriod.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and the last grading period selected which is not closed', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02' });
|
||||
const lastPeriod = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-09-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: lastPeriod.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and the last grading period selected which is closed', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-12-25' });
|
||||
const lastPeriodAndClosed = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true, closed: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-09-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriodAndClosed];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: lastPeriodAndClosed.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade hidden for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, true);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
|
||||
test('submission has grade visible for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.hideGrade, false);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,919 @@
|
|||
define([
|
||||
'underscore',
|
||||
'timezone',
|
||||
'jsx/gradebook/SubmissionStateMap'
|
||||
], (_, tz, SubmissionStateMap) => {
|
||||
const student = {
|
||||
id: '1',
|
||||
group_ids: ['1'],
|
||||
sections: ['1']
|
||||
};
|
||||
|
||||
const tooltipKeys = {
|
||||
NOT_IN_ANY_GP: "not_in_any_grading_period",
|
||||
IN_ANOTHER_GP: "in_another_grading_period",
|
||||
IN_CLOSED_GP: "in_closed_grading_period",
|
||||
NONE: null
|
||||
};
|
||||
|
||||
function createMap(opts={}) {
|
||||
const defaults = {
|
||||
gradingPeriodsEnabled: false,
|
||||
selectedGradingPeriodID: '0',
|
||||
isAdmin: false,
|
||||
gradingPeriods: []
|
||||
};
|
||||
|
||||
const params = Object.assign(defaults, opts);
|
||||
return new SubmissionStateMap(params);
|
||||
}
|
||||
|
||||
function createAndSetupMap(assignment, opts={}) {
|
||||
const map = createMap(opts);
|
||||
const assignments = {};
|
||||
assignments[assignment.id] = assignment;
|
||||
map.setup([student], assignments);
|
||||
return map;
|
||||
}
|
||||
|
||||
function createGradingPeriod(opts={}) {
|
||||
const defaults = {
|
||||
id: '1',
|
||||
is_last: false,
|
||||
closed: false
|
||||
};
|
||||
|
||||
return Object.assign(defaults, opts);
|
||||
}
|
||||
|
||||
function createOverride({ type, id, dueAt }={}) {
|
||||
const override = {
|
||||
assignment_id: '1',
|
||||
due_at: dueAt,
|
||||
};
|
||||
|
||||
if (type === 'student') {
|
||||
override.student_ids = [id];
|
||||
} else if (type === 'section') {
|
||||
override.course_section_id = id;
|
||||
} else {
|
||||
override.group_id = id;
|
||||
}
|
||||
|
||||
return override;
|
||||
}
|
||||
|
||||
function createAssignment({ dueAt, overrides, gradedButNotAssigned }={}) {
|
||||
const assignment = {
|
||||
id: '1',
|
||||
only_visible_to_overrides: false,
|
||||
assignment_visibility: [],
|
||||
due_at: null,
|
||||
has_overrides: false
|
||||
};
|
||||
|
||||
if (dueAt === undefined) {
|
||||
assignment.only_visible_to_overrides = true;
|
||||
} else {
|
||||
assignment.due_at = tz.parse(dueAt);
|
||||
}
|
||||
|
||||
if (overrides) {
|
||||
assignment.has_overrides = true;
|
||||
assignment.overrides = overrides;
|
||||
|
||||
const overrideForStudent = _.any(overrides, function(override) {
|
||||
const includesStudent = override.student_ids && _.contains(override.student_ids, student.id);
|
||||
const includesSection = _.contains(student.sections, override.course_section_id);
|
||||
const includesGroup = _.contains(student.group_ids, override.group_id);
|
||||
return includesStudent || includesSection || includesGroup;
|
||||
});
|
||||
|
||||
const studentGradedButNotAssigned = gradedButNotAssigned && _.contains(gradedButNotAssigned, student.id);
|
||||
|
||||
if (overrideForStudent || studentGradedButNotAssigned) assignment.assignment_visibility.push(student.id);
|
||||
}
|
||||
|
||||
return assignment;
|
||||
}
|
||||
|
||||
// TODO: the spec setup above should live in a spec helper -- at the
|
||||
// time this is being written a significant amount of work is needed
|
||||
// to be able to require javascript files that live in the spec directory
|
||||
|
||||
const OTHER_STUDENT_ID = '2';
|
||||
|
||||
module('SubmissionStateMap with MGP disabled');
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, { gradingPeriodsEnabled: false });
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, { gradingPeriodsEnabled: false });
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and all grading periods selected', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02' });
|
||||
const lastPeriod = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: '0', gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due in a closed grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('user is admin: submission is unlocked for an assigned student with assignment due in a closed grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const mapOptions = Object.assign(this.mapOptions, { isAdmin: true });
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment due in a non-closed grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment due outside of any grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due in a closed grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('user is admin: submission is unlocked for an assigned student with overridden assignment due in a closed grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const mapOptions = Object.assign(this.mapOptions, { isAdmin: true })
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment due in a non-closed grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment due outside of any grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in a closed grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('user is admin: submission is unlocked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in a closed grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const mapOptions = Object.assign(this.mapOptions, { isAdmin: true });
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in a non-closed grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const mapOptions = Object.assign(this.mapOptions);
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date due outside of any grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const mapOptions = Object.assign(this.mapOptions);
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: null });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const mapOptions = Object.assign(this.mapOptions);
|
||||
const map = createAndSetupMap(assignment, mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and a non-closed grading period selected that is not the last grading period', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02' });
|
||||
const lastPeriod = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-08-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: openPeriod.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and a closed grading period selected that is not the last grading period', {
|
||||
setup() {
|
||||
const firstClosedPeriod = createGradingPeriod({ id: '1', start_date: '2015-06-01', end_date: '2015-06-30', close_date: '2015-07-02', closed: true });
|
||||
const secondClosedPeriod = createGradingPeriod({ id: '2', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '3', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02'});
|
||||
const lastPeriod = createGradingPeriod({ id: '4', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-05-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [firstClosedPeriod, secondClosedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: secondClosedPeriod.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap -- user is admin with MGP enabled and a closed grading period selected that is not the last grading period', {
|
||||
setup() {
|
||||
const firstClosedPeriod = createGradingPeriod({ id: '1', start_date: '2015-06-01', end_date: '2015-06-30', close_date: '2015-07-02', closed: true });
|
||||
const secondClosedPeriod = createGradingPeriod({ id: '2', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '3', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02'});
|
||||
const lastPeriod = createGradingPeriod({ id: '4', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-05-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [firstClosedPeriod, secondClosedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: secondClosedPeriod.id, gradingPeriods, isAdmin: true };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and the last grading period selected which is not closed', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-09-02' });
|
||||
const lastPeriod = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-09-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriod];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: lastPeriod.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap with MGP enabled and the last grading period selected which is closed', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-12-25' });
|
||||
const lastPeriodAndClosed = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true, closed: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-09-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriodAndClosed];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: lastPeriodAndClosed.id, gradingPeriods };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
module('SubmissionStateMap -- user is admin with MGP enabled and the last grading period selected which is closed', {
|
||||
setup() {
|
||||
const closedPeriod = createGradingPeriod({ id: '1', start_date: '2015-07-01', end_date: '2015-07-31', close_date: '2015-08-02', closed: true });
|
||||
const openPeriod = createGradingPeriod({ id: '2', start_date: '2015-08-01', end_date: '2015-08-31', close_date: '2015-12-25' });
|
||||
const lastPeriodAndClosed = createGradingPeriod({ id: '3', start_date: '2015-09-01', end_date: '2015-09-30', close_date: '2015-10-02', is_last: true, closed: true });
|
||||
this.DATE_BEFORE_FIRST_PERIOD = '2015-06-15';
|
||||
this.DATE_IN_CLOSED_PERIOD = '2015-07-15';
|
||||
this.DATE_IN_OPEN_PERIOD = '2015-08-15';
|
||||
this.DATE_IN_SELECTED_PERIOD = '2015-09-15';
|
||||
this.DATE_AFTER_LAST_PERIOD = '2015-10-15';
|
||||
const gradingPeriods = [closedPeriod, openPeriod, lastPeriodAndClosed];
|
||||
this.mapOptions = { gradingPeriodsEnabled: true, selectedGradingPeriodID: lastPeriodAndClosed.id, gradingPeriods, isAdmin: true };
|
||||
}
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with no submission or ungraded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an unassigned student with a graded submission', function() {
|
||||
const override = createOverride({ type: 'student', id: OTHER_STUDENT_ID, dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override], gradedButNotAssigned: [student.id] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with assignment due outside of the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment due in the selected grading period', function() {
|
||||
const assignment = createAssignment({ dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with assignment with no due date', function() {
|
||||
const assignment = createAssignment({ dueAt: null });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment due outside of the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment due in the selected grading period', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with no due date', function() {
|
||||
const override = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const assignment = createAssignment({ overrides: [override] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is locked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date outside of the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_OPEN_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, true);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with multiple applicable overrides with the latest due date in the selected grading period', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_BEFORE_FIRST_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_IN_SELECTED_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
|
||||
test('submission is unlocked for an assigned student with overridden assignment with with multiple applicable overrides with at least one override with no due date', function() {
|
||||
const studentOverride = createOverride({ type: 'student', id: student.id, dueAt: null });
|
||||
const sectionOverride = createOverride({ type: 'section', id: student.sections[0], dueAt: this.DATE_IN_CLOSED_PERIOD });
|
||||
const groupOverride = createOverride({ type: 'group', id: student.group_ids[0], dueAt: this.DATE_AFTER_LAST_PERIOD });
|
||||
const assignment = createAssignment({ overrides: [studentOverride, sectionOverride, groupOverride] });
|
||||
const map = createAndSetupMap(assignment, this.mapOptions);
|
||||
const state = map.getSubmissionState({ user_id: student.id, assignment_id: assignment.id });
|
||||
equal(state.locked, false);
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load Diff
|
@ -16,7 +16,8 @@ define([
|
|||
id: "1",
|
||||
title: "We did it! We did it! We did it! #dora #boots",
|
||||
startDate: new Date("2015-01-01T20:11:00+00:00"),
|
||||
endDate: new Date("2015-03-01T00:00:00+00:00")
|
||||
endDate: new Date("2015-03-01T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-08T00:00:00+00:00")
|
||||
},
|
||||
readOnly: false,
|
||||
onEdit: () => {},
|
||||
|
@ -75,6 +76,12 @@ define([
|
|||
equal(endDate, "End Date: Mar 1, 2015 at 12am");
|
||||
});
|
||||
|
||||
test("displays the close date in a friendly format", function() {
|
||||
let period = this.renderComponent();
|
||||
const closeDate = ReactDOM.findDOMNode(period.refs.closeDate).textContent;
|
||||
equal(closeDate, "Close Date: Mar 8, 2015 at 12am");
|
||||
});
|
||||
|
||||
test("calls the 'onEdit' callback when the edit button is clicked", function() {
|
||||
let spy = sinon.spy();
|
||||
let period = this.renderComponent({onEdit: spy});
|
||||
|
|
|
@ -7,9 +7,18 @@ define([
|
|||
const wrapper = document.getElementById('fixtures');
|
||||
const Simulate = React.addons.TestUtils.Simulate;
|
||||
|
||||
const examplePeriod = {
|
||||
id: '1',
|
||||
title: 'Q1',
|
||||
startDate: new Date("2015-11-01T12:00:00Z"),
|
||||
endDate: new Date("2015-12-31T12:00:00Z"),
|
||||
closeDate: new Date("2016-01-07T12:00:00Z")
|
||||
};
|
||||
|
||||
module('GradingPeriodForm', {
|
||||
renderComponent: function(opts={}) {
|
||||
const defaults = {
|
||||
period: examplePeriod,
|
||||
disabled: false,
|
||||
onSave: () => {},
|
||||
onCancel: () => {}
|
||||
|
@ -23,43 +32,112 @@ define([
|
|||
}
|
||||
});
|
||||
|
||||
test('mounts', function() {
|
||||
test("sets form values from 'period' props", function() {
|
||||
let form = this.renderComponent();
|
||||
ok(form.isMounted());
|
||||
equal(form.refs.title.value, 'Q1');
|
||||
equal(form.refs.startDate.refs.dateInput.value, 'Nov 1, 2015 at 12pm');
|
||||
equal(form.refs.endDate.refs.dateInput.value, 'Dec 31, 2015 at 12pm');
|
||||
equal(form.refs.closeDate.refs.dateInput.value, 'Jan 7 at 12pm');
|
||||
});
|
||||
|
||||
test('renders with the save button enabled', function() {
|
||||
let form = this.renderComponent();
|
||||
let saveButton = React.findDOMNode(form.refs.saveButton);
|
||||
let saveButton = ReactDOM.findDOMNode(form.refs.saveButton);
|
||||
equal(saveButton.disabled, false);
|
||||
});
|
||||
|
||||
test('renders with the cancel button enabled', function() {
|
||||
let form = this.renderComponent();
|
||||
let cancelButton = React.findDOMNode(form.refs.saveButton);
|
||||
let cancelButton = ReactDOM.findDOMNode(form.refs.saveButton);
|
||||
equal(cancelButton.disabled, false);
|
||||
});
|
||||
|
||||
test('optionally renders with the save and cancel buttons disabled', function() {
|
||||
let form = this.renderComponent({disabled: true});
|
||||
let saveButton = React.findDOMNode(form.refs.saveButton);
|
||||
let cancelButton = React.findDOMNode(form.refs.cancelButton);
|
||||
let saveButton = ReactDOM.findDOMNode(form.refs.saveButton);
|
||||
let cancelButton = ReactDOM.findDOMNode(form.refs.cancelButton);
|
||||
equal(saveButton.disabled, true);
|
||||
equal(cancelButton.disabled, true);
|
||||
});
|
||||
|
||||
test("auto-updates 'closeDate' when not already set and 'endDate' changes", function() {
|
||||
let incompletePeriod = _.extend({}, examplePeriod, { closeDate: null });
|
||||
let form = this.renderComponent({period: incompletePeriod});
|
||||
let endDateInput = ReactDOM.findDOMNode(form.refs.endDate.refs.dateInput);
|
||||
endDateInput.value = 'Dec 31, 2015 at 12pm';
|
||||
endDateInput.dispatchEvent(new Event("change"));
|
||||
equal(form.refs.endDate.refs.dateInput.value, 'Dec 31, 2015 at 12pm');
|
||||
equal(form.refs.closeDate.refs.dateInput.value, 'Dec 31, 2015 at 12pm');
|
||||
});
|
||||
|
||||
test("auto-updates 'closeDate' when set equal to 'endDate' and 'endDate' changes", function() {
|
||||
let consistentPeriod = _.extend({}, examplePeriod, { closeDate: examplePeriod.endDate });
|
||||
let form = this.renderComponent({period: consistentPeriod});
|
||||
let endDateInput = ReactDOM.findDOMNode(form.refs.endDate.refs.dateInput);
|
||||
endDateInput.value = 'Dec 30, 2015 at 12pm';
|
||||
endDateInput.dispatchEvent(new Event("change"));
|
||||
equal(form.refs.endDate.refs.dateInput.value, 'Dec 30, 2015 at 12pm');
|
||||
equal(form.refs.closeDate.refs.dateInput.value, 'Dec 30, 2015 at 12pm');
|
||||
});
|
||||
|
||||
test("preserves 'closeDate' when not set equal to 'endDate' and 'endDate' changes", function() {
|
||||
let form = this.renderComponent();
|
||||
let endDateInput = ReactDOM.findDOMNode(form.refs.endDate.refs.dateInput);
|
||||
endDateInput.value = 'Dec 30, 2015 at 12pm';
|
||||
endDateInput.dispatchEvent(new Event("change"));
|
||||
equal(form.refs.endDate.refs.dateInput.value, 'Dec 30, 2015 at 12pm');
|
||||
equal(form.refs.closeDate.refs.dateInput.value, 'Jan 7 at 12pm');
|
||||
});
|
||||
|
||||
test("preserves 'closeDate' when already set and 'endDate' changes to match, then changes again", function() {
|
||||
let form = this.renderComponent();
|
||||
let endDateInput = ReactDOM.findDOMNode(form.refs.endDate.refs.dateInput);
|
||||
endDateInput.value = 'Jan 7 at 12pm';
|
||||
endDateInput.dispatchEvent(new Event("change"));
|
||||
endDateInput.value = 'Dec 30, 2015 at 12pm';
|
||||
endDateInput.dispatchEvent(new Event("change"));
|
||||
equal(form.refs.endDate.refs.dateInput.value, 'Dec 30, 2015 at 12pm');
|
||||
equal(form.refs.closeDate.refs.dateInput.value, 'Jan 7 at 12pm');
|
||||
});
|
||||
|
||||
test("auto-updates 'closeDate' when cleared and 'endDate' changes", function() {
|
||||
let form = this.renderComponent();
|
||||
let closeDateInput = ReactDOM.findDOMNode(form.refs.closeDate.refs.dateInput);
|
||||
closeDateInput.value = '';
|
||||
closeDateInput.dispatchEvent(new Event("change"));
|
||||
let endDateInput = ReactDOM.findDOMNode(form.refs.endDate.refs.dateInput);
|
||||
endDateInput.value = 'Jan 7 at 12pm';
|
||||
endDateInput.dispatchEvent(new Event("change"));
|
||||
equal(form.refs.endDate.refs.dateInput.value, 'Jan 7 at 12pm');
|
||||
equal(form.refs.closeDate.refs.dateInput.value, 'Jan 7 at 12pm');
|
||||
});
|
||||
|
||||
test("calls the 'onSave' callback when the save button is clicked", function() {
|
||||
let spy = sinon.spy();
|
||||
let form = this.renderComponent({onSave: spy});
|
||||
let saveButton = React.findDOMNode(form.refs.saveButton);
|
||||
let saveButton = ReactDOM.findDOMNode(form.refs.saveButton);
|
||||
Simulate.click(saveButton);
|
||||
ok(spy.calledOnce);
|
||||
});
|
||||
|
||||
test("sends form values in 'onSave'", function() {
|
||||
let spy = sinon.spy();
|
||||
let form = this.renderComponent({onSave: spy});
|
||||
let saveButton = ReactDOM.findDOMNode(form.refs.saveButton);
|
||||
Simulate.click(saveButton);
|
||||
deepEqual(spy.args[0][0], {
|
||||
id: '1',
|
||||
title: 'Q1',
|
||||
startDate: new Date("2015-11-01T12:00:00Z"),
|
||||
endDate: new Date("2015-12-31T12:00:00Z"),
|
||||
closeDate: new Date("2016-01-07T12:00:00Z")
|
||||
});
|
||||
});
|
||||
|
||||
test("calls the 'onCancel' callback when the cancel button is clicked", function() {
|
||||
let spy = sinon.spy();
|
||||
let form = this.renderComponent({onCancel: spy});
|
||||
let cancelButton = React.findDOMNode(form.refs.cancelButton);
|
||||
let cancelButton = ReactDOM.findDOMNode(form.refs.cancelButton);
|
||||
Simulate.click(cancelButton);
|
||||
ok(spy.calledOnce);
|
||||
});
|
||||
|
|
|
@ -41,19 +41,20 @@ define([
|
|||
id: "1",
|
||||
title: "We did it! We did it! We did it! #dora #boots",
|
||||
startDate: new Date("2015-01-01T20:11:00+00:00"),
|
||||
endDate: new Date("2015-03-01T00:00:00+00:00")
|
||||
},
|
||||
{
|
||||
endDate: new Date("2015-03-01T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-01T00:00:00+00:00")
|
||||
},{
|
||||
id: "3",
|
||||
title: "Como estas?",
|
||||
startDate: new Date("2014-11-01T20:11:00+00:00"),
|
||||
endDate: new Date("2014-11-11T00:00:00+00:00")
|
||||
},
|
||||
{
|
||||
endDate: new Date("2014-11-11T00:00:00+00:00"),
|
||||
closeDate: new Date("2014-11-11T00:00:00+00:00")
|
||||
},{
|
||||
id: "2",
|
||||
title: "Swiper no swiping!",
|
||||
startDate: new Date("2015-04-01T20:11:00+00:00"),
|
||||
endDate: new Date("2015-05-01T00:00:00+00:00")
|
||||
endDate: new Date("2015-05-01T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-05-01T00:00:00+00:00")
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -61,7 +62,8 @@ define([
|
|||
id: "4",
|
||||
title: "Example Period",
|
||||
startDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
|
||||
const props = {
|
||||
|
@ -383,7 +385,8 @@ define([
|
|||
id: "1",
|
||||
title: "",
|
||||
startDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -397,7 +400,8 @@ define([
|
|||
id: "1",
|
||||
title: " ",
|
||||
startDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -410,7 +414,8 @@ define([
|
|||
let period = {
|
||||
title: "Period without Start Date",
|
||||
startDate: undefined,
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -423,7 +428,22 @@ define([
|
|||
let period = {
|
||||
title: "Period without End Date",
|
||||
startDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
endDate: null
|
||||
endDate: null,
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
this.callOnSave(set, period);
|
||||
notOk(gradingPeriodsApi.batchUpdate.called, "does not call update");
|
||||
ok(set.refs.editPeriodForm, "form is still visible");
|
||||
});
|
||||
|
||||
test('does not save a grading period without a valid closeDate', function() {
|
||||
let period = {
|
||||
title: "Period without End Date",
|
||||
startDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
closeDate: null
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -436,7 +456,8 @@ define([
|
|||
let period = {
|
||||
title: "Period with Overlapping Start Date",
|
||||
startDate: new Date("2015-04-30T20:11:00+00:00"),
|
||||
endDate: new Date("2015-05-30T00:00:00+00:00")
|
||||
endDate: new Date("2015-05-30T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-05-30T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -449,7 +470,8 @@ define([
|
|||
let period = {
|
||||
title: "Period with Overlapping End Date",
|
||||
startDate: new Date("2014-12-30T20:11:00+00:00"),
|
||||
endDate: new Date("2015-01-30T00:00:00+00:00")
|
||||
endDate: new Date("2015-01-30T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-01-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -462,7 +484,22 @@ define([
|
|||
let period = {
|
||||
title: "Overlapping Period",
|
||||
startDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
endDate: new Date("2015-03-02T20:11:00+00:00")
|
||||
endDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
this.callOnSave(set, period);
|
||||
notOk(gradingPeriodsApi.batchUpdate.called, "does not call update");
|
||||
ok(set.refs.editPeriodForm, "form is still visible");
|
||||
});
|
||||
|
||||
test('does not save a grading period with closeDate before endDate', function() {
|
||||
let period = {
|
||||
title: "Overlapping Period",
|
||||
startDate: new Date("2015-03-01T00:00:00+00:00"),
|
||||
endDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
closeDate: new Date("2015-03-02T20:10:59+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -677,7 +714,8 @@ define([
|
|||
let period = {
|
||||
title: "",
|
||||
startDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -690,7 +728,8 @@ define([
|
|||
let period = {
|
||||
title: "Period without Start Date",
|
||||
startDate: undefined,
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
endDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -703,7 +742,8 @@ define([
|
|||
let period = {
|
||||
title: "Period without End Date",
|
||||
startDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
endDate: null
|
||||
endDate: null,
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -716,7 +756,8 @@ define([
|
|||
let period = {
|
||||
title: "Period with Overlapping Start Date",
|
||||
startDate: new Date("2015-04-30T20:11:00+00:00"),
|
||||
endDate: new Date("2015-05-30T00:00:00+00:00")
|
||||
endDate: new Date("2015-05-30T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-05-30T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -729,7 +770,8 @@ define([
|
|||
let period = {
|
||||
title: "Period with Overlapping End Date",
|
||||
startDate: new Date("2014-12-30T20:11:00+00:00"),
|
||||
endDate: new Date("2015-01-30T00:00:00+00:00")
|
||||
endDate: new Date("2015-01-30T00:00:00+00:00"),
|
||||
closeDate: new Date("2015-01-30T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
@ -742,7 +784,8 @@ define([
|
|||
let period = {
|
||||
title: "Overlapping Period",
|
||||
startDate: new Date("2015-03-03T00:00:00+00:00"),
|
||||
endDate: new Date("2015-03-02T20:11:00+00:00")
|
||||
endDate: new Date("2015-03-02T20:11:00+00:00"),
|
||||
closeDate: new Date("2015-03-03T00:00:00+00:00")
|
||||
};
|
||||
let update = this.stubUpdate();
|
||||
let set = this.renderComponent();
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
require(["jsx/speed_grader/mgp"], ({
|
||||
gradingPeriodForDate,
|
||||
dueDateForStudent,
|
||||
assignmentClosedForStudent,
|
||||
}) => {
|
||||
module("Speedgrader MGP Spec");
|
||||
|
||||
const MS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
const NOW = new Date().getTime();
|
||||
const closedGradingPeriod = {
|
||||
start_date: new Date(1999, 0, 1).toISOString(),
|
||||
end_date: new Date(1999, 5, 1).toISOString(),
|
||||
close_date: new Date(1999, 6, 1).toISOString(),
|
||||
};
|
||||
// this one is over but not closed
|
||||
const pastGradingPeriod = {
|
||||
start_date: new Date(NOW - MS_IN_DAY * 8).toISOString(),
|
||||
end_date: new Date(NOW - MS_IN_DAY * 2).toISOString(),
|
||||
close_date: new Date(NOW + MS_IN_DAY * 1).toISOString(),
|
||||
};
|
||||
const currentGradingPeriod = {
|
||||
start_date: new Date(NOW - MS_IN_DAY * 1).toISOString(),
|
||||
end_date: new Date(NOW + MS_IN_DAY * 7).toISOString(),
|
||||
close_date: new Date(NOW + MS_IN_DAY * 14).toISOString(),
|
||||
};
|
||||
|
||||
const gradingPeriods = [
|
||||
closedGradingPeriod,
|
||||
pastGradingPeriod,
|
||||
currentGradingPeriod
|
||||
];
|
||||
|
||||
test("gradingPeriodForDate", () => {
|
||||
const pastGPDate = new Date(NOW - MS_IN_DAY * 3).toISOString();
|
||||
ok(gradingPeriodForDate(pastGPDate, gradingPeriods) === pastGradingPeriod);
|
||||
|
||||
const currentGPDate = new Date(NOW + MS_IN_DAY * 5).toISOString();
|
||||
ok(gradingPeriodForDate(currentGPDate, gradingPeriods) ===
|
||||
currentGradingPeriod);
|
||||
|
||||
const invalidDate = new Date(NOW + MS_IN_DAY * 10).toISOString();
|
||||
ok(gradingPeriodForDate(invalidDate, gradingPeriods) ===
|
||||
undefined);
|
||||
|
||||
ok(gradingPeriodForDate(null, gradingPeriods) === currentGradingPeriod);
|
||||
});
|
||||
|
||||
const student = {id: 1};
|
||||
const studentOverride = {student_ids: [1], due_at: currentGradingPeriod.start_date};
|
||||
const sectionOverride = {course_section_id: 2, due_at: currentGradingPeriod.end_date};
|
||||
const overrides = [studentOverride,sectionOverride];
|
||||
|
||||
test("dueDateForStudent", () => {
|
||||
ok(dueDateForStudent(student, [{default: true, due_at: NOW}]) === NOW,
|
||||
"no assignment overrides returns default due date");
|
||||
|
||||
ok(dueDateForStudent(student, [
|
||||
{default: true, due_at: currentGradingPeriod.start_date},
|
||||
...overrides
|
||||
]) == studentOverride.due_at,
|
||||
"returns overrides for matching student_ids");
|
||||
|
||||
ok(dueDateForStudent({...student, section_ids: [2]}, [
|
||||
{default: true, due_at: closedGradingPeriod.end_date},
|
||||
...overrides
|
||||
]) == sectionOverride.due_at,
|
||||
"returns section due dates");
|
||||
|
||||
ok(dueDateForStudent(student,
|
||||
[{default: true, due_at: null}, studentOverride]
|
||||
) == null,
|
||||
"returns most lenient date");
|
||||
});
|
||||
|
||||
test("assignmentClosedForStudent", () => {
|
||||
const dueAt = closedGradingPeriod.start_date
|
||||
ok(!assignmentClosedForStudent(student, {
|
||||
due_at: dueAt,
|
||||
gradingPeriods: gradingPeriods,
|
||||
assignmentOverrides: overrides
|
||||
}));
|
||||
|
||||
ok(assignmentClosedForStudent(student, {
|
||||
due_at: null,
|
||||
only_visible_to_overrides: true,
|
||||
gradingPeriods: gradingPeriods,
|
||||
assignmentOverrides: [{
|
||||
student_ids: [student.id],
|
||||
due_at: dueAt
|
||||
}],
|
||||
}), "respects only_visible_to_overrides");
|
||||
|
||||
const closedStudent = {id: 99};
|
||||
ok(assignmentClosedForStudent(closedStudent, {
|
||||
due_at: dueAt,
|
||||
gradingPeriods: gradingPeriods,
|
||||
assignmentOverrides: overrides
|
||||
}));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe DataFixup::PopulateGradingPeriodCloseDates do
|
||||
before(:each) do
|
||||
root_account = Account.create(name: 'new account')
|
||||
group = Factories::GradingPeriodGroupHelper.new.create_for_account(root_account)
|
||||
period_helper = Factories::GradingPeriodHelper.new
|
||||
@first_period = period_helper.create_presets_for_group(group, :past).first
|
||||
@first_period.close_date = nil
|
||||
@first_period.save!
|
||||
@second_period = period_helper.create_presets_for_group(group, :current).first
|
||||
@second_period.close_date = 3.days.from_now(@second_period.end_date)
|
||||
@second_period.save!
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
DataFixup::PopulateGradingPeriodCloseDates.run
|
||||
end
|
||||
|
||||
it "does not alter already-set close dates" do
|
||||
@second_period.reload
|
||||
expect(@second_period.close_date).to eq 3.days.from_now(@second_period.end_date)
|
||||
end
|
||||
|
||||
it "sets the close date to the end date for periods with nil close dates" do
|
||||
@first_period.reload
|
||||
expect(@first_period.close_date).to eq @first_period.end_date
|
||||
end
|
||||
end
|
|
@ -21,7 +21,11 @@ require_relative '../spec_helper'
|
|||
require 'csv'
|
||||
|
||||
describe GradebookImporter do
|
||||
let(:gradebook_user){ user_model }
|
||||
let(:gradebook_user) do
|
||||
teacher = User.create!
|
||||
course_with_teacher(user: teacher, course: @course)
|
||||
teacher
|
||||
end
|
||||
|
||||
context "construction" do
|
||||
let!(:gradebook_course){ course_model }
|
||||
|
@ -386,9 +390,10 @@ describe GradebookImporter do
|
|||
|
||||
describe "simplified json output" do
|
||||
it "has only the specified keys" do
|
||||
keys = [:assignments,:assignments_outside_current_periods,
|
||||
:missing_objects, :original_submissions, :students,
|
||||
:unchanged_assignments]
|
||||
keys = [:assignments, :missing_objects,
|
||||
:original_submissions, :students,
|
||||
:unchanged_assignments,
|
||||
:warning_messages]
|
||||
expect(hash.keys.sort).to eql(keys)
|
||||
end
|
||||
|
||||
|
@ -398,12 +403,12 @@ describe GradebookImporter do
|
|||
end
|
||||
|
||||
it "a submission only has specified keys" do
|
||||
keys = ["assignment_id", "grade", "original_grade"]
|
||||
keys = ["assignment_id", "grade", "gradeable", "original_grade"]
|
||||
expect(submission.keys.sort).to eql(keys)
|
||||
end
|
||||
|
||||
it "an assignment only has specified keys" do
|
||||
keys = [:due_at, :grading_type, :id, :points_possible, :previous_id,
|
||||
keys = [:grading_type, :id, :points_possible, :previous_id,
|
||||
:title]
|
||||
expect(assignment.keys.sort).to eql(keys)
|
||||
end
|
||||
|
@ -453,120 +458,235 @@ describe GradebookImporter do
|
|||
expect(@gi.assignments.last.title).to eq 'a3'
|
||||
expect(@gi.assignments.last).to be_new_record
|
||||
expect(@gi.assignments.last.id).to be < 0
|
||||
json = @gi.as_json
|
||||
expect(json[:students][0][:submissions].first["grade"]).to eq "1"
|
||||
expect(json[:students][0][:submissions].last["grade"]).to eq "3"
|
||||
submissions = @gi.as_json[:students][0][:submissions]
|
||||
expect(submissions.length).to eq(2)
|
||||
expect(submissions.first["grade"]).to eq "1"
|
||||
expect(submissions.last["grade"]).to eq "3"
|
||||
end
|
||||
end
|
||||
|
||||
context "multiple grading periods" do
|
||||
let(:group) { Factories::GradingPeriodGroupHelper.new.legacy_create_for_course(course) }
|
||||
let!(:old_period) do
|
||||
old_period_params = { title: "Course Period 2: old period",
|
||||
start_date: 2.months.ago,
|
||||
end_date: 1.month.ago }
|
||||
group.grading_periods.create old_period_params
|
||||
before(:once) do
|
||||
account = Account.default
|
||||
@course = account.courses.create!
|
||||
@teacher = User.create!
|
||||
course_with_teacher(course: @course, user: @teacher, active_enrollment: true)
|
||||
account.enable_feature!(:multiple_grading_periods)
|
||||
group = account.grading_period_groups.create!
|
||||
group.enrollment_terms << @course.enrollment_term
|
||||
@now = Time.zone.now
|
||||
group.grading_periods.create!(
|
||||
title: "Closed Period",
|
||||
start_date: 3.months.ago(@now),
|
||||
end_date: 1.month.ago(@now),
|
||||
close_date: 1.month.ago(@now)
|
||||
)
|
||||
|
||||
@active_period = group.grading_periods.create!(
|
||||
title: "Active Period",
|
||||
start_date: 1.month.ago(@now),
|
||||
end_date: 2.months.from_now(@now),
|
||||
close_date: 2.months.from_now(@now)
|
||||
)
|
||||
|
||||
@closed_assignment = @course.assignments.create!(
|
||||
name: "Assignment in closed period",
|
||||
points_possible: 10,
|
||||
due_at: date_in_closed_period
|
||||
)
|
||||
|
||||
@open_assignment = @course.assignments.create!(
|
||||
name: "Assignment in open period",
|
||||
points_possible: 10,
|
||||
due_at: date_in_open_period
|
||||
)
|
||||
end
|
||||
|
||||
let!(:current_period) do
|
||||
current_period_params = { title: "Course Period 1: current period",
|
||||
start_date: 1.month.ago,
|
||||
end_date: 1.month.from_now }
|
||||
group.grading_periods.create current_period_params
|
||||
end
|
||||
let(:assignments) { @gi.as_json[:assignments] }
|
||||
let(:date_in_open_period) { 1.month.from_now(@now) }
|
||||
let(:date_in_closed_period) { 2.months.ago(@now) }
|
||||
let(:student_submissions) { @gi.as_json[:students][0][:submissions] }
|
||||
|
||||
let(:future_period) do
|
||||
future_period_params = { title: "Course Period 3: future period",
|
||||
start_date: 1.month.from_now,
|
||||
end_date: 2.months.from_now }
|
||||
group.grading_periods.create future_period_params
|
||||
end
|
||||
|
||||
let(:account) { Account.default }
|
||||
let(:course) { Course.create account: account }
|
||||
let(:student) { User.create }
|
||||
let(:progress) { Progress.create tag: "test", context: student }
|
||||
|
||||
let(:importer_json) do
|
||||
lambda do |hashes|
|
||||
hashes.each { |hash| course.assignments.create hash }
|
||||
|
||||
contents = <<CSV
|
||||
Student,ID,Section,#{course.assignments.map(&:name).join(',')}
|
||||
,#{student.id},#{',9' * course.assignments.length}
|
||||
CSV
|
||||
upload = GradebookUpload.create!(course: course, user: student, progress: progress)
|
||||
attachment = attachment_with_rows(contents)
|
||||
importer = GradebookImporter.new(upload, attachment, student, progress)
|
||||
importer.parse!
|
||||
importer.as_json
|
||||
end
|
||||
end
|
||||
|
||||
describe "assignments_outside_current_periods" do
|
||||
describe "when multiple grading periods is on" do
|
||||
before do
|
||||
course.root_account.enable_feature! :multiple_grading_periods
|
||||
context "uploading submissions for existing assignments" do
|
||||
context "assignments without overrides" do
|
||||
before(:once) do
|
||||
@student = User.create!
|
||||
course_with_student(course: @course, user: @student, active_enrollment: true)
|
||||
end
|
||||
|
||||
describe "empty assignments_outside_current_periods" do
|
||||
it "when assignments are in a current grading period" do
|
||||
assignment_hashes = [ { name: 'Assignment 1',
|
||||
points_possible: 10,
|
||||
due_at: Time.zone.now } ]
|
||||
json = importer_json.call(assignment_hashes)
|
||||
expect(json[:assignments_outside_current_periods]).to be_empty
|
||||
|
||||
it "excludes entire assignments if no submissions for the assignment are being uploaded" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5",
|
||||
)
|
||||
assignment_ids = assignments.map { |a| a[:id] }
|
||||
expect(assignment_ids).to_not include @closed_assignment.id
|
||||
end
|
||||
|
||||
it "includes assignments if there is at least one submission in the assignment being uploaded" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5",
|
||||
)
|
||||
assignment_ids = assignments.map { |a| a[:id] }
|
||||
expect(assignment_ids).to include @open_assignment.id
|
||||
end
|
||||
|
||||
context "submissions already exist" do
|
||||
before(:once) do
|
||||
@closed_assignment.grade_student(@student, grade: 8)
|
||||
@open_assignment.grade_student(@student, grade: 8)
|
||||
end
|
||||
|
||||
it "when all assignments have no due_ats" do
|
||||
assignment_hashes = [ { points_possible: 10,
|
||||
name: 'Assignment 2' } ]
|
||||
json = importer_json.call(assignment_hashes)
|
||||
expect(json[:assignments_outside_current_periods]).to be_empty
|
||||
it "does not include submissions that fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5",
|
||||
)
|
||||
assignment_ids = student_submissions.map { |s| s['assignment_id'] }
|
||||
expect(assignment_ids).to_not include @closed_assignment.id
|
||||
end
|
||||
|
||||
it "when assignment due_ats are nil and there is a future period" do
|
||||
future_period
|
||||
assignment_hashes = [ { points_possible: 10,
|
||||
name: 'Assignment 2.five' } ]
|
||||
json = importer_json.call(assignment_hashes)
|
||||
expect(json[:assignments_outside_current_periods]).to be_empty
|
||||
it "includes submissions that do not fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5",
|
||||
)
|
||||
assignment_ids = student_submissions.map { |s| s['assignment_id'] }
|
||||
expect(assignment_ids).to include @open_assignment.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "when all assignments are in past grading periods" do
|
||||
it "indicates assignments not in a current grading period" do
|
||||
assignment_hashes = [ { points_possible: 10,
|
||||
name: 'Assignment 3',
|
||||
due_at: 6.weeks.ago } ]
|
||||
json = importer_json.call(assignment_hashes)
|
||||
past_assignment = json[:assignments_outside_current_periods].first
|
||||
expect(past_assignment[:title]).to eq 'Assignment 3'
|
||||
end
|
||||
end
|
||||
|
||||
describe "when some assignments are in past grading periods" do
|
||||
it "indicates assignments not in a current grading period" do
|
||||
assignment_hashes = [ { points_possible: 10,
|
||||
name: 'Assignment 4',
|
||||
due_at: 6.weeks.ago},
|
||||
{ points_possible: 10,
|
||||
name: 'Assignment 5',
|
||||
due_at: 1.day.from_now } ]
|
||||
json = importer_json.call(assignment_hashes)
|
||||
past_assignment = json[:assignments_outside_current_periods].first
|
||||
expect(past_assignment[:title]).to eq 'Assignment 4'
|
||||
context "submissions do not already exist" do
|
||||
it "does not include submissions that will fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5",
|
||||
)
|
||||
expect(student_submissions.map {|s| s['assignment_id']}).to_not include @closed_assignment.id
|
||||
end
|
||||
|
||||
it "includes submissions that will not fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5",
|
||||
)
|
||||
expect(student_submissions.map {|s| s['assignment_id']}).to include @open_assignment.id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "should be empty when multiple grading periods is off" do
|
||||
assignment_hashes = [ { points_possible: 10,
|
||||
name: 'Assignment 6',
|
||||
due_at: 6.weeks.ago } ]
|
||||
json = importer_json.call(assignment_hashes)
|
||||
course.root_account.disable_feature! :multiple_grading_periods
|
||||
expect(json[:assignments_outside_current_periods]).to be_empty
|
||||
context "assignments with overrides" do
|
||||
before(:once) do
|
||||
section_one = @course.course_sections.create!(name: 'Section One')
|
||||
@student = student_in_section(section_one)
|
||||
|
||||
# set up overrides such that the student has a due date in an open grading period
|
||||
# for @closed_assignment and a due date in a closed grading period for @open_assignment
|
||||
@override_in_open_grading_period = @closed_assignment.assignment_overrides.create! do |override|
|
||||
override.set = section_one
|
||||
override.due_at_overridden = true
|
||||
override.due_at = date_in_open_period
|
||||
end
|
||||
|
||||
@open_assignment.assignment_overrides.create! do |override|
|
||||
override.set = section_one
|
||||
override.due_at_overridden = true
|
||||
override.due_at = date_in_closed_period
|
||||
end
|
||||
end
|
||||
|
||||
it "excludes entire assignments if there are no submissions in the assignment" \
|
||||
"being uploaded that are gradeable" do
|
||||
@override_in_open_grading_period.update_attribute(:due_at, date_in_closed_period)
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5"
|
||||
)
|
||||
assignment_ids = assignments.map { |a| a[:id] }
|
||||
expect(assignment_ids).not_to include @closed_assignment.id
|
||||
end
|
||||
|
||||
it "includes assignments if there is at least one submission in the assignment" \
|
||||
"being uploaded that is gradeable (it does not fall in a closed grading period)" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5"
|
||||
)
|
||||
assignment_ids = assignments.map { |a| a[:id] }
|
||||
expect(assignment_ids).to include @closed_assignment.id
|
||||
end
|
||||
|
||||
context "submissions already exist" do
|
||||
before(:once) do
|
||||
@closed_assignment.grade_student(@student, grade: 8)
|
||||
@open_assignment.grade_student(@student, grade: 8)
|
||||
end
|
||||
|
||||
it "does not include submissions that fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5"
|
||||
)
|
||||
assignment_ids = student_submissions.map { |s| s['assignment_id'] }
|
||||
expect(assignment_ids).not_to include @open_assignment.id
|
||||
end
|
||||
|
||||
it "includes submissions that do not fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5"
|
||||
)
|
||||
assignment_ids = student_submissions.map { |s| s['assignment_id'] }
|
||||
expect(assignment_ids).to include @closed_assignment.id
|
||||
end
|
||||
end
|
||||
|
||||
context "submissions do not already exist" do
|
||||
it "does not include submissions that will fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5"
|
||||
)
|
||||
assignment_ids = student_submissions.map {|s| s['assignment_id']}
|
||||
expect(assignment_ids).to_not include @open_assignment.id
|
||||
end
|
||||
|
||||
it "includes submissions that will not fall in closed grading periods" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Assignment in closed period,Assignment in open period",
|
||||
",#{@student.id},,5,5"
|
||||
)
|
||||
assignment_ids = student_submissions.map {|s| s['assignment_id']}
|
||||
expect(assignment_ids).to include @closed_assignment.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "uploading submissions for new assignments" do
|
||||
before(:once) do
|
||||
@student = User.create!
|
||||
course_with_student(course: @course, user: @student, active_enrollment: true)
|
||||
end
|
||||
|
||||
it "does not create a new assignment if the last grading period is closed" do
|
||||
@active_period.destroy!
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Some new assignment",
|
||||
",#{@student.id},,5",
|
||||
)
|
||||
expect(assignments.count).to eq(0)
|
||||
end
|
||||
|
||||
it "creates a new assignment if the last grading period is not closed" do
|
||||
importer_with_rows(
|
||||
"Student,ID,Section,Some new assignment",
|
||||
",#{@student.id},,5",
|
||||
)
|
||||
expect(assignments.count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
# Copyright (C) 2011 Instructure, Inc.
|
||||
#
|
||||
|
@ -26,7 +25,8 @@ describe Assignment do
|
|||
end
|
||||
|
||||
it "should create a new instance given valid attributes" do
|
||||
@course.assignments.create!(assignment_valid_attributes)
|
||||
course = @course.assignments.create!(assignment_valid_attributes)
|
||||
expect(course).to be_valid
|
||||
end
|
||||
|
||||
it "should have a useful state machine" do
|
||||
|
|
|
@ -59,29 +59,92 @@ describe GradingPeriod do
|
|||
expect(grading_period).to_not be_valid
|
||||
end
|
||||
|
||||
describe "#as_json_with_user_permissions" do
|
||||
it "includes the close_date in the returned object" do
|
||||
json = grading_period.as_json_with_user_permissions(User.new)
|
||||
expect(json).to have_key("close_date")
|
||||
end
|
||||
end
|
||||
|
||||
describe "close_date" do
|
||||
it "sets the close_date to the end_date if no close_date is provided" do
|
||||
grading_period = grading_period_group.grading_periods.create!(params.except(:close_date))
|
||||
expect(grading_period.close_date).to eq(grading_period.end_date)
|
||||
context "grading period group belonging to an account" do
|
||||
it "allows setting a close_date that is different from the end_date" do
|
||||
grading_period = grading_period_group.grading_periods.create!(params)
|
||||
expect(grading_period.close_date).not_to eq(grading_period.end_date)
|
||||
end
|
||||
|
||||
it "sets the close_date to the end_date if no close_date is provided" do
|
||||
grading_period = grading_period_group.grading_periods.create!(params.except(:close_date))
|
||||
expect(grading_period.close_date).to eq(grading_period.end_date)
|
||||
end
|
||||
|
||||
it "considers the grading period invalid if the close date is before the end date" do
|
||||
period_params = params.merge(close_date: 1.day.ago(params[:end_date]))
|
||||
grading_period = grading_period_group.grading_periods.build(period_params)
|
||||
expect(grading_period).to be_invalid
|
||||
end
|
||||
|
||||
it "considers the grading period valid if the close date is equal to the end date" do
|
||||
period_params = params.merge(close_date: params[:end_date])
|
||||
grading_period = grading_period_group.grading_periods.build(period_params)
|
||||
expect(grading_period).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
it "allows setting a close_date that is different from the end_date" do
|
||||
skip
|
||||
grading_period = grading_period_group.grading_periods.create!(params)
|
||||
expect(grading_period.close_date).not_to eq(grading_period.end_date)
|
||||
context "grading period group belonging to a course" do
|
||||
let(:course_grading_period_group) { group_helper.legacy_create_for_course(course) }
|
||||
|
||||
it "does not allow setting a close_date that is different from the end_date" do
|
||||
grading_period = course_grading_period_group.grading_periods.create!(params)
|
||||
expect(grading_period.close_date).to eq(params[:end_date])
|
||||
end
|
||||
|
||||
it "sets the close_date to the end_date if no close_date is provided" do
|
||||
grading_period = course_grading_period_group.grading_periods.create!(params.except(:close_date))
|
||||
expect(grading_period.close_date).to eq(grading_period.end_date)
|
||||
end
|
||||
|
||||
it "sets the close_date to the end_date when the grading period is updated" do
|
||||
grading_period = course_grading_period_group.grading_periods.create!(params.except(:close_date))
|
||||
new_end_date = 5.weeks.from_now(now)
|
||||
grading_period.end_date = new_end_date
|
||||
grading_period.save!
|
||||
expect(grading_period.close_date).to eq(new_end_date)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#closed?" do
|
||||
around { |example| Timecop.freeze(now, &example) }
|
||||
|
||||
it "returns true if the current date is past the close date" do
|
||||
period = grading_period_group.grading_periods.build(
|
||||
title: "Closed Period",
|
||||
start_date: 10.days.ago(now),
|
||||
end_date: 5.days.ago(now),
|
||||
close_date: 3.days.ago(now)
|
||||
)
|
||||
expect(period).to be_closed
|
||||
end
|
||||
|
||||
it "considers the grading period invalid if the close date is before the end date" do
|
||||
skip
|
||||
period_params = params.merge(close_date: 1.day.ago(params[:end_date]))
|
||||
grading_period = grading_period_group.grading_periods.build(period_params)
|
||||
expect(grading_period).to be_invalid
|
||||
it "returns false if the current date is before the close date" do
|
||||
period = grading_period_group.grading_periods.build(
|
||||
title: "Open Period",
|
||||
start_date: 10.days.ago(now),
|
||||
end_date: 5.days.ago(now),
|
||||
close_date: 2.days.from_now(now)
|
||||
)
|
||||
expect(period).not_to be_closed
|
||||
end
|
||||
|
||||
it "considers the grading period valid if the close date is equal to the end date" do
|
||||
period_params = params.merge(close_date: params[:end_date])
|
||||
grading_period = grading_period_group.grading_periods.build(period_params)
|
||||
expect(grading_period).to be_valid
|
||||
it "returns false if the current date matches the close date" do
|
||||
period = grading_period_group.grading_periods.build(
|
||||
title: "Open Period",
|
||||
start_date: 10.days.ago(now),
|
||||
end_date: 5.days.ago(now),
|
||||
close_date: now
|
||||
)
|
||||
expect(period).not_to be_closed
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -178,7 +241,7 @@ describe GradingPeriod do
|
|||
it "does not include grading periods from the course enrollment term group if inherit is false" do
|
||||
group = group_helper.create_for_account(@root_account)
|
||||
term.update_attribute(:grading_period_group_id, group)
|
||||
period_1 = period_helper.create_with_weeks_for_group(group, 5, 3)
|
||||
period_helper.create_with_weeks_for_group(group, 5, 3)
|
||||
period_2 = period_helper.create_with_weeks_for_group(group, 3, 1)
|
||||
period_2.workflow_state = :deleted
|
||||
period_2.save
|
||||
|
@ -212,8 +275,8 @@ describe GradingPeriod do
|
|||
|
||||
it "does not return grading periods on the course directly" do
|
||||
group = group_helper.legacy_create_for_course(@course)
|
||||
period_1 = period_helper.create_with_weeks_for_group(group, 5, 3)
|
||||
period_2 = period_helper.create_with_weeks_for_group(group, 3, 1)
|
||||
period_helper.create_with_weeks_for_group(group, 5, 3)
|
||||
period_helper.create_with_weeks_for_group(group, 3, 1)
|
||||
expect(GradingPeriod.for(@root_account)).to match_array([])
|
||||
end
|
||||
|
||||
|
|
|
@ -35,6 +35,133 @@ describe Submission do
|
|||
}
|
||||
end
|
||||
|
||||
describe "Multiple Grading Periods" do
|
||||
let(:in_closed_grading_period) { 9.days.ago }
|
||||
let(:in_open_grading_period) { 1.day.from_now }
|
||||
let(:outside_of_any_grading_period) { 10.days.from_now }
|
||||
|
||||
before(:once) do
|
||||
@root_account = @context.root_account
|
||||
@root_account.enable_feature!(:multiple_grading_periods)
|
||||
group = @root_account.grading_period_groups.create!
|
||||
@closed_period = group.grading_periods.create!(
|
||||
title: "Closed!",
|
||||
start_date: 2.weeks.ago,
|
||||
end_date: 1.week.ago,
|
||||
close_date: 3.days.ago
|
||||
)
|
||||
@open_period = group.grading_periods.create!(
|
||||
title: "Open!",
|
||||
start_date: 3.days.ago,
|
||||
end_date: 3.days.from_now,
|
||||
close_date: 5.days.from_now
|
||||
)
|
||||
group.enrollment_terms << @context.enrollment_term
|
||||
end
|
||||
|
||||
describe "#in_closed_grading_period?" do
|
||||
it "returns true if the submission is due in a closed grading period" do
|
||||
@assignment.due_at = in_closed_grading_period
|
||||
@assignment.save!
|
||||
submission = Submission.create!(@valid_attributes)
|
||||
expect(submission).to be_in_closed_grading_period
|
||||
end
|
||||
|
||||
it "returns false if the submission is due in an open grading period" do
|
||||
@assignment.due_at = in_open_grading_period
|
||||
@assignment.save!
|
||||
submission = Submission.create!(@valid_attributes)
|
||||
expect(submission).not_to be_in_closed_grading_period
|
||||
end
|
||||
|
||||
it "returns false if the submission is due outside of any grading period" do
|
||||
@assignment.due_at = outside_of_any_grading_period
|
||||
@assignment.save!
|
||||
submission = Submission.create!(@valid_attributes)
|
||||
expect(submission).not_to be_in_closed_grading_period
|
||||
end
|
||||
end
|
||||
|
||||
describe "permissions" do
|
||||
before(:once) do
|
||||
@admin = user(active_all: true)
|
||||
@root_account.account_users.create!(user: @admin)
|
||||
@teacher = user(active_all: true)
|
||||
@context.enroll_teacher(@teacher)
|
||||
end
|
||||
|
||||
describe "grade" do
|
||||
context "the submission is due in a closed grading period" do
|
||||
before(:once) do
|
||||
@assignment.due_at = in_closed_grading_period
|
||||
@assignment.save!
|
||||
@submission = Submission.create!(@valid_attributes)
|
||||
end
|
||||
|
||||
it "has grade permissions if the user is a root account admin" do
|
||||
expect(@submission.grants_right?(@admin, :grade)).to eq(true)
|
||||
end
|
||||
|
||||
it "does not have grade permissions if the user is not a root account admin" do
|
||||
expect(@submission.grants_right?(@teacher, :grade)).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "the submission is due in an open grading period" do
|
||||
before(:once) do
|
||||
@assignment.due_at = in_open_grading_period
|
||||
@assignment.save!
|
||||
@submission = Submission.create!(@valid_attributes)
|
||||
end
|
||||
|
||||
it "has grade permissions if the user is a root account admin" do
|
||||
expect(@submission.grants_right?(@admin, :grade)).to eq(true)
|
||||
end
|
||||
|
||||
it "has grade permissions if the user is non-root account admin with manage_grades permissions" do
|
||||
expect(@submission.grants_right?(@teacher, :grade)).to eq(true)
|
||||
end
|
||||
|
||||
it "has not have grade permissions if the user is non-root account admin without manage_grades permissions" do
|
||||
@student = user(active_all: true)
|
||||
@context.enroll_student(@student)
|
||||
expect(@submission.grants_right?(@student, :grade)).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "the submission is due outside of any grading period" do
|
||||
before(:once) do
|
||||
@assignment.due_at = outside_of_any_grading_period
|
||||
@assignment.save!
|
||||
@submission = Submission.create!(@valid_attributes)
|
||||
end
|
||||
|
||||
it "has grade permissions if the user is a root account admin" do
|
||||
expect(@submission.grants_right?(@admin, :grade)).to eq(true)
|
||||
end
|
||||
|
||||
it "has grade permissions if the user is non-root account admin with manage_grades permissions" do
|
||||
expect(@submission.grants_right?(@teacher, :grade)).to eq(true)
|
||||
end
|
||||
|
||||
it "has not have grade permissions if the user is non-root account admin without manage_grades permissions" do
|
||||
@student = user(active_all: true)
|
||||
@context.enroll_student(@student)
|
||||
expect(@submission.grants_right?(@student, :grade)).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "#in_closed_grading_period? returns false if the course does not have Multiple Grading Periods enabled" do
|
||||
@context.root_account.disable_feature!(:multiple_grading_periods)
|
||||
@assignment.due_at = 9.days.ago
|
||||
@assignment.save!
|
||||
submission = Submission.create!(@valid_attributes)
|
||||
expect(submission).not_to be_in_closed_grading_period
|
||||
end
|
||||
|
||||
it "should create a new instance given valid attributes" do
|
||||
Submission.create!(@valid_attributes)
|
||||
end
|
||||
|
|
|
@ -3018,6 +3018,27 @@ describe User do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#admin_of_root_account?" do
|
||||
before(:once) do
|
||||
@user = user(active_all: true)
|
||||
@root_account = Account.default
|
||||
end
|
||||
|
||||
it "returns false if the user is not an admin of the root account" do
|
||||
expect(@user).not_to be_admin_of_root_account(@root_account)
|
||||
end
|
||||
|
||||
it "returns true if the user is an admin of the root account" do
|
||||
@root_account.account_users.create!(user: @user)
|
||||
expect(@user).to be_admin_of_root_account(@root_account)
|
||||
end
|
||||
|
||||
it "raises an error if the given account is not a root account" do
|
||||
sub_account = @root_account.sub_accounts.create!
|
||||
expect { @user.admin_of_root_account?(sub_account) }.to raise_error("must be a root account")
|
||||
end
|
||||
end
|
||||
|
||||
it "should not grant user_notes rights to restricted users" do
|
||||
course_with_ta(:active_all => true)
|
||||
student_in_course(:course => @course, :active_all => true)
|
||||
|
|
|
@ -47,13 +47,6 @@ describe "gradebook2" do
|
|||
context "return focus to settings menu when it closes" do
|
||||
let!(:open_gradebook_settings_menu) { f('#gradebook_settings').click }
|
||||
|
||||
it "after set group weights closes", priority: "2", test_id: 720464 do
|
||||
f("[aria-controls='assignment_group_weights_dialog']").click
|
||||
f('.ui-dialog-titlebar-close').click
|
||||
|
||||
expect(active_element).to have_attribute('id', 'gradebook_settings')
|
||||
end
|
||||
|
||||
it "after hide/show student names is clicked", priority: "2", test_id: 720461 do
|
||||
f(".student_names_toggle").click
|
||||
|
||||
|
|
|
@ -48,10 +48,6 @@ describe "group weights" do
|
|||
end
|
||||
|
||||
it 'should show total column as points' do
|
||||
points_array = ["25"]
|
||||
unweighted_array = ["41.67%"]
|
||||
weighted_array = ["45%"]
|
||||
|
||||
@assignment1.grade_student @student, :grade => 20
|
||||
@assignment2.grade_student @student, :grade => 5
|
||||
|
||||
|
@ -60,37 +56,19 @@ describe "group weights" do
|
|||
|
||||
# Displays total column as points
|
||||
get "/courses/#{@course.id}/gradebook2"
|
||||
expect(student_totals).to eq(points_array)
|
||||
wait_for_ajax_requests
|
||||
|
||||
# Display weighted totals
|
||||
toggle_group_weight
|
||||
expect(student_totals).to eq(weighted_array)
|
||||
|
||||
# Display unweighted totals again
|
||||
toggle_group_weight
|
||||
expect(student_totals).to eq(unweighted_array)
|
||||
expect(student_totals).to eq(["25"])
|
||||
end
|
||||
|
||||
it "should validate setting group weights", priority: "1", test_id: 164007 do
|
||||
weight_numbers = [26.1, 73.5]
|
||||
it 'should show total column as percent' do
|
||||
@assignment1.grade_student @student, :grade => 20
|
||||
@assignment2.grade_student @student, :grade => 5
|
||||
|
||||
@course.show_total_grade_as_points = false
|
||||
@course.update_attributes(:group_weighting_scheme => 'percent')
|
||||
|
||||
# Displays total column as points
|
||||
get "/courses/#{@course.id}/gradebook2"
|
||||
wait_for_ajaximations
|
||||
|
||||
group_1 = AssignmentGroup.where(name: @group1.name).first
|
||||
group_2 = AssignmentGroup.where(name: @group2.name).first
|
||||
|
||||
#set and check the group weight of the first assignment group
|
||||
set_group_weight(group_1, weight_numbers[0])
|
||||
|
||||
#set and check the group weight of the second assignment group
|
||||
set_group_weight(group_2, weight_numbers[1])
|
||||
validate_group_weight(group_2, weight_numbers[1])
|
||||
|
||||
# check display of group weights in column heading
|
||||
# TODO: make the header cell in the UI update to reflect new value
|
||||
# validate_group_weight_text(AssignmentGroup.all, weight_numbers)
|
||||
expect(student_totals).to eq(["45%"])
|
||||
end
|
||||
|
||||
context "warning message" do
|
||||
|
@ -124,13 +102,10 @@ describe "group weights" do
|
|||
expect(ff('.icon-warning').count).to eq(2)
|
||||
end
|
||||
|
||||
it 'should remove triangle warnings if group weights are turned off in gradebook', priority: "1", test_id: 305579 do
|
||||
it 'should not display triangle warnings if group weights are turned off in gradebook', priority: "1", test_id: 305579 do
|
||||
@course.apply_assignment_group_weights = false
|
||||
@course.save!
|
||||
get "/courses/#{@course.id}/gradebook"
|
||||
f('#gradebook_settings').click
|
||||
f("[aria-controls='assignment_group_weights_dialog']").click
|
||||
f('#group_weighting_scheme').click
|
||||
submit_dialog('.ui-dialog-buttonset', '.ui-button')
|
||||
refresh_page
|
||||
expect(f("body")).not_to contain_css('.icon-warning')
|
||||
end
|
||||
|
||||
|
|
|
@ -280,32 +280,6 @@ describe "Screenreader Gradebook" do
|
|||
expect(ff('#assignment_information table td').map(&:text)).to eq ['20', '10', '15', '5']
|
||||
end
|
||||
|
||||
context 'Group Weights' do
|
||||
before(:each) do
|
||||
enroll_teacher_and_students
|
||||
assignment_1
|
||||
assignment_5
|
||||
user_session(teacher)
|
||||
get "/courses/#{test_course.id}/gradebook/change_gradebook_version?version=srgb"
|
||||
end
|
||||
|
||||
it 'should display the group weighting dialog with group weights disabled', priority: '1', test_id: 163995 do
|
||||
group_weights_button.click
|
||||
expect(f("#assignment_group_weights_dialog table[style='opacity: 0.5;']")).to be_truthy
|
||||
end
|
||||
|
||||
it 'should correctly sync group weight settings between srgb and gb2', priority: '1', test_id: 588913 do
|
||||
turn_on_group_weights
|
||||
|
||||
# go back to gb2 to verify settings stuck
|
||||
get "/courses/#{test_course.id}/gradebook/change_gradebook_version?version=2"
|
||||
gradebook_settings_cog.click
|
||||
group_weights_menu.click
|
||||
|
||||
expect(f("#assignment_group_weights_dialog table[style='opacity: 1;']")).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context "as a teacher" do
|
||||
before(:each) do
|
||||
gradebook_data_setup
|
||||
|
|
|
@ -21,11 +21,11 @@ describe 'Screenreader Gradebook Student Information' do
|
|||
|
||||
before(:each) do
|
||||
course_setup
|
||||
login_to_srgb
|
||||
end
|
||||
|
||||
context 'in Student Information section' do
|
||||
it 'allows comments in Notes field', priority: "2", test_id: 615709 do
|
||||
login_to_srgb
|
||||
skip_if_chrome('fails in chrome - due to replace content')
|
||||
select_student(student)
|
||||
show_notes_option.click
|
||||
|
@ -37,7 +37,9 @@ describe 'Screenreader Gradebook Student Information' do
|
|||
|
||||
context 'displays no points possible warning' do
|
||||
before(:each) do
|
||||
turn_on_group_weights
|
||||
@course.apply_assignment_group_weights = true
|
||||
@course.save!
|
||||
login_to_srgb
|
||||
end
|
||||
|
||||
it "with only a student selected", priority: "2", test_id: 615711 do
|
||||
|
@ -55,4 +57,4 @@ describe 'Screenreader Gradebook Student Information' do
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,16 +39,22 @@ describe "gradebook2 - total points toggle" do
|
|||
submit_dialog(dialog, '.ui-button')
|
||||
end
|
||||
|
||||
it "setting group weights should switch to percentage", test_id: 164231, priority: "2" do
|
||||
it "shows points when group weights are not set" do
|
||||
@course.show_total_grade_as_points = true
|
||||
@course.save!
|
||||
get "/courses/#{@course.id}/gradebook2"
|
||||
|
||||
toggle_grade_display
|
||||
should_show_points
|
||||
end
|
||||
|
||||
it "shows percentages when group weights are set", test_id: 164231, priority: "2" do
|
||||
@course.show_total_grade_as_points = false
|
||||
@course.save!
|
||||
group = AssignmentGroup.where(name: @group.name).first
|
||||
set_group_weight(group, 50, enable_scheme: true)
|
||||
group.group_weight = 50
|
||||
group.save!
|
||||
|
||||
disable_group_weight
|
||||
get "/courses/#{@course.id}/gradebook2"
|
||||
should_show_percentages
|
||||
end
|
||||
|
||||
|
|
|
@ -50,11 +50,6 @@ describe 'Course Grading Periods' do
|
|||
expect(ff(grading_period_selector).length).to be 1
|
||||
end
|
||||
|
||||
it 'does not allow adding grading periods', priority: "1", test_id: 239999 do
|
||||
get "/courses/#{@course.id}/grading_standards"
|
||||
expect(f('#grading_periods')).to_not contain_css(('#add-period-button'))
|
||||
end
|
||||
|
||||
it 'allows updating grading periods', priority: "1", test_id: 202317 do
|
||||
period_helper.create_with_group_for_course(@course)
|
||||
get "/courses/#{@course.id}/grading_standards"
|
||||
|
|
|
@ -318,55 +318,4 @@ module Gradebook2Common
|
|||
def get_group_points
|
||||
ff('div.assignment-points-possible')
|
||||
end
|
||||
|
||||
def check_group_points(expected_weight_text)
|
||||
2..3.each do |i|
|
||||
expect(get_group_points[i].text).to eq expected_weight_text[i-2] + ' of grade'
|
||||
end
|
||||
end
|
||||
|
||||
def set_group_weight(assignment_group, weight_number, enable_scheme: false)
|
||||
f('#gradebook_settings').click
|
||||
f('[aria-controls="assignment_group_weights_dialog"]').click
|
||||
|
||||
dialog = f('#assignment_group_weights_dialog')
|
||||
expect(dialog).to be_displayed
|
||||
|
||||
if enable_scheme
|
||||
group_check = dialog.find_element(:id, 'group_weighting_scheme')
|
||||
group_check.click
|
||||
end
|
||||
expect(is_checked('#group_weighting_scheme')).to be_truthy
|
||||
group_weight_input = f("#assignment_group_#{assignment_group.id}_weight")
|
||||
set_value(group_weight_input, "")
|
||||
set_value(group_weight_input, weight_number)
|
||||
fj('.ui-button:contains("Save")').click
|
||||
wait_for_ajaximations
|
||||
expect(@course.reload.group_weighting_scheme).to eq 'percent'
|
||||
end
|
||||
|
||||
def disable_group_weight
|
||||
f('#gradebook_settings').click
|
||||
f('[aria-controls="assignment_group_weights_dialog"]').click
|
||||
|
||||
dialog = f('#assignment_group_weights_dialog')
|
||||
expect(dialog).to be_displayed
|
||||
|
||||
group_check = dialog.find_element(:id, 'group_weighting_scheme')
|
||||
group_check.click
|
||||
expect(is_checked('#group_weighting_scheme')).to be_falsey
|
||||
fj('.ui-button:contains("Save")').click
|
||||
refresh_page
|
||||
end
|
||||
|
||||
def validate_group_weight_text(assignment_groups, weight_numbers)
|
||||
assignment_groups.each_with_index do |ag, i|
|
||||
heading = fj(".slick-column-name:contains('#{ag.name}') .assignment-points-possible")
|
||||
expect(heading).to include_text("#{weight_numbers[i]}% of grade")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_group_weight(assignment_group, weight_number)
|
||||
expect(assignment_group.reload.group_weight).to eq weight_number
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,6 @@ module Gradebook2SRGBCommon
|
|||
let(:grade_for_label) { f("label[for='student_and_assignment_grade']") }
|
||||
let(:next_assignment_button) { fj("button:contains('Next Assignment')") }
|
||||
let(:submission_details_button) { f('#submission_details') }
|
||||
let(:group_weights_button) { f('#ag_weights') }
|
||||
let(:notes_field) { f('#student_information textarea') }
|
||||
let(:final_grade) { f('#student_information .total-grade') }
|
||||
let(:secondary_id_label) { f('#student_information .secondary_id') }
|
||||
|
@ -51,12 +50,6 @@ module Gradebook2SRGBCommon
|
|||
replace_content(input, grade)
|
||||
end
|
||||
|
||||
def turn_on_group_weights
|
||||
f('#ag_weights').click
|
||||
f('#group_weighting_scheme').click
|
||||
f('button .ui-button-text').click
|
||||
end
|
||||
|
||||
def tab_out_of_input(input_selector)
|
||||
# This is a hack for a timing issue with SRGB
|
||||
2.times { input_selector.send_keys(:tab) }
|
||||
|
|
|
@ -131,40 +131,6 @@ describe "interaction with multiple grading periods" do
|
|||
end
|
||||
end
|
||||
|
||||
context 'sub-accounts' do
|
||||
# top-level account & grading periods setup
|
||||
let(:parent_account) { Account.default }
|
||||
let!(:enable_mgp_flag) { parent_account.enable_feature!(:multiple_grading_periods) }
|
||||
# sub-account & grading periods setup
|
||||
let(:sub_account) { Account.create(name: 'Sub Account', parent_account: parent_account) }
|
||||
# sub-account course setup
|
||||
let(:sub_account_course) do
|
||||
sub_account.courses.create(
|
||||
name: 'Sub-Account Course',
|
||||
workflow_state: 'active'
|
||||
)
|
||||
end
|
||||
let(:sub_account_teacher) { user(active_all: true) }
|
||||
let(:enroll_teacher) do
|
||||
sub_account_course.enroll_user(
|
||||
sub_account_teacher,
|
||||
'TeacherEnrollment',
|
||||
enrollment_state: 'active'
|
||||
)
|
||||
end
|
||||
let(:view_sub_course_grading_period) do
|
||||
sub_account_course
|
||||
enroll_teacher
|
||||
user_session(sub_account_teacher)
|
||||
get "/courses/#{sub_account_course.id}/grading_standards"
|
||||
end
|
||||
|
||||
it 'does not allow creation of a GP in sub-account course', priority: "1", test_id: 587759 do
|
||||
view_sub_course_grading_period
|
||||
expect(f('#grading_periods')).not_to contain_css('#add-period-button')
|
||||
end
|
||||
end
|
||||
|
||||
context 'student view' do
|
||||
let(:account) { Account.default }
|
||||
let(:test_course) { account.courses.create!(name: 'New Course') }
|
||||
|
|
|
@ -130,12 +130,15 @@ describe "speed grader - quiz submissions" do
|
|||
Quizzes::SubmissionGrader.new(qs).grade_submission
|
||||
|
||||
get "/courses/#{@course.id}/gradebook/speed_grader?assignment_id=#{@assignment.id}"
|
||||
|
||||
input = f('#grade_container input')
|
||||
expect(input["readonly"]).to eq "true"
|
||||
|
||||
in_frame('speedgrader_iframe') do
|
||||
question_inputs = ff('.header .question_input')
|
||||
question_inputs.each { |qi| replace_content(qi, 3) }
|
||||
submit_form('#update_history_form')
|
||||
end
|
||||
input = f('#grade_container input')
|
||||
expect(input).to have_attribute('value', expected_points)
|
||||
end
|
||||
|
||||
|
|
|
@ -508,4 +508,33 @@ describe 'Speedgrader' do
|
|||
expect(keyboard_modal).not_to be_displayed
|
||||
end
|
||||
end
|
||||
|
||||
context "closed grading periods" do
|
||||
before(:once) do
|
||||
course_with_teacher(active_all: true)
|
||||
student_in_course(active_all: true)
|
||||
|
||||
account = @course.root_account
|
||||
account.enable_feature! :multiple_grading_periods
|
||||
|
||||
gpg = GradingPeriodGroup.new
|
||||
gpg.account_id = account
|
||||
gpg.save!
|
||||
gpg.grading_periods.create! start_date: 3.years.ago,
|
||||
end_date: 1.year.ago,
|
||||
close_date: 1.week.ago,
|
||||
title: "closed grading period"
|
||||
term = @course.enrollment_term
|
||||
term.update_attribute :grading_period_group, gpg
|
||||
|
||||
@assignment = @course.assignments.create! name: "aaa", due_at: 2.years.ago
|
||||
user_session(@teacher)
|
||||
end
|
||||
|
||||
it "disables grading" do
|
||||
get "/courses/#{@course.id}/gradebook/speed_grader?assignment_id=#{@assignment.id}"
|
||||
expect(f("#grade_container input")["readonly"]).to eq "true"
|
||||
expect(f("#closed_gp_notice")).to be_displayed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue