update due dates and availability info for quizzes on index page

fixes CNVS-9679

test plan:
  As a teacher:
  - The availability date should display in six different formats
    - Blank (when there is no availability dates)
    - "Available" (when the assignment is unlocked, and there is no lock date)
    - "Not available until <date>" (when the assignment is not unlocked yet)
    - "Available until <date>" (when the assignment is unlocked and has a lock date)
    - "Closed" (when the locked date has passed)
    - "Multiple Availability" (when there are multiple availability dates)
  - Add different variations on availability dates for quizzes
  - Check that the format appears correct
  - Generally availability and due dates should work the same between quizzes
    and assignments

  As a student:
    - The format of availability / due dates should generally work similarly
      to that of a teacher except:
    - It should never show "Multiple Availability" for due dates
    - It should never show "Multiple Availability" for availability dates

Change-Id: If68c15049f854ff42def76239e2dcfd4901fcc20
Reviewed-on: https://gerrit.instructure.com/26792
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
QA-Review: Caleb Guanzon <cguanzon@instructure.com>
Product-Review: Derek DeVries <ddevries@instructure.com>
This commit is contained in:
Derek DeVries 2013-11-26 12:56:06 -07:00
parent 980004aa49
commit 008a784bd1
8 changed files with 168 additions and 40 deletions

View File

@ -1,13 +1,16 @@
define [
'jquery'
'underscore'
'Backbone'
'compiled/models/Assignment'
'compiled/models/DateGroup'
'compiled/collections/AssignmentOverrideCollection'
'compiled/collections/DateGroupCollection'
'str/pluralize'
'i18n!quizzes'
'jquery.ajaxJSON'
'jquery.instructure_misc_helpers' # $.underscore
], ($, Backbone, Assignment, AssignmentOverrideCollection, pluralize, I18n) ->
], ($, _, Backbone, Assignment, DateGroup, AssignmentOverrideCollection, DateGroupCollection, pluralize, I18n) ->
class Quiz extends Backbone.Model
resourceName: 'quizzes'
@ -28,6 +31,7 @@ define [
@initUnpublishable()
@initQuestionsCount()
@initPointsCount()
@initAllDates()
# initialize attributes
initAssignment: ->
@ -64,6 +68,10 @@ define [
text = I18n.t('assignment_points_possible', 'pt', count: pts) if pts isnt null
@set 'possible_points_label', text
initAllDates: ->
if (allDates = @get('all_dates'))?
@set 'all_dates', new DateGroupCollection(allDates)
# publishing
publish: =>
@ -76,3 +84,44 @@ define [
disabledMessage: ->
I18n.t('cant_unpublish_when_students_submit', "Can't unpublish if there are student submissions")
# methods needed by views
dueAt: (date) =>
return @get 'due_at' unless arguments.length > 0
@set 'due_at', date
unlockAt: (date) =>
return @get 'unlock_at' unless arguments.length > 0
@set 'unlock_at', date
lockAt: (date) =>
return @get 'lock_at' unless arguments.length > 0
@set 'lock_at', date
htmlUrl: =>
@get 'url'
defaultDates: =>
group = new DateGroup
due_at: @get("due_at")
unlock_at: @get("unlock_at")
lock_at: @get("lock_at")
multipleDueDates: =>
dateGroups = @get("all_dates")
dateGroups && dateGroups.length > 1
allDates: =>
groups = @get("all_dates")
models = (groups and groups.models) or []
result = _.map models, (group) -> group.toJSON()
toView: =>
fields = [
'htmlUrl', 'multipleDueDates', 'allDates', 'dueAt', 'lockAt', 'unlockAt'
]
hash = id: @get 'id'
for field in fields
hash[field] = @[field]()
hash

View File

@ -5,11 +5,11 @@ define [
'compiled/views/PublishIconView'
'jst/quizzes/QuizItemGroupView'
'compiled/views/quizzes/QuizItemView'
], ($, _, CollectionView, PublishIconView, template, quizItemView) ->
], ($, _, CollectionView, PublishIconView, template, QuizItemView) ->
class ItemGroupView extends CollectionView
template: template
itemView: quizItemView
itemView: QuizItemView
tagName: 'div'
className: 'item-group-condensed'
@ -36,6 +36,3 @@ define [
renderItem: (model) =>
return if model.get 'hidden'
super
createItemView: (model) ->
new @itemView model: model, publishIconView: new PublishIconView(model: model)

View File

@ -3,9 +3,11 @@ define [
'jquery'
'underscore'
'Backbone'
'compiled/views/PublishIconView'
'compiled/views/assignments/DateDueColumnView'
'compiled/views/assignments/DateAvailableColumnView'
'jst/quizzes/QuizItemView'
'jst/_vddTooltip'
], (I18n, $, _, Backbone, template) ->
], (I18n, $, _, Backbone, PublishIconView, DateDueColumnView, DateAvailableColumnView, template) ->
class ItemView extends Backbone.View
@ -14,7 +16,9 @@ define [
tagName: 'li'
className: 'quiz'
@child 'publishIconView', '[data-view=publish-icon]'
@child 'publishIconView', '[data-view=publish-icon]'
@child 'dateDueColumnView', '[data-view=date-due]'
@child 'dateAvailableColumnView', '[data-view=date-available]'
events:
'click': 'clickRow'
@ -25,9 +29,19 @@ define [
multipleDates: I18n.t('multiple_due_dates', 'Multiple Dates')
initialize: (options) ->
@initializeChildViews()
@observeModel()
super
initializeChildViews: ->
@publishIconView = false
if @canManage()
@publishIconView = new PublishIconView(model: @model)
@dateDueColumnView = new DateDueColumnView(model: @model)
@dateAvailableColumnView = new DateAvailableColumnView(model: @model)
# make clicks follow through to url for entire row
clickRow: (e) =>
target = $(e.target)
@ -55,6 +69,9 @@ define [
upatePublishState: =>
@$('.ig-row').toggleClass('ig-published', @model.get('published'))
canManage: ->
ENV.PERMISSIONS.manage
toJSON: ->
base = _.extend(@model.toJSON(), @options)
if @model.get("multiple_due_dates")

View File

@ -55,13 +55,12 @@ class QuizzesController < ApplicationController
@quiz_options = @quizzes.each_with_object({}) do |q, hash|
hash[q.id] = {
:can_update => is_authorized_action?(q, @current_user, :update),
:can_unpublish => q.can_unpublish?,
:multiple_due_dates => q.multiple_due_dates_apply_to?(@current_user),
:due_at => q.overridden_for(@current_user).due_at,
:due_dates => OverrideTooltipPresenter.new(q, @current_user).due_date_summary,
:unlock_at => q.all_dates_visible_to(@current_user).first[:unlock_at]
:can_update => is_authorized_action?(q, @current_user, :update),
:can_unpublish => q.can_unpublish?
}
hash[q.id][:all_dates] = if is_authorized_action?(q, @current_user, :update)
q.dates_hash_visible_to(@current_user)
end
end
# legacy

View File

@ -27,7 +27,7 @@ li.quiz
.ig-details
right: 110px
width: 415px
width: 425px
#quiz_show
.alert

View File

@ -14,26 +14,10 @@
</a>
<div class="ig-details row-fluid">
<div class="span4 ellipses description">
{{#if multiple_due_dates}}
<strong>{{#t "quiz_due"}}Due{{/t}}</strong>
{{> vddTooltip}}
{{else}}
{{#if due_at}}
<strong>{{#t "quiz_due"}}Due{{/t}}</strong> {{tDateToString due_at "date_at_time"}}
{{/if}}
{{/if}}
</div>
<div class="span3 ellipses">{{question_count_label}}</div>
<div class="span3 ellipses">
{{#if unlock_at}}
<strong>{{#t "quiz_available"}}Available{{/t}}</strong> {{tDateToString unlock_at "short"}}
{{/if}}
</div>
<div class="span4 ellipses date-available" data-view="date-available"></div>
<div class="span4 ellipses date-due" data-view="date-due"></div>
<div class="span2 ellipses">{{possible_points_label}}</div>
<div class="span2 ellipses">{{question_count_label}}</div>
</div>
{{#if can_update}}

View File

@ -2,9 +2,10 @@ define [
'jquery'
'compiled/models/Quiz'
'compiled/models/Assignment'
'compiled/models/DateGroup'
'compiled/collections/AssignmentOverrideCollection'
'jquery.ajaxJSON'
], ($, Quiz, Assignment, AssignmentOverrideCollection) ->
], ($, Quiz, Assignment, DateGroup, AssignmentOverrideCollection) ->
module 'Quiz',
setup: ->
@ -109,3 +110,75 @@ define [
test '#unpublish sets published attribute to false', ->
@quiz.unpublish()
ok !@quiz.get('published')
# multiple due dates
module "Quiz#multipleDueDates"
test "checks for multiple due dates from assignment overrides", ->
quiz = new Quiz all_dates: [{title: "Winter"}, {title: "Summer"}]
ok quiz.multipleDueDates()
test "checks for no multiple due dates from quiz overrides", ->
quiz = new Quiz
ok !quiz.multipleDueDates()
module "Quiz#allDates"
test "gets the due dates from the assignment overrides", ->
dueAt = new Date("2013-08-20 11:13:00")
dates = [
new DateGroup due_at: dueAt, title: "Everyone"
]
quiz = new Quiz all_dates: dates
allDates = quiz.allDates()
first = allDates[0]
equal first.dueAt+"", dueAt+""
equal first.dueFor, "Everyone"
test "gets empty due dates when there are no dates", ->
quiz = new Quiz
deepEqual quiz.allDates(), []
# toView
module "Quiz#toView"
test "returns the quiz's dueAt", ->
date = Date.now()
quiz = new Quiz name: 'foo'
quiz.dueAt date
json = quiz.toView()
deepEqual json.dueAt, date
test "returns quiz's lockAt", ->
lockAt = Date.now()
quiz = new Quiz name: 'foo'
quiz.lockAt lockAt
json = quiz.toView()
deepEqual json.lockAt, lockAt
test "includes quiz's unlockAt", ->
unlockAt = Date.now()
quiz = new Quiz name: 'foo'
quiz.unlockAt unlockAt
json = quiz.toView()
deepEqual json.unlockAt, unlockAt
test "includes htmlUrl", ->
quiz = new Quiz url: 'http://example.com/quizzes/1'
json = quiz.toView()
deepEqual json.htmlUrl, 'http://example.com/quizzes/1'
test "includes multipleDueDates", ->
quiz = new Quiz all_dates: [{title: "Summer"}, {title: "Winter"}]
json = quiz.toView()
deepEqual json.multipleDueDates, true
test "includes allDates", ->
quiz = new Quiz all_dates: [{title: "Summer"}, {title: "Winter"}]
json = quiz.toView()
equal json.allDates.length, 2

View File

@ -737,14 +737,23 @@ describe "quizzes" do
it "should show a summary of due dates if there are multiple" do
create_quiz_with_default_due_dates
get "/courses/#{@course.id}/quizzes"
f('.ig-details .description').should_not include_text "Multiple Dates"
f('.ig-details .date-due').should_not include_text "Multiple Dates"
f('.ig-details .date-available').should_not include_text "Multiple Dates"
add_due_date_override(@quiz)
get "/courses/#{@course.id}/quizzes"
f('.ig-details .description').should include_text "Multiple Dates"
driver.mouse.move_to f('.ig-details .description a')
f('.ig-details .date-due').should include_text "Multiple Dates"
driver.mouse.move_to f('.ig-details .date-due a')
wait_for_ajaximations
tooltip = fj('.vdd_tooltip_content:visible')
tooltip = fj('.ui-tooltip:visible')
tooltip.should include_text 'New Section'
tooltip.should include_text 'Everyone else'
f('.ig-details .date-available').should include_text "Multiple Dates"
driver.mouse.move_to f('.ig-details .date-available a')
wait_for_ajaximations
tooltip = fj('.ui-tooltip:visible')
tooltip.should include_text 'New Section'
tooltip.should include_text 'Everyone else'
end