Merge remote-tracking branch 'origin/master' into dev/fft

This commit is contained in:
Jon Jensen 2012-06-01 10:57:32 -06:00
commit 7322030773
71 changed files with 617 additions and 378 deletions

View File

@ -85,7 +85,7 @@ group :test do
gem 'rcov', '0.9.9'
gem 'rspec', '1.3.2'
gem 'rspec-rails', '1.3.4'
gem 'selenium-webdriver', '2.19.0'
gem 'selenium-webdriver', '2.22.0'
gem 'webrat', '0.7.3'
gem 'yard', '0.8.0'
if ONE_NINE

View File

@ -10,18 +10,6 @@ define [
constructor: (@context) ->
@state = 'off'
@locked = false
@sectionsLocked = false
pubsubHelper = (fn) =>
(sender) =>
return if sender is this
fn.apply(this)
$.subscribe '/contextSelector/disable', pubsubHelper(@disable)
$.subscribe '/contextSelector/enable', pubsubHelper(@enable)
$.subscribe '/contextSelector/uncheck', pubsubHelper(=> @setState('off'))
$.subscribe '/contextSelector/lockSections', @lockSections
render: ($list) ->
@$listItem = $(contextSelectorItemTemplate(@context))
@ -55,12 +43,9 @@ define [
@$contentCheckbox.prop('checked', checked)
@$contentCheckbox.prop('indeterminate', false)
@$sectionCheckboxes.prop('checked', checked)
$.publish("/contextSelector/enable", [this])
when 'partial'
@$contentCheckbox.prop('checked', true)
@$contentCheckbox.prop('indeterminate', true)
$.publish('/contextSelector/disable', [this])
$.publish('/contextSelector/uncheck', [this])
$.publish('/contextSelector/changed')
@ -80,22 +65,9 @@ define [
disableSections: ->
@$sectionCheckboxes.prop('disabled', true)
enable: ->
unless @locked
@$contentCheckbox.prop('disabled', false)
@enableSections()
enableSections: ->
unless @lockedSections
@$sectionCheckboxes.prop('disabled', false)
lock: ->
@locked = true
@disable()
$.publish('/contextSelector/lockSections')
lockSections: =>
@lockedSections = true
@disableSections()
isChecked: -> @state != 'off'
@ -110,6 +82,7 @@ define [
class ContextSelector
constructor: (selector, @apptGroup, @contexts, contextsChangedCB, closeCB) ->
@$menu = $(selector).html contextSelectorTemplate()
$contextsList = @$menu.find('.ag-contexts')
$.subscribe('/contextSelector/changed', => contextsChangedCB @selectedContexts(), @selectedSections())
@ -120,19 +93,26 @@ define [
item.render($contextsList)
@contextSelectorItems[item.context.asset_string] = item
for contextCode in @apptGroup.context_codes when @contextSelectorItems[contextCode]
@contextSelectorItems[contextCode].setState('on')
@contextSelectorItems[contextCode].lock()
if @apptGroup.sub_context_codes.length > 0
# if you choose sub_contexts when creating an appointment
# group, the appointment group is locked down
# TODO: be smarter about this
for subContextCode in @apptGroup.sub_context_codes
$("[value='#{subContextCode}']").prop('checked', true)
if @apptGroup.sub_context_codes[0].match /^group_category_/
for c, item of @contextSelectorItems
item.lock()
else
contextsBySubContext = {}
for c in @contexts
for section in c.course_sections
contextsBySubContext[section.asset_string] = c.asset_string
for subContextCode in @apptGroup.sub_context_codes
$("[value='#{subContextCode}']").prop('checked', true)
context = contextsBySubContext[subContextCode]
item = @contextSelectorItems[context]
item.sectionChange()
item.lock()
else
for contextCode in @apptGroup.context_codes
@contextSelectorItems[contextCode].setState('on')
@contextSelectorItems[contextCode].lock()
$('.ag_contexts_done').click preventDefault closeCB
@ -145,10 +125,6 @@ define [
.map( (c) -> c.context.asset_string)
.value()
numPartials = _.filter(contexts, (c) -> c.state == 'partial')
if numPartials > 1 or numPartials == 1 and contexts.length > 1
throw "invalid state"
contexts
selectedSections: ->
@ -156,7 +132,7 @@ define [
.values()
.map( (c) -> c.sections())
.reject((ss) -> ss.length == 0)
.flatten()
.value()
throw "invalid state" if sections.length > 1
sections[0]
sections

View File

@ -169,30 +169,33 @@ define [
contextsChanged: (contextCodes, sectionCodes) =>
# dropdown text
if sectionCodes
sectionCode = sectionCodes[0]
section = _.chain(@contexts)
.pluck('course_sections')
.flatten()
.find((s) -> s.asset_string == sectionCode)
.value()
text = section.name
if sectionCodes.length > 1
text += I18n.t('and_n_sectionCodes', ' and %{n} others', n: sectionCodes.length - 1)
@form.find('.ag_contexts_selector').text(text)
else if contextCodes.length > 0
contextCode = contextCodes[0]
text = @contextsHash[contextCode].name
if contextCodes.length > 1
text += I18n.t('and_n_contexts', ' and %{n} others', n: contextCodes.length - 1)
@form.find('.ag_contexts_selector').text(text)
else
if sectionCodes.length == 0 and contextCodes.length == 0
@form.find('.ag_contexts_selector').text(I18n.t 'select_calendars', 'Select Calendars')
else
if contextCodes.length > 0
contextCode = contextCodes[0]
text = @contextsHash[contextCode].name
if contextCodes.length > 1
text += I18n.t('and_n_contexts', ' and %{n} others', n: contextCodes.length - 1)
@form.find('.ag_contexts_selector').text(text)
if sectionCodes.length > 0
sectionCode = sectionCodes[0]
section = _.chain(@contexts)
.pluck('course_sections')
.flatten()
.find((s) -> s.asset_string == sectionCode)
.value()
text = section.name
if sectionCodes.length > 1
text += I18n.t('and_n_sectionCodes', ' and %{n} others', n: sectionCodes.length - 1)
@form.find('.ag_contexts_selector').text(text)
# group selector
context = @contextsHash[contextCodes[0]]
if contextCodes.length == 1 and not sectionCodes and context.group_categories?.length > 0
if contextCodes.length == 1 and sectionCodes.length == 0 and context.group_categories?.length > 0
@enableGroups(context)
if @apptGroup.sub_context_codes.length > 0
@form.find('[name=group_category_id]').prop('disabled', true)
else
@disableGroups()

View File

@ -56,6 +56,7 @@ class AppointmentGroupsController < ApplicationController
publish = params[:appointment_group].delete(:publish) == '1'
params[:appointment_group][:contexts] = contexts
@group = AppointmentGroup.new(params[:appointment_group])
@group.update_contexts_and_sub_contexts
if authorized_action(@group, @current_user, :manage)
if @group.save
@group.publish! if publish

View File

@ -66,6 +66,11 @@ class CalendarsController < ApplicationController
@view_start = event.start_at.in_time_zone.strftime("%Y-%m-%d")
end
@contexts_json = @contexts.map do |context|
if context.respond_to? :appointment_groups
ag = AppointmentGroup.new(:contexts => [context])
ag.update_contexts_and_sub_contexts
can_create_ags = ag.grants_right? @current_user, session, :create
end
info = {
:name => context.name,
:asset_string => context.asset_string,
@ -82,7 +87,7 @@ class CalendarsController < ApplicationController
:can_create_calendar_events => context.respond_to?("calendar_events") && context.calendar_events.new.grants_right?(@current_user, session, :create),
:can_create_assignments => context.respond_to?("assignments") && context.assignments.new.grants_right?(@current_user, session, :create),
:assignment_groups => context.respond_to?("assignments") ? context.assignment_groups.active.scoped(:select => "id, name").map {|g| { :id => g.id, :name => g.name } } : [],
:can_create_appointment_groups => context.respond_to?("appointment_groups") && AppointmentGroup.new(:contexts => [context]).grants_right?(@current_user, session, :create),
:can_create_appointment_groups => can_create_ags
}
if context.respond_to?("course_sections")
info[:course_sections] = context.course_sections.active.scoped(:select => "id, name").map {|cs| { :id => cs.id, :asset_string => cs.asset_string, :name => cs.name } }

View File

@ -99,6 +99,9 @@
#
# // The API URL for this item. Used to clone the collection item.
# url: "https://<canvas>/api/v1/collections/items/7"
#
# // The timestamp of when the item was posted by the user
# created_at: "2012-05-30T17:45:25Z",
# }
class CollectionItemsController < ApplicationController
before_filter :require_collection, :only => [:index, :create]
@ -130,6 +133,7 @@ class CollectionItemsController < ApplicationController
# image_url: "https://<canvas>/files/item_image.png",
# description: "some block of plain text",
# url: "https://<canvas>/api/v1/collections/items/7"
# created_at: "2012-05-30T17:45:25Z",
# }
# ]
def index
@ -163,6 +167,7 @@ class CollectionItemsController < ApplicationController
# image_url: "https://<canvas>/files/item_image.png",
# description: "some block of plain text",
# url: "https://<canvas>/api/v1/collections/items/7"
# created_at: "2012-05-30T17:45:25Z",
# }
def show
find_item_and_collection

View File

@ -9,7 +9,7 @@
<%= t('subject', 'Reservation canceled for "%{appointment_name}" (%{course})', :appointment_name => asset.title, :course => courses) %>
<% end %>
<%= t :message, '%{user} canceled his/her reservation for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, '%{user} canceled his/her reservation for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>
<%= before_label :details, "Appointment details" %>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %>
@ -25,6 +25,6 @@
<% end -%>
<%= before_label :cancel_reason, "Reason for canceling" %>
<%= asset.cancel_reason || t(:no_reason_given, "none given") %>
<%= data.cancel_reason || t(:no_reason_given, "none given") %>
<%= t :instructions, "View the appointment at the following link: %{link}", :link => content(:link) %>

View File

@ -2,7 +2,7 @@
http://<%= HostUrl.context_host(asset.appointment_group.contexts.first) %>/appointment_groups/<%= asset.appointment_group.id %>
<% end %>
<%= t :message, '%{user} canceled his/her reservation for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, '%{user} canceled his/her reservation for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>
<b><%= before_label :details, "Appointment details" %></b><br>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %><br>
@ -20,6 +20,6 @@
<% end -%>
<br>
<b><%= before_label :cancel_reason, "Reason for canceling" %></b><br>
<%= asset.cancel_reason || t(:no_reason_given, "none given") %><br>
<%= data.cancel_reason || t(:no_reason_given, "none given") %><br>
<br>
<a href="<%= content :link %>"><%= t :instructions, "View the appointment" %></a>

View File

@ -1,3 +1,3 @@
<%= t :message, '%{user} canceled his/her reservation for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, '%{user} canceled his/her reservation for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>
<%= t :more_info, "More info at %{url}", :url => HostUrl.context_host(asset.appointment_group.contexts.first) %>

View File

@ -1 +1 @@
<%= t :message, 'Canvas Alert - %{user} canceled his/her reservation for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, 'Canvas Alert - %{user} canceled his/her reservation for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>

View File

@ -9,7 +9,7 @@
<%= t('subject', 'Your time slot for "%{appointment_name}" has been canceled (%{course})', :appointment_name => asset.title, :course => courses) %>
<% end %>
<%= t :message, '%{user} canceled your time slot for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, '%{user} canceled your time slot for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>
<%= before_label :details, "Appointment details" %>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %>
@ -22,6 +22,6 @@
<%= before_label :course, "Course" %> <%= courses %>
<%= before_label :cancel_reason, "Reason for canceling" %>
<%= asset.cancel_reason || t(:no_reason_given, "none given") %>
<%= data.cancel_reason || t(:no_reason_given, "none given") %>
<%= t :instructions, 'Sign up for a different time slot at the following link: %{link}', :link => content(:link) %>

View File

@ -2,7 +2,7 @@
http://<%= HostUrl.context_host(asset.appointment_group.contexts.first) %>/appointment_groups/<%= asset.appointment_group.id %>
<% end %>
<%= t :message, '%{user} canceled your time slot for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %><br>
<%= t :message, '%{user} canceled your time slot for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %><br>
<br>
<b><%= before_label :details, "Appointment details" %></b><br>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %><br>
@ -17,6 +17,6 @@
asset.appointment_group.contexts_for_user(user).map(&:name).join(", ") %><br>
<br>
<b><%= before_label :cancel_reason, "Reason for canceling" %></b><br>
<%= asset.cancel_reason || t(:no_reason_given, "none given") %><br>
<%= data.cancel_reason || t(:no_reason_given, "none given") %><br>
<br>
<a href="<%= content(:link) %>"><%= t :instructions, 'Sign up for a different time slot' %></a>

View File

@ -16,4 +16,4 @@
asset.contexts_for_user(user).map(&:name).join(", ") %><br>
<%= before_label :cancel_reason, "Reason for canceling" %>
<%= asset.cancel_reason || t(:no_reason_given, "none given") %>
<%= data.cancel_reason || t(:no_reason_given, "none given") %>

View File

@ -8,4 +8,4 @@
asset.contexts_for_user(user).map(&:name).join(", ") %><br>
<br>
<b><%= before_label :cancel_reason, "Reason for canceling" %></b><br>
<%= asset.cancel_reason || t(:no_reason_given, "none given") %>
<%= data.cancel_reason || t(:no_reason_given, "none given") %>

View File

@ -6,7 +6,7 @@
<%= t('subject', 'User signed up for "%{appointment_name}" (%{course})', :appointment_name => asset.title, :course => asset.appointment_group.contexts_for_user(user).map(&:name).join(", ")) %>
<% end %>
<%= t :message, '%{user} has signed up for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, '%{user} has signed up for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>
<%= before_label :details, "Appointment details" %>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %>

View File

@ -2,7 +2,7 @@
http://<%= HostUrl.context_host(asset.appointment_group.contexts.first) %>/appointment_groups/<%= asset.appointment_group.id %>
<% end %>
<%= t :message, '%{user} has signed up for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %><br>
<%= t :message, '%{user} has signed up for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %><br>
<br>
<b><%= before_label :details, "Appointment details" %></b><br>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %><br>

View File

@ -1,3 +1,3 @@
<%= t :message, '%{user} has signed up for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, '%{user} has signed up for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>
<%= t :more_info, "More info at %{url}", :url => HostUrl.context_host(asset.appointment_group.contexts.first) %>

View File

@ -1 +1 @@
<%= t :message, 'Canvas Alert - %{user} has signed up for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, 'Canvas Alert - %{user} has signed up for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>

View File

@ -6,7 +6,7 @@
<%= t('subject', 'You have been signed up for "%{appointment_name}"', :appointment_name => asset.title) %>
<% end %>
<%= t :message, '%{user} has signed you up for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %>
<%= t :message, '%{user} has signed you up for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %>
<%= before_label :details, "Appointment details" %>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %>

View File

@ -2,7 +2,7 @@
http://<%= HostUrl.context_host(asset.appointment_group.contexts.first) %>/appointment_groups/<%= asset.appointment_group.id %>
<% end %>
<%= t :message, '%{user} has signed you up for "%{appointment_name}".', :user => asset.updating_user.name, :appointment_name => asset.title %><br>
<%= t :message, '%{user} has signed you up for "%{appointment_name}".', :user => data.updating_user.name, :appointment_name => asset.title %><br>
<br>
<b><%= before_label :details, "Appointment details" %></b><br>
<%= before_label :date_and_time, "Date/time" %> <%= datetime_string(asset.start_at, asset.end_at) %><br>

View File

@ -10,4 +10,4 @@
asset.appointment_group.contexts_for_user(user).map(&:name).join(", ")) %>
<% end %>
<%= t :message, '%{user} has signed you up for "%{appointment_name}" (%{date_and_time}).', :user => asset.updating_user.name, :appointment_name => asset.title, :date_and_time => datetime_string(asset.start_at, asset.end_at) %>
<%= t :message, '%{user} has signed you up for "%{appointment_name}" (%{date_and_time}).', :user => data.updating_user.name, :appointment_name => asset.title, :date_and_time => datetime_string(asset.start_at, asset.end_at) %>

View File

@ -1 +1 @@
<%= t :message, 'Canvas Alert - You have been signed up for "%{appointment_name}".', :appointment_name => asset.title %>
<%= t :message, 'Canvas Alert - You have been signed up for "%{appointment_name}".', :appointment_name => asset.title %>

View File

@ -38,6 +38,7 @@ class AppointmentGroup < ActiveRecord::Base
end
before_validation :default_values
before_validation :update_contexts_and_sub_contexts
before_save :update_cached_values
after_save :update_appointments
@ -59,8 +60,8 @@ class AppointmentGroup < ActiveRecord::Base
def validate
if appointment_group_contexts.empty?
errors.add(:appointment_group_contexts,
t('errors.needs_contexts', 'Must have at least one context'))
errors.add :appointment_group_contexts,
t('errors.needs_contexts', 'Must have at least one context')
end
end
@ -88,28 +89,66 @@ class AppointmentGroup < ActiveRecord::Base
super
end
# TODO: someday this should become context_codes= for consistency
def contexts=(new_contexts)
new_contexts -= self.contexts
self.appointment_group_contexts += new_contexts.map do |context|
AppointmentGroupContext.create! :appointment_group => self,
:context => context
end
appointments.update_all :effective_context_code => contexts.map(&:asset_string).join(",")
@new_contexts ||= []
@new_contexts += new_contexts.compact
end
def sub_context_codes=(codes)
if new_record?
sub_contexts = codes.map do |code|
context = case code
when /\Acourse_section_(.*)/; CourseSection.find_by_id($1)
when /\Agroup_category_(.*)/; GroupCategory.find_by_id($1)
else next
end
AppointmentGroupSubContext.new :appointment_group => self,
:sub_context => context,
:sub_context_code => code
@new_sub_context_codes ||= []
@new_sub_context_codes += codes.compact
end
def update_contexts_and_sub_contexts
# TODO: validate the updating user has manage rights for all contexts /
# sub_contexts
#
# sub contexts
@new_sub_context_codes -= sub_context_codes if @new_sub_context_codes
if @new_sub_context_codes.present?
if new_record? &&
@new_contexts.size == 1 &&
@new_sub_context_codes.size == 1 &&
@new_sub_context_codes.first =~ /\Agroup_category_(.*)/
# a group category can only be assigned at creation time to
# appointment groups with one course
gc = GroupCategory.find_by_id($1)
code = @new_sub_context_codes.first
self.appointment_group_sub_contexts = [
AppointmentGroupSubContext.new :appointment_group => self,
:sub_context => gc,
:sub_context_code => code
]
else
# right now we don't support changing the sub contexts for a context
# on an appointment group after it has been saved
disallowed_sub_context_codes = contexts.map(&:course_sections).
flatten.map(&:asset_string)
@new_sub_context_codes -= disallowed_sub_context_codes
new_sub_contexts = @new_sub_context_codes.map { |code|
next unless code =~ /\Acourse_section_(.*)/
cs = CourseSection.find_by_id($1)
AppointmentGroupSubContext.new :appointment_group => self,
:sub_context => cs,
:sub_context_code => code
}
self.appointment_group_sub_contexts += new_sub_contexts.compact
end
end
# contexts
@new_contexts -= contexts if @new_contexts
if @new_contexts.present?
unless appointment_group_sub_contexts.size == 1 &&
appointment_group_sub_contexts.first.sub_context_type == 'GroupCategory' &&
!new_record?
self.appointment_group_contexts += @new_contexts.map { |c|
AppointmentGroupContext.new :context => c, :appointment_group => self
}
@contexts_changed = true
end
self.appointment_group_sub_contexts = sub_contexts.compact
end
end
@ -176,10 +215,12 @@ class AppointmentGroup < ActiveRecord::Base
given { |user, session|
next false if deleted?
next false unless contexts.all? { |c| c.grants_right? user, nil, :manage_calendar }
if appointment_group_sub_contexts.present?
raise "you can't have multiple contexts and sub_contexts" if appointment_group_contexts.size > 1
context = contexts.first
next true if appointment_group_sub_contexts.any? { |sc| sc.sub_context_type == 'CourseSection' && context.section_visibilities_for(user).any?{ |v| sc.sub_context_id == v[:course_section_id] } }
if appointment_group_sub_contexts.present? && appointment_group_sub_contexts.first.sub_context_type == 'CourseSection'
sub_context_ids = appointment_group_sub_contexts.map(&:sub_context_id)
user_visible_sections = sub_context_ids & contexts.map { |c|
c.section_visibilities_for(user).map { |v| v[:course_section_id] }
}.flatten
next true if user_visible_sections.length == sub_contexts.length
end
!contexts.all? { |c| c.visibility_limited_to_course_sections?(user) }
}
@ -212,6 +253,7 @@ class AppointmentGroup < ActiveRecord::Base
dispatch :appointment_group_deleted
to { possible_users }
whenever { contexts.any?(&:available?) && deleted? && workflow_state_changed? }
data { {:cancel_reason => @cancel_reason} }
end
def possible_users
@ -271,7 +313,7 @@ class AppointmentGroup < ActiveRecord::Base
def eligible_participant?(participant)
return false unless participant && participant.class.base_ar_class.name == participant_type
codes = participant.appointment_context_codes
return false unless (codes[:primary]. & appointment_group_contexts.map(&:context_code)).present?
return false unless (codes[:primary] & appointment_group_contexts.map(&:context_code)).present?
return false unless sub_context_codes.empty? || (codes[:secondary] & sub_context_codes).present?
true
end
@ -326,12 +368,20 @@ class AppointmentGroup < ActiveRecord::Base
map{ |attr| [attr, attr == :description ? description_html : send(attr)] }
]
if @contexts_changed
changed[:effective_context_code] = contexts.map(&:asset_string).join(",")
end
return unless changed.present?
desc = changed.delete :description
if changed.present?
appointments.update_all changed
changed.delete(:effective_context_code)
end
if changed.present?
CalendarEvent.update_all changed, {:parent_calendar_event_id => appointments.map(&:id), :workflow_state => ['active', 'locked']}
end

View File

@ -312,6 +312,7 @@ class CalendarEvent < ActiveRecord::Base
just_created &&
context == appointment_group.participant_for(user)
}
data { {:updating_user => @updating_user} }
dispatch :appointment_canceled_by_user
to { appointment_group.instructors }
@ -322,6 +323,10 @@ class CalendarEvent < ActiveRecord::Base
@updating_user &&
context == appointment_group.participant_for(@updating_user)
}
data { {
:updating_user => @updating_user,
:cancel_reason => @cancel_reason
} }
dispatch :appointment_reserved_for_user
to { participants - [@updating_user] }
@ -329,6 +334,7 @@ class CalendarEvent < ActiveRecord::Base
appointment_group && parent_event &&
just_created
}
data { {:updating_user => @updating_user} }
dispatch :appointment_deleted_for_user
to { participants - [@updating_user] }
@ -337,6 +343,10 @@ class CalendarEvent < ActiveRecord::Base
deleted? &&
workflow_state_changed?
}
data { {
:updating_user => @updating_user,
:cancel_reason => @cancel_reason
} }
end
def participants

View File

@ -1749,7 +1749,7 @@ class Course < ActiveRecord::Base
WikiPage.process_migration_course_outline(data, migration);migration.fast_update_progress(95)
if !migration.copy_options || migration.is_set?(migration.copy_options[:everything]) || migration.is_set?(migration.copy_options[:all_course_settings])
import_settings_from_migration(data); migration.fast_update_progress(96)
import_settings_from_migration(data, migration); migration.fast_update_progress(96)
end
begin
@ -1802,18 +1802,38 @@ class Course < ActiveRecord::Base
attr_accessor :imported_migration_items, :full_migration_hash, :external_url_hash, :content_migration
attr_accessor :folder_name_lookups, :attachment_path_id_lookup, :assignment_group_no_drop_assignments
def import_settings_from_migration(data)
def import_settings_from_migration(data, migration)
return unless data[:course]
settings = data[:course]
self.syllabus_body = ImportedHtmlConverter.convert(settings[:syllabus_body], self) if settings[:syllabus_body]
if settings[:tab_configuration] && settings[:tab_configuration].is_a?(Array)
self.tab_configuration = settings[:tab_configuration]
end
if settings[:storage_quota] && ( migration.for_course_copy? || self.account.grants_right?(migration.user, nil, :manage_courses))
self.storage_quota = settings[:storage_quota]
end
self.settings[:hide_final_grade] = !!settings[:hide_final_grade] unless settings[:hide_final_grade].nil?
atts = Course.clonable_attributes
atts -= Canvas::Migration::MigratorHelper::COURSE_NO_COPY_ATTS
settings.slice(*atts.map(&:to_s)).each do |key, val|
self.send("#{key}=", val)
end
if settings[:grading_standard_enabled]
self.grading_standard_enabled = true
if settings[:grading_standard_identifier_ref]
if gs = self.grading_standards.find_by_migration_id(settings[:grading_standard_identifier_ref])
self.grading_standard = gs
else
migration.add_warning("Couldn't find copied grading standard for the course.")
end
elsif settings[:grading_standard_id]
if gs = GradingStandard.sorted_standards_for(self).find{|s|s.id == settings[:grading_standard_id]}
self.grading_standard = gs
else
migration.add_warning("Couldn't find account grading standard for the course.")
end
end
end
end
def add_migration_warning(message, exception='')

View File

@ -24,7 +24,7 @@ module Api::V1::Collection
}
API_COLLECTION_ITEM_JSON_OPTS = {
:only => %w(id collection_id description),
:only => %w(id collection_id user_id description created_at),
}
API_COLLECTION_ITEM_DATA_JSON_OPTS = {

View File

@ -95,9 +95,19 @@ module CC
end
atts = Course.clonable_attributes
atts -= Canvas::Migration::MigratorHelper::COURSE_NO_COPY_ATTS
atts << :grading_standard_enabled
atts << :storage_quota
atts.each do |att|
c.tag!(att, @course.send(att)) unless @course.send(att).nil? || @course.send(att) == ''
end
c.hide_final_grade @course.settings[:hide_final_grade] unless @course.settings[:hide_final_grade].nil?
if @course.grading_standard
if @course.grading_standard.context_type == "Account"
c.grading_standard_id @course.grading_standard.id
else
c.grading_standard_identifier_ref create_key(@course.grading_standard)
end
end
end
course_file.close if course_file
rel_path

View File

@ -18,7 +18,7 @@
module CC
module Events
def create_events(document=nil)
return nil unless @course.calendar_events.count > 0
return nil unless @course.calendar_events.active.count > 0
if document
events_file = nil
@ -35,7 +35,7 @@ module CC
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation"=> "#{CCHelper::CANVAS_NAMESPACE} #{CCHelper::XSD_URI}"
) do |events_node|
@course.calendar_events.each do |event|
@course.calendar_events.active.each do |event|
next unless export_object?(event)
migration_id = CCHelper.create_key(event)
events_node.event(:identifier=>migration_id) do |event_node|

View File

@ -52,7 +52,7 @@ module CC::Importer::Canvas
['title', 'course_code', 'hashtag', 'default_wiki_editing_roles',
'turnitin_comments', 'default_view', 'license', 'locale',
'group_weighting_scheme'].each do |string_type|
'group_weighting_scheme', 'storage_quota', 'grading_standard_identifier_ref'].each do |string_type|
val = get_node_val(doc, string_type)
course[string_type] = val unless val.nil?
end
@ -60,7 +60,7 @@ module CC::Importer::Canvas
'allow_student_assignment_edits', 'show_public_context_messages',
'allow_student_forum_attachments', 'allow_student_organized_groups',
'show_all_discussion_entries', 'open_enrollment', 'allow_wiki_comments',
'self_enrollment'].each do |bool_val|
'self_enrollment', 'hide_final_grade', 'grading_standard_enabled'].each do |bool_val|
val = get_bool_val(doc, bool_val)
course[bool_val] = val unless val.nil?
end
@ -68,6 +68,9 @@ module CC::Importer::Canvas
val = get_time_val(doc, date_type)
course[date_type] = val unless val.nil?
end
if val = get_int_val(doc, 'grading_standard_id')
course['grading_standard_id'] = val
end
if nav = get_node_val(doc, 'tab_configuration')
begin
nav = JSON.parse(nav)

View File

@ -27,6 +27,11 @@
<xs:element name="self_enrollment" type="xs:boolean" minOccurs="0"/>
<xs:element name="turnitin_comments" type="xs:string" minOccurs="0"/>
<xs:element name="locale" type="xs:string" minOccurs="0"/>
<xs:element name="hide_final_grade" type="xs:boolean" minOccurs="0"/>
<xs:element name="grading_standard_enabled" type="xs:boolean" minOccurs="0"/>
<xs:element name="grading_standard_identifier_ref" type="xs:string" minOccurs="0"/>
<xs:element name="grading_standard_id" type="xs:integer" minOccurs="0"/>
<xs:element name="storage_quota" type="xs:float" minOccurs="0"/>
<xs:element name="default_view" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">

View File

@ -198,10 +198,16 @@ define([
$(".configure_report_link").click(function(event) {
event.preventDefault();
$(this).parent("td").find(".report_dialog").clone(true).dialog({
width: 400,
title: I18n.t('titles.configure_report', 'Configure Report')
});
var data = $(this).data(),
$dialog = data.$report_dialog;
if (!$dialog) {
$dialog = data.$report_dialog = $(this).parent("td").find(".report_dialog").dialog({
autoOpen: false,
width: 400,
title: I18n.t('titles.configure_report', 'Configure Report')
});
}
$dialog.dialog('open');
})
$('.service_help_dialog').each(function(index) {

View File

@ -21,6 +21,9 @@ require File.expand_path(File.dirname(__FILE__) + '/../api_spec_helper')
describe AppointmentGroupsController, :type => :integration do
before do
course_with_teacher(:active_all => true, :user => user_with_pseudonym(:active_user => true))
@course1 = @course
course_with_teacher(:active_all => true, :user => @user)
@course2 = @course
@me = @user
end
@ -34,11 +37,11 @@ describe AppointmentGroupsController, :type => :integration do
]
it 'should return manageable appointment groups' do
ag1 = AppointmentGroup.create!(:title => "something", :contexts => [@course])
cat = @course.group_categories.create
ag2 = AppointmentGroup.create!(:title => "another", :contexts => [@course], :sub_context_codes => [cat.asset_string])
ag1 = AppointmentGroup.create!(:title => "something", :contexts => [@course1])
cat = @course1.group_categories.create
ag2 = AppointmentGroup.create!(:title => "another", :contexts => [@course1], :sub_context_codes => [cat.asset_string])
ag3 = AppointmentGroup.create!(:title => "inaccessible", :contexts => [Course.create!])
ag4 = AppointmentGroup.create!(:title => "past", :contexts => [@course], :new_appointments => [["#{Time.now.year - 1}-01-01 12:00:00", "#{Time.now.year - 1}-01-01 13:00:00"]])
ag4 = AppointmentGroup.create!(:title => "past", :contexts => [@course1, @course2], :new_appointments => [["#{Time.now.year - 1}-01-01 12:00:00", "#{Time.now.year - 1}-01-01 13:00:00"]])
json = api_call(:get, "/api/v1/appointment_groups?scope=manageable", {
:controller => 'appointment_groups', :action => 'index', :format => 'json', :scope => 'manageable'})
@ -81,12 +84,32 @@ describe AppointmentGroupsController, :type => :integration do
ag8 = AppointmentGroup.create!(:title => "past", :new_appointments => [["#{Time.now.year - 1}-01-01 12:00:00", "#{Time.now.year - 1}-01-01 13:00:00"]], :contexts => [@course])
ag8.publish!
c1s2 = @course1.course_sections.create!
c2s2 = @course2.course_sections.create!
user_in_c1s2 = student_in_section(c1s2)
user_in_c2s2 = student_in_section(c2s2)
@user = @me
ag9 = AppointmentGroup.create! :title => "multiple contexts / sub contexts",
:contexts => [@course1, @course2],
:sub_context_codes => [c1s2.asset_string, c2s2.asset_string],
:new_appointments => [["#{Time.now.year + 1}-01-01 12:00:00", "#{Time.now.year + 1}-01-01 13:00:00"]]
ag9.publish!
json = api_call(:get, "/api/v1/appointment_groups?scope=reservable", {
:controller => 'appointment_groups', :action => 'index', :format => 'json', :scope => 'reservable'})
json.size.should eql 2
json.first.keys.sort.should eql expected_fields
json.first.slice('id', 'title', 'participant_type').should eql({'id' => ag6.id, 'title' => 'yay', 'participant_type' => 'User'})
json.last.slice('id', 'title', 'participant_type').should eql({'id' => ag7.id, 'title' => 'double yay', 'participant_type' => 'Group'})
[user_in_c1s2, user_in_c2s2].each do |user|
@user = user
json = api_call(:get, "/api/v1/appointment_groups?scope=reservable", {
:controller => 'appointment_groups', :action => 'index', :format => 'json', :scope => 'reservable'})
json.size.should eql 1
json.first['id'].should eql ag9.id
end
end
it "should return past reservable appointment groups, if requested" do
@ -249,16 +272,6 @@ describe AppointmentGroupsController, :type => :integration do
json['title'].should eql 'lol'
end
it 'should ignore updates to readonly fields' do
ag = AppointmentGroup.create!(:title => "something", :new_appointments => [["2012-01-01 12:00:00", "2012-01-01 13:00:00"]], :contexts => [@course])
json = api_call(:put, "/api/v1/appointment_groups/#{ag.id}",
{:controller => 'appointment_groups', :action => 'update', :format => 'json', :id => ag.id.to_s},
{:appointment_group => {:title => "lol", :sub_context_codes => [@course.default_section.asset_string]} })
json.keys.sort.should eql expected_fields
json['title'].should eql 'lol'
json['sub_context_codes'].should eql []
end
it 'should publish an appointment group in an update through the api' do
ag = AppointmentGroup.create!(:title => "something", :new_appointments => [["2012-01-01 12:00:00", "2012-01-01 13:00:00"]], :contexts => [@course])
ag.workflow_state.should == 'pending'

View File

@ -277,7 +277,7 @@ describe CalendarEventsApiController, :type => :integration do
othergroup.users << otherguy
@me.reload
ag2 = AppointmentGroup.create!(:title => "something", :participants_per_appointment => 4, :sub_context_codes => [cat.asset_string], :new_appointments => [["2012-01-01 12:00:00", "2012-01-01 13:00:00"]], :contexts => [course1, course2])
ag2 = AppointmentGroup.create!(:title => "something", :participants_per_appointment => 4, :sub_context_codes => [cat.asset_string], :new_appointments => [["2012-01-01 12:00:00", "2012-01-01 13:00:00"]], :contexts => [course1])
ag2.publish!
event2 = ag2.appointments.first
my_group_appointment = event2.reserve_for(mygroup, @me)

View File

@ -158,6 +158,7 @@ describe "Collections API", :type => :integration do
{
'id' => item.id,
'collection_id' => item.collection_id,
'user_id' => item.user_id,
'item_type' => item.collection_item_data.item_type,
'link_url' => item.collection_item_data.link_url,
'post_count' => item.collection_item_data.post_count,
@ -169,6 +170,7 @@ describe "Collections API", :type => :integration do
'html_preview' => item.data.html_preview,
'description' => item.description,
'url' => "http://www.example.com/api/v1/collections/items/#{item.id}",
'created_at' => item.created_at.iso8601,
}
end

View File

@ -32,6 +32,7 @@ def appointment_participant_model(opts={})
end
parent_event = opts.delete(:parent_event) || appointment_model(opts)
parent_event.context.publish! unless opts[:no_publish]
@appointment_group.reload #why!?
updating_user = opts.delete(:updating_user) || user_model
@event = parent_event.reserve_for(participant, updating_user)
end

View File

@ -20,70 +20,6 @@ describe "Canvas Cartridge importing" do
@copy_to.content_migration = @migration
end
it "should import course settings" do
#set all the possible values to non-default values
@copy_from.start_at = 5.minutes.ago
@copy_from.conclude_at = 1.month.from_now
@copy_from.is_public = false
@copy_from.name = "haha copy from test &amp;"
@copy_from.course_code = 'something funny'
@copy_from.publish_grades_immediately = false
@copy_from.allow_student_wiki_edits = true
@copy_from.allow_student_assignment_edits = true
@copy_from.hashtag = 'oi'
@copy_from.show_public_context_messages = false
@copy_from.allow_student_forum_attachments = false
@copy_from.default_wiki_editing_roles = 'teachers'
@copy_from.allow_student_organized_groups = false
@copy_from.default_view = 'modules'
@copy_from.show_all_discussion_entries = false
@copy_from.open_enrollment = true
@copy_from.storage_quota = 444
@copy_from.allow_wiki_comments = true
@copy_from.turnitin_comments = "Don't plagiarize"
@copy_from.self_enrollment = true
@copy_from.license = "cc_by_nc_nd"
@copy_from.locale = "es"
@copy_from.tab_configuration = [{"id"=>0}, {"id"=>14}, {"id"=>8}, {"id"=>5}, {"id"=>6}, {"id"=>2}, {"id"=>3, "hidden"=>true}]
@copy_from.save!
body_with_link = %{<p>Watup? <strong>eh?</strong><a href="/courses/%s/assignments">Assignments</a></p>
<div>
<div><img src="http://www.instructure.com/images/header-logo.png"></div>
<div><img src="http://www.instructure.com/images/header-logo.png"></div>
</div>}
@copy_from.syllabus_body = body_with_link % @copy_from.id
#export to xml
builder = Builder::XmlMarkup.new(:indent=>2)
@resource.create_course_settings("1", builder)
syllabus = StringIO.new
@resource.create_syllabus(syllabus)
#convert to json
doc = Nokogiri::XML(builder.target!)
hash = @converter.convert_course_settings(doc)
syl_doc = Nokogiri::HTML(syllabus.string)
hash[:syllabus_body] = @converter.convert_syllabus(syl_doc)
#import json into new course
hash = hash.with_indifferent_access
@copy_to.import_settings_from_migration({:course=>hash})
@copy_to.save!
#compare settings
@copy_to.conclude_at.should == nil
@copy_to.start_at.should == nil
@copy_to.syllabus_body.should == (body_with_link % @copy_to.id)
@copy_to.storage_quota.should_not == @copy_from.storage_quota
@copy_to.name.should == 'alt name'
@copy_to.course_code.should == 'alt name'
atts = Course.clonable_attributes
atts -= Canvas::Migration::MigratorHelper::COURSE_NO_COPY_ATTS
atts.each do |att|
@copy_to.send(att).should == @copy_from.send(att)
end
@copy_to.tab_configuration.should == @copy_from.tab_configuration
end
it "should import assignment groups" do
ag1 = @copy_from.assignment_groups.new
ag1.name = "Boring assignments"
@ -900,50 +836,6 @@ XML
a.assignment_group.id.should == ag1.id
end
it "should import calendar events" do
body_with_link = "<p>Watup? <strong>eh?</strong><a href=\"/courses/%s/assignments\">Assignments</a></p>"
cal = @copy_from.calendar_events.new
cal.title = "Calendar event"
cal.description = body_with_link % @copy_from.id
cal.start_at = 1.week.from_now
cal.save!
cal.all_day = true
cal.save!
cal2 = @copy_from.calendar_events.new
cal2.title = "Stupid events"
cal2.start_at = 5.minutes.from_now
cal2.end_at = 10.minutes.from_now
cal2.all_day = false
cal2.save!
#export to xml
builder = Builder::XmlMarkup.new(:indent=>2)
@resource.create_events(builder)
#convert to json
doc = Nokogiri::XML(builder.target!)
hash = @converter.convert_events(doc)
#import json into new course
hash[0] = hash[0].with_indifferent_access
hash[1] = hash[1].with_indifferent_access
CalendarEvent.process_migration({'calendar_events'=>hash}, @migration)
@copy_to.save!
@copy_to.calendar_events.count.should == 2
cal_2 = @copy_to.calendar_events.find_by_migration_id(CC::CCHelper.create_key(cal))
cal_2.title.should == cal.title
cal_2.start_at.to_i.should == cal.start_at.to_i
cal_2.end_at.to_i.should == cal.end_at.to_i
cal_2.all_day.should == true
cal_2.all_day_date.should == cal.all_day_date
cal_2.description = body_with_link % @copy_to.id
cal2_2 = @copy_to.calendar_events.find_by_migration_id(CC::CCHelper.create_key(cal2))
cal2_2.title.should == cal2.title
cal2_2.start_at.to_i.should == cal2.start_at.to_i
cal2_2.end_at.to_i.should == cal2.end_at.to_i
cal2_2.description.should == ''
end
it "should import quizzes into correct assignment group" do
quiz_hash = {"lock_at"=>nil,
"questions"=>[],

View File

@ -22,14 +22,15 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_canceled_by_user.email' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => user)
generate_message(:appointment_canceled_by_user, :email, @event)
generate_message(:appointment_canceled_by_user, :email, @event,
:user => @user, :data => {:updating_user => user,
:cancel_reason => "because"})
@message.subject.should include('some title')
@message.body.should include('some title')
@message.body.should include('just because')
@message.body.should include('because')
@message.body.should include(user.name)
@message.body.should include(@course.name)
@message.body.should include("/appointment_groups/#{@appointment_group.id}")
@ -41,10 +42,12 @@ describe 'appointment_canceled_by_user.email' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => user, :participant => @group, :course => @course)
appointment_participant_model(:participant => @group, :course => @course)
@event.cancel_reason = 'just because'
generate_message(:appointment_canceled_by_user, :email, @event)
generate_message(:appointment_canceled_by_user, :email, @event,
:data => {:updating_user => user,
:cancel_reason => "just because"})
@message.subject.should include('some title')
@message.body.should include('some title')

View File

@ -22,10 +22,11 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_canceled_by_user.facebook' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => user)
generate_message(:appointment_canceled_by_user, :facebook, @event)
generate_message(:appointment_canceled_by_user, :facebook, @event,
:data => {:updating_user => user,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include('just because')
@ -40,10 +41,11 @@ describe 'appointment_canceled_by_user.facebook' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => user, :participant => @group, :course => @course)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_canceled_by_user, :facebook, @event)
generate_message(:appointment_canceled_by_user, :facebook, @event,
:data => {:updating_user => user,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include('just because')

View File

@ -22,10 +22,11 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_canceled_by_user.sms' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => user)
generate_message(:appointment_canceled_by_user, :sms, @event)
generate_message(:appointment_canceled_by_user, :sms, @event,
:data => {:updating_user => user,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include(user.name)
@ -37,10 +38,12 @@ describe 'appointment_canceled_by_user.sms' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => user, :participant => @group, :course => @course)
appointment_participant_model(:participant => @group, :course => @course)
@event.cancel_reason = 'just because'
generate_message(:appointment_canceled_by_user, :sms, @event)
generate_message(:appointment_canceled_by_user, :sms, @event,
:data => {:updating_user => user,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include(user.name)

View File

@ -22,10 +22,11 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_canceled_by_user.twitter' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => user)
generate_message(:appointment_canceled_by_user, :twitter, @event)
generate_message(:appointment_canceled_by_user, :twitter, @event,
:data => {:updating_user => user,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include(user.name)
@ -37,10 +38,11 @@ describe 'appointment_canceled_by_user.twitter' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => user, :participant => @group, :course => @course)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_canceled_by_user, :twitter, @event)
generate_message(:appointment_canceled_by_user, :twitter, @event,
:data => {:updating_user => user,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include(user.name)

View File

@ -22,10 +22,11 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_deleted_for_user.email' do
it "should render" do
user = user_model(:name => 'bob')
appointment_participant_model(:updating_user => @teacher, :participant => user)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => user)
generate_message(:appointment_deleted_for_user, :email, @event)
generate_message(:appointment_deleted_for_user, :email, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.subject.should include('some title')
@message.body.should include('some title')
@ -42,10 +43,11 @@ describe 'appointment_deleted_for_user.email' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => @teacher, :participant => @group, :course => @course)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_deleted_for_user, :email, @event)
generate_message(:appointment_deleted_for_user, :email, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.subject.should include('some title')
@message.body.should include('some title')

View File

@ -22,10 +22,11 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_deleted_for_user.facebook' do
it "should render" do
user = user_model(:name => 'bob')
appointment_participant_model(:updating_user => @teacher, :participant => user)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => user)
generate_message(:appointment_deleted_for_user, :facebook, @event)
generate_message(:appointment_deleted_for_user, :facebook, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include('just because')
@ -41,10 +42,11 @@ describe 'appointment_deleted_for_user.facebook' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => @teacher, :participant => @group, :course => @course)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_deleted_for_user, :facebook, @event)
generate_message(:appointment_deleted_for_user, :facebook, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.body.should include('some title')
@message.body.should include('just because')

View File

@ -22,10 +22,11 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_deleted_for_user.sms' do
it "should render" do
user = user_model(:name => 'bob')
appointment_participant_model(:updating_user => @teacher, :participant => user)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => user)
generate_message(:appointment_deleted_for_user, :sms, @event)
generate_message(:appointment_deleted_for_user, :sms, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.body.should include('some title')
end
@ -36,10 +37,11 @@ describe 'appointment_deleted_for_user.sms' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => @teacher, :participant => @group, :course => @course)
@event.cancel_reason = 'just because'
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_deleted_for_user, :sms, @event)
generate_message(:appointment_deleted_for_user, :sms, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.body.should include('some title')
end

View File

@ -22,10 +22,12 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_deleted_for_user.twitter' do
it "should render" do
user = user_model(:name => 'bob')
appointment_participant_model(:updating_user => @teacher, :participant => user)
appointment_participant_model(:participant => user)
@event.cancel_reason = 'just because'
generate_message(:appointment_deleted_for_user, :twitter, @event)
generate_message(:appointment_deleted_for_user, :twitter, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.body.should include('some title')
end
@ -36,10 +38,12 @@ describe 'appointment_deleted_for_user.twitter' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => @teacher, :participant => @group, :course => @course)
appointment_participant_model(:participant => @group, :course => @course)
@event.cancel_reason = 'just because'
generate_message(:appointment_deleted_for_user, :twitter, @event)
generate_message(:appointment_deleted_for_user, :twitter, @event,
:data => {:updating_user => @teacher,
:cancel_reason => "just because"})
@message.body.should include('some title')
end

View File

@ -23,13 +23,13 @@ describe 'appointment_group_deleted.email' do
it "should render" do
course_with_student(:active_all => true)
appointment_group_model(:contexts => [@course])
@appointment_group.cancel_reason = 'just because'
generate_message(:appointment_group_deleted, :email, @appointment_group, :user => @user)
generate_message(:appointment_group_deleted, :email, @appointment_group,
:user => @user, :data => {:cancel_reason => "because"})
@message.subject.should include('some title')
@message.body.should include('some title')
@message.body.should include('just because')
@message.body.should include('because')
@message.body.should include(@course.name)
end
end

View File

@ -25,10 +25,11 @@ describe 'appointment_group_deleted.facebook' do
appointment_group_model(:contexts => [@course])
@appointment_group.cancel_reason = 'just because'
generate_message(:appointment_group_deleted, :facebook, @appointment_group, :user => @user)
generate_message(:appointment_group_deleted, :facebook, @appointment_group,
:user => @user, :data => {:cancel_reason => "because"})
@message.body.should include('some title')
@message.body.should include('just because')
@message.body.should include('because')
@message.body.should include(@course.name)
end
end

View File

@ -21,11 +21,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_group_deleted.sms' do
it "should render" do
user = user_model
appointment_group_model(:contexts => [course_model])
@appointment_group.cancel_reason = 'just because'
generate_message(:appointment_group_deleted, :sms, @appointment_group)
generate_message(:appointment_group_deleted, :sms, @appointment_group,
:data => {:cancel_reason => "just because"})
@message.body.should include('some title')
end

View File

@ -21,11 +21,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_group_deleted.twitter' do
it "should render" do
user = user_model
appointment_group_model(:contexts => [course_model])
@appointment_group.cancel_reason = 'just because'
generate_message(:appointment_group_deleted, :twitter, @appointment_group)
generate_message(:appointment_group_deleted, :twitter, @appointment_group,
:data => {:cancel_reason => "just because"})
@message.body.should include('some title')
end

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_by_user.email' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_by_user, :email, @event)
generate_message(:appointment_reserved_by_user, :email, @event,
:data => {:updating_user => user})
@message.subject.should include('some title')
@message.body.should include('some title')
@ -39,9 +40,10 @@ describe 'appointment_reserved_by_user.email' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => user, :participant => @group, :course => @course)
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_reserved_by_user, :email, @event)
generate_message(:appointment_reserved_by_user, :email, @event,
:data => {:updating_user => user})
@message.subject.should include('some title')
@message.body.should include('some title')

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_by_user.facebook' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_by_user, :facebook, @event)
generate_message(:appointment_reserved_by_user, :facebook, @event,
:data => {:updating_user => user})
@message.body.should include('some title')
@message.body.should include(user.name)
@ -38,9 +39,10 @@ describe 'appointment_reserved_by_user.facebook' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => user, :participant => @group, :course => @course)
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_reserved_by_user, :facebook, @event)
generate_message(:appointment_reserved_by_user, :facebook, @event,
:data => {:updating_user => user})
@message.body.should include('some title')
@message.body.should include(user.name)

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_by_user.sms' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_by_user, :sms, @event)
generate_message(:appointment_reserved_by_user, :sms, @event,
:data => {:updating_user => user})
@message.body.should include('some title')
@message.body.should include(user.name)

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_by_user.twitter' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => user, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_by_user, :twitter, @event)
generate_message(:appointment_reserved_by_user, :twitter, @event,
:data => {:updating_user => user})
@message.body.should include('some title')
@message.body.should include(user.name)

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_for_user.email' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => @teacher, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_for_user, :email, @event)
generate_message(:appointment_reserved_for_user, :email, @event,
:data => {:updating_user => @teacher})
@message.subject.should include('some title')
@message.body.should include('some title')
@ -40,9 +41,10 @@ describe 'appointment_reserved_for_user.email' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => @teacher, :participant => @group, :course => @course)
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_reserved_for_user, :email, @event)
generate_message(:appointment_reserved_for_user, :email, @event,
:data => {:updating_user => @teacher})
@message.subject.should include('some title')
@message.body.should include('some title')

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_for_user.facebook' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => @teacher, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_for_user, :facebook, @event)
generate_message(:appointment_reserved_for_user, :facebook, @event,
:data => {:updating_user => @teacher})
@message.body.should include('some title')
@message.body.should include(@teacher.name)
@ -39,9 +40,10 @@ describe 'appointment_reserved_for_user.facebook' do
cat = @course.group_categories.create
@group = cat.groups.create(:context => @course)
@group.users << user
appointment_participant_model(:updating_user => @teacher, :participant => @group, :course => @course)
appointment_participant_model(:participant => @group, :course => @course)
generate_message(:appointment_reserved_for_user, :facebook, @event)
generate_message(:appointment_reserved_for_user, :facebook, @event,
:data => {:updating_user => @teacher})
@message.body.should include('some title')
@message.body.should include(@teacher.name)

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_for_user.sms' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => @teacher, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_for_user, :sms, @event)
generate_message(:appointment_reserved_for_user, :sms, @event,
:data => {:updating_user => @teacher})
@message.body.should include('some title')
end

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_for_user.summary' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => @teacher, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_for_user, :summary, @event)
generate_message(:appointment_reserved_for_user, :summary, @event,
:data => {:updating_user => @teacher})
@message.subject.should include('some title')
@message.body.should include('some title')

View File

@ -22,9 +22,10 @@ require File.expand_path(File.dirname(__FILE__) + '/messages_helper')
describe 'appointment_reserved_for_user.twitter' do
it "should render" do
user = user_model
appointment_participant_model(:updating_user => @teacher, :participant => user)
appointment_participant_model(:participant => user)
generate_message(:appointment_reserved_for_user, :twitter, @event)
generate_message(:appointment_reserved_for_user, :twitter, @event,
:data => {:updating_user => @teacher})
@message.body.should include('some title')
end

View File

@ -21,10 +21,11 @@ def generate_message(notification_name, path_type, asset, options = {})
@notification = Notification.create!(:name => notification_name.to_s)
user = options[:user]
asset_context = options[:asset_context]
data = options[:data] || {}
user ||= User.create!(:name => "some user")
@cc = user.communication_channels.create!(:path_type => path_type.to_s, :path => 'generate_message@example.com')
@message = Message.new(:notification => @notification, :context => asset, :user => user, :communication_channel => @cc, :asset_context => asset_context)
@message = Message.new(:notification => @notification, :context => asset, :user => user, :communication_channel => @cc, :asset_context => asset_context, :data => data)
@message.delayed_messages = []
@message.parse!(path_type.to_s)
@message.body.should_not be_nil

View File

@ -49,9 +49,11 @@ describe AppointmentGroup do
group.should be_valid
group.sub_context_codes.should be_empty
end
end
context "add context" do
it "should only add contexts" do
course1 = @course
course1 = course
course_with_student(:active_all => true)
course2 = @course
@ -71,9 +73,20 @@ describe AppointmentGroup do
group.save!
group.contexts.should eql [course1, course2]
end
end
context "add context" do
it "should not add contexts when it has a group category" do
course1 = course
gc = course1.group_categories.create!
ag = AppointmentGroup.create!(:title => 'test',
:contexts => [course1],
:sub_context_codes => [gc.asset_string])
ag.contexts.should eql [course1]
ag.contexts = [course]
ag.save!
ag.contexts.should eql [course1]
end
it "should update appointments effective_context_code" do
course(:active_all => true)
course1 = @course
@ -95,6 +108,32 @@ describe AppointmentGroup do
end
end
context "add sub_contexts" do
before do
@course1 = course
@c1section1 = @course1.default_section
@c1section2 = @course1.course_sections.create!
@course2 = course
end
it "should only add sub_contexts when first adding a course" do
ag = AppointmentGroup.create! :title => 'test',
:contexts => [@course1],
:sub_context_codes => [@c1section1.asset_string]
ag.sub_contexts.should eql [@c1section1]
ag.sub_context_codes = [@c1section2.asset_string]
ag.sub_contexts.should eql [@c1section1]
ag.contexts = [@course1, @course2]
c2section = @course2.default_section.asset_string
ag.sub_context_codes = [c2section]
ag.save!
ag.contexts.should eql [@course1, @course2]
ag.sub_context_codes.should eql [@c1section1.asset_string, c2section]
end
end
context "add_appointment" do
before do
course_with_student(:active_all => true)
@ -132,14 +171,6 @@ describe AppointmentGroup do
end
context "permissions" do
def student_in_section(section)
@user = user
enrollment = @course.enroll_user(@user, 'StudentEnrollment', :section => section)
enrollment.workflow_state = 'active'
enrollment.save!
@user
end
before do
course_with_teacher(:active_all => true)
@teacher = @user
@ -154,8 +185,8 @@ describe AppointmentGroup do
@student = @user
@user_group.users << @user
@student_in_section2 = student_in_section(section2)
@student_in_section3 = student_in_section(section3)
@student_in_section2 = student_in_section(section2, :course => @course)
@student_in_section3 = student_in_section(section3, :course => @course)
user(:active_all => true)
@course.enroll_user(@user, 'TaEnrollment', :section => section2, :limit_privileges_to_course_section => true).accept!
@ -187,6 +218,17 @@ describe AppointmentGroup do
@g8 = AppointmentGroup.create(:title => "test", :contexts => [@course2, @course3])
@g8.publish!
c2s2 = @course2.course_sections.create!
c3s2 = @course3.course_sections.create!
@student_in_course2_section2 = student_in_section(c2s2, :course => @course2)
@student_in_course3_section2 = student_in_section(c3s2, :course => @course3)
# multiple contexts and sub contexts
@g9 = AppointmentGroup.create! :title => "multiple everything",
:contexts => [@course2, @course3],
:sub_context_codes => [c2s2.asset_string, c3s2.asset_string]
@g9.publish!
@groups = [@g1, @g2, @g3, @g4, @g5, @g7]
end
@ -233,6 +275,14 @@ describe AppointmentGroup do
@g8.grants_right?(@student_in_course1, nil, :reserve).should be_false
@g8.grants_right?(@student_in_course2, nil, :reserve).should be_true
@g8.grants_right?(@student_in_course3, nil, :reserve).should be_true
# multiple contexts and sub contexts
@g9.grants_right?(@student_in_course1, nil, :reserve).should be_false
@g9.grants_right?(@student_in_course2, nil, :reserve).should be_false
@g9.grants_right?(@student_in_course3, nil, :reserve).should be_false
@g9.grants_right?(@student_in_course2_section2, nil, :reserve).should be_true
@g9.grants_right?(@student_in_course3_section2, nil, :reserve).should be_true
end
@ -257,7 +307,7 @@ describe AppointmentGroup do
@g4.grants_right?(@ta, nil, :manage).should be_false
@g5.grants_right?(@ta, nil, :manage).should be_true
@g6.grants_right?(@ta, nil, :manage).should be_false
@g7.grants_right?(@ta, nil, :manage).should be_true
@g7.grants_right?(@ta, nil, :manage).should be_false # not in all sections
# student can't manage anything
visible_groups = AppointmentGroup.manageable_by(@student).sort_by(&:id)
@ -268,6 +318,10 @@ describe AppointmentGroup do
@g8.grants_right?(@teacher, nil, :manage).should be_false # not in any courses
@g8.grants_right?(@teacher2, nil, :manage).should be_true
@g8.grants_right?(@teacher3, nil, :manage).should be_false # not in all courses
# multiple contexts and sub contexts
@g9.grants_right?(@teacher2, nil, :manage).should be_true
@g9.grants_right?(@teacher3, nil, :manage).should be_false
end
end
@ -303,6 +357,7 @@ describe AppointmentGroup do
it "should notify all participants when deleting" do
@ag.publish!
@ag.cancel_reason = "just because"
@ag.destroy
@ag.messages_sent.should be_include("Appointment Group Deleted")
@ag.messages_sent["Appointment Group Deleted"].map(&:user_id).sort.uniq.should eql [@student.id]

View File

@ -25,7 +25,7 @@ describe ContentMigration do
course_with_teacher(:course_name => "from course", :active_all => true)
@copy_from = @course
course_with_teacher(:user => @user, :course_name => "to course")
course_with_teacher(:user => @user, :course_name => "tocourse", :course_code => "tocourse")
@copy_to = @course
@cm = ContentMigration.new(:context => @copy_to, :user => @user, :source_course => @copy_from, :copy_options => {:everything => "1"})
@ -88,17 +88,98 @@ describe ContentMigration do
@copy_to.syllabus_body.should match(/\/courses\/#{@copy_to.id}\/discussion_topics\/#{new_topic.id}/)
end
def make_grading_standard(context)
gs = context.grading_standards.new
gs.title = "Standard eh"
gs.data = [["A", 0.93], ["A-", 0.89], ["B+", 0.85], ["B", 0.83], ["B!-", 0.80], ["C+", 0.77], ["C", 0.74], ["C-", 0.70], ["D+", 0.67], ["D", 0.64], ["D-", 0.61], ["F", 0]]
gs.save!
gs
end
it "should copy course attributes" do
@copy_from.tab_configuration = [{"id"=>0}, {"id"=>14}, {"id"=>8}, {"id"=>5}, {"id"=>6}, {"id"=>2}, {"id"=>3, "hidden"=>true}]
#set all the possible values to non-default values
@copy_from.start_at = 5.minutes.ago
@copy_from.conclude_at = 1.month.from_now
@copy_from.is_public = false
@copy_from.name = "haha copy from test &amp;"
@copy_from.course_code = 'something funny'
@copy_from.publish_grades_immediately = false
@copy_from.allow_student_wiki_edits = true
@copy_from.allow_student_assignment_edits = true
@copy_from.hashtag = 'oi'
@copy_from.show_public_context_messages = false
@copy_from.allow_student_forum_attachments = false
@copy_from.default_wiki_editing_roles = 'teachers'
@copy_from.allow_student_organized_groups = false
@copy_from.default_view = 'modules'
@copy_from.show_all_discussion_entries = false
@copy_from.open_enrollment = true
@copy_from.storage_quota = 444
@copy_from.allow_wiki_comments = true
@copy_from.turnitin_comments = "Don't plagiarize"
@copy_from.self_enrollment = true
@copy_from.license = "cc_by_nc_nd"
@copy_from.locale = "es"
@copy_from.save
@copy_from.tab_configuration = [{"id"=>0}, {"id"=>14}, {"id"=>8}, {"id"=>5}, {"id"=>6}, {"id"=>2}, {"id"=>3, "hidden"=>true}]
@copy_from.settings[:hide_final_grade] = true
gs = make_grading_standard(@copy_from)
@copy_from.grading_standard = gs
@copy_from.grading_standard_enabled = true
@copy_from.save!
body_with_link = %{<p>Watup? <strong>eh?</strong><a href="/courses/%s/assignments">Assignments</a></p>
<div>
<div><img src="http://www.instructure.com/images/header-logo.png"></div>
<div><img src="http://www.instructure.com/images/header-logo.png"></div>
</div>}
@copy_from.syllabus_body = body_with_link % @copy_from.id
run_course_copy
@copy_to.locale.should == 'es'
#compare settings
@copy_to.conclude_at.should == nil
@copy_to.start_at.should == nil
@copy_to.syllabus_body.should == (body_with_link % @copy_to.id)
@copy_to.storage_quota.should == 444
@copy_to.settings[:hide_final_grade].should == true
@copy_to.grading_standard_enabled.should == true
gs_2 = @copy_to.grading_standards.find_by_migration_id(mig_id(gs))
gs_2.data.should == gs.data
@copy_to.grading_standard.should == gs_2
@copy_to.name.should == "tocourse"
@copy_to.course_code.should == "tocourse"
atts = Course.clonable_attributes
atts -= Canvas::Migration::MigratorHelper::COURSE_NO_COPY_ATTS
atts.each do |att|
@copy_to.send(att).should == @copy_from.send(att)
end
@copy_to.tab_configuration.should == @copy_from.tab_configuration
end
it "should retain reference to account grading standard" do
gs = make_grading_standard(@copy_from.root_account)
@copy_from.grading_standard = gs
@copy_from.grading_standard_enabled = true
@copy_from.save!
run_course_copy
@copy_to.grading_standard.should == gs
end
it "should create a warning if an account grading standard can't be found" do
gs = make_grading_standard(@copy_from.root_account)
@copy_from.grading_standard = gs
@copy_from.grading_standard_enabled = true
@copy_from.save!
gs.delete
run_course_copy(["Couldn't find account grading standard for the course."])
@copy_to.grading_standard.should == nil
end
it "should copy external tools" do
tool_from = @copy_from.context_external_tools.create!(:name => "new tool", :consumer_key => "key", :shared_secret => "secret", :domain => 'example.com', :custom_fields => {'a' => '1', 'b' => '2'})
tool_from.settings[:course_navigation] = {:url => "http://www.example.com", :text => "Example URL"}
@ -600,7 +681,7 @@ describe ContentMigration do
@copy_to.syllabus_body.should == @copy_from.syllabus_body.gsub("/courses/#{@copy_from.id}/file_contents/course%20files",'')
end
it "should included implied files for course exports" do
it "should include implied files for course exports" do
att = Attachment.create!(:filename => 'first.png', :uploaded_data => StringIO.new('ohai'), :folder => Folder.root_folders(@copy_from).first, :context => @copy_from)
att2 = Attachment.create!(:filename => 'second.jpg', :uploaded_data => StringIO.new('ohais'), :folder => Folder.root_folders(@copy_from).first, :context => @copy_from)
att3 = Attachment.create!(:filename => 'third.jpg', :uploaded_data => StringIO.new('3333'), :folder => Folder.root_folders(@copy_from).first, :context => @copy_from)
@ -941,6 +1022,42 @@ equation: <img class="equation_image" title="Log_216" src="/equation_images/Log_
aq.question_data[:answers][1][:left_html].should == data2[:answers][1][:left_html]
end
it "should import calendar events" do
body_with_link = "<p>Watup? <strong>eh?</strong><a href=\"/courses/%s/assignments\">Assignments</a></p>"
cal = @copy_from.calendar_events.new
cal.title = "Calendar event"
cal.description = body_with_link % @copy_from.id
cal.start_at = 1.week.from_now
cal.save!
cal.all_day = true
cal.save!
cal2 = @copy_from.calendar_events.new
cal2.title = "Stupid events"
cal2.start_at = 5.minutes.from_now
cal2.end_at = 10.minutes.from_now
cal2.all_day = false
cal2.save!
cal3 = @copy_from.calendar_events.create!(:title => "deleted event")
cal3.destroy
run_course_copy
@copy_to.calendar_events.count.should == 2
cal_2 = @copy_to.calendar_events.find_by_migration_id(CC::CCHelper.create_key(cal))
cal_2.title.should == cal.title
cal_2.start_at.to_i.should == cal.start_at.to_i
cal_2.end_at.to_i.should == cal.end_at.to_i
cal_2.all_day.should == true
cal_2.all_day_date.should == cal.all_day_date
cal_2.description = body_with_link % @copy_to.id
cal2_2 = @copy_to.calendar_events.find_by_migration_id(CC::CCHelper.create_key(cal2))
cal2_2.title.should == cal2.title
cal2_2.start_at.to_i.should == cal2.start_at.to_i
cal2_2.end_at.to_i.should == cal2.end_at.to_i
cal2_2.description.should == ''
end
context "copying frozen assignments" do
append_before (:each) do
@setting = PluginSetting.create!(:name => "assignment_freezer", :settings => {"no_copying" => "yes"})

View File

@ -2518,6 +2518,34 @@ describe Course, ".import_from_migration" do
@course.course_imports.first.update_attribute(:workflow_state, 'failed')
@course.should_not have_open_course_imports
end
describe "setting storage quota" do
before do
course_with_teacher
@course.storage_quota = 1
@cm = ContentMigration.new(:context => @course, :user => @user, :copy_options => {:everything => "1"})
@cm.user = @user
@cm.save!
end
it "should not adjust for unauthorized user" do
@course.import_settings_from_migration({:course=>{:storage_quota => 4}}, @cm)
@course.storage_quota.should == 1
end
it "should adjust for authorized user" do
account_admin_user(:user => @user)
@course.import_settings_from_migration({:course=>{:storage_quota => 4}}, @cm)
@course.storage_quota.should == 4
end
it "should be set for course copy" do
@cm.source_course = @course
@course.import_settings_from_migration({:course=>{:storage_quota => 4}}, @cm)
@course.storage_quota.should == 4
end
end
end
describe Course, "enrollments" do

View File

@ -85,7 +85,7 @@ describe "conversations" do
it "should link to the course page" do
get_messages
find_with_jquery("#create_message_form .audience a").click
expect_new_page_load { fj("#create_message_form .audience a").click }
driver.current_url.should match %r{/courses/#{@course.id}}
end

View File

@ -33,7 +33,7 @@ describe "cross-listing" do
keep_trying_until { course_name.text != "Confirming Course ID \"#{@course2.id}\"..." }
course_name.text.should eql @course2.name
form.find_element(:id, 'course_autocomplete_id').attribute(:value).should eql @course.id.to_s
submit_btn.attribute(:disabled).should eql 'false'
submit_btn.should_not have_class('disabled')
submit_btn.click
wait_for_ajaximations
keep_trying_until { driver.current_url.match /courses\/#{@course2.id}/ }

View File

@ -84,11 +84,11 @@ describe "dashboard" do
@appointment_group.update_attributes(:new_appointments => [[Time.now.utc + 2.hour, Time.now.utc + 3.hour]])
get "/"
find_all_with_jquery(".topic_message div.communication_message.dashboard_notification").size.should == 3
ffj(".topic_message div.communication_message.dashboard_notification").size.should == 3
# appointment group publish and update notifications
find_all_with_jquery("div.communication_message.message_appointment_group_#{@appointment_group.id}").size.should == 2
ffj("div.communication_message.message_appointment_group_#{@appointment_group.id}").size.should == 2
# signup notification
find_all_with_jquery("div.communication_message.message_group_#{@group.id}").size.should == 1
ffj("div.communication_message.message_group_#{@group.id}").size.should == 1
end
it "should display assignment in to do list" do

View File

@ -34,9 +34,9 @@ shared_examples_for "discussions selenium tests" do
end
def delete_entry(entry)
click_entry_option(entry, '#ui-menu-0-2')
validate_entry_text(entry, "This entry has been deleted")
keep_trying_until do
click_entry_option(entry, '#ui-menu-0-2')
validate_entry_text(entry, "This entry has been deleted")
entry.save!
entry.reload
entry.workflow_state.should == 'deleted'
@ -56,8 +56,8 @@ shared_examples_for "discussions selenium tests" do
f('.discussion-reply-form').submit
wait_for_ajax_requests
keep_trying_until {
id = DiscussionEntry.last.id
keep_trying_until {
id = DiscussionEntry.last.id
@last_entry = fj ".entry[data-id=#{id}]"
}
end
@ -75,14 +75,11 @@ shared_examples_for "discussions selenium tests" do
def click_entry_option(discussion_entry, menu_item_selector)
li_selector = %([data-id$="#{discussion_entry.id}"])
menu_item = keep_trying_until do
fj(li_selector).should be_displayed
fj("#{li_selector} .al-trigger").should be_displayed
fj("#{li_selector} .al-trigger").click
menu_item = fj(menu_item_selector)
menu_item.should be_displayed
menu_item
end
fj(li_selector).should be_displayed
fj("#{li_selector} .al-trigger").should be_displayed
fj("#{li_selector} .al-trigger").click
menu_item = fj(menu_item_selector)
menu_item.should be_displayed
menu_item.click
end

View File

@ -321,6 +321,7 @@ describe "discussions" do
end
it "should delete a side comment" do
pending("intermittently fails")
entry = @topic.discussion_entries.create!(:user => @student, :message => "new side comment from student", :parent_entry => @entry)
get "/courses/#{@course.id}/discussion_topics/#{@topic.id}"
wait_for_ajax_requests

View File

@ -76,14 +76,13 @@ describe "Wiki pages and Tiny WYSIWYG editor Images" do
new_course.enroll_teacher(@user)
get "/courses/#{new_course.id}/wiki"
@tree1 = driver.find_element(:id, :tree1)
@image_list = driver.find_element(:css, '#editor_tabs_3 .image_list')
driver.find_element(:css, '#editor_tabs .ui-tabs-nav li:nth-child(3) a').click
keep_trying_until {
images = @image_list.find_elements(:css, 'img.img')
f('#editor_tabs .ui-tabs-nav li:nth-child(3) a').click
keep_trying_until do
images = ffj('#editor_tabs_3 .image_list img.img')
images.length.should == 2
images.each { |i| i.attribute('complete').should == 'true' }
}
#images.each { |i| i.attribute('complete').should == 'true' } - commented out because it is breaking with
#webdriver 2.22 and firefox 12
end
end
it "should infini-scroll images" do

View File

@ -240,7 +240,7 @@ describe "Wiki pages and Tiny WYSIWYG editor" do
end
[:width, :color].each do |part|
[:top, :right, :bottom, :left].each do |side|
expected_value = attributes[{:width => :border, :color => :bordercolor}[part]] || {:width => 1, :color => 'rgb(136, 136, 136)'}[part]
expected_value = attributes[{:width => :border, :color => :bordercolor}[part]] || {:width => 1, :color => 'rgba(136,136,136,1)'}[part]
if expected_value.is_a?(Numeric)
expected_value = 1 if expected_value == 0
expected_value = "#{expected_value}px"
@ -262,7 +262,7 @@ describe "Wiki pages and Tiny WYSIWYG editor" do
:cellpadding => 5,
:cellspacing => 6,
:border => 7,
:bordercolor => 'rgb(255, 0, 0)'
:bordercolor => 'rgba(255,0,0,1)'
)
check_table(
:align => 'center',

View File

@ -313,6 +313,14 @@ Spec::Runner.configure do |config|
course_with_student(opts)
end
def student_in_section(section, opts={})
user
enrollment = section.course.enroll_user(@user, 'StudentEnrollment', :section => section)
enrollment.workflow_state = 'active'
enrollment.save!
@user
end
def teacher_in_course(opts={})
opts[:course] = @course if @course && !opts[:course]
course_with_teacher(opts)

View File

@ -93,7 +93,7 @@ class Converter < Canvas::Migration::Migrator
raise "The QTI must be converted to 2.1 before converting to JSON" unless @converted
begin
manifest_file = File.join(@dest_dir_2_1, MANIFEST_FILE)
@quizzes[:assessments] = Qti.convert_assessments(manifest_file, :converted_questions => questions)
@quizzes[:assessments] = Qti.convert_assessments(manifest_file, @settings.merge({:converted_questions => questions}))
rescue => e
message = "Error processing assessment QTI data: #{$!}: #{$!.backtrace.join("\n")}"
add_error "qti_assessments", message, @questions, e

View File

@ -6,7 +6,7 @@ describe "Converting Blackboard Vista qti" do
archive_file_path = File.join(BASE_FIXTURE_DIR, 'bb_vista', 'vista_archive.zip')
unzipped_file_path = File.join(File.dirname(archive_file_path), "qti_#{File.basename(archive_file_path, '.zip')}", 'oi')
export_folder = File.join(File.dirname(archive_file_path), "qti_vista_archive")
@exporter = Qti::Converter.new(:export_archive_path=>archive_file_path, :base_download_dir=>unzipped_file_path)
@exporter = Qti::Converter.new(:export_archive_path=>archive_file_path, :base_download_dir=>unzipped_file_path, :flavor => Qti::Flavors::WEBCT)
@exporter.export
@exporter.delete_unzipped_archive
@assessment = @exporter.course[:assessments][:assessments].first
@ -95,7 +95,7 @@ describe "Converting Blackboard Vista qti" do
end
it "should convert the assessments into quizzes" do
@assessment == VistaExpected::ASSESSMENT
@assessment.should == VistaExpected::ASSESSMENT
end
it "should convert simple calculated questions" do
@ -240,9 +240,10 @@ module VistaExpected
:question_count=>11,
:title=>"Blackboard Vista Export Test",
:quiz_name=>"Blackboard Vista Export Test",
:show_score=>true,
:quiz_type=>"assignment",
:allowed_attempts=>1,
:migration_id=>"ID_2f207fc5-0a34-0287-01c7-bcc0a626db16.4609765293341_R",
:migration_id=>"ID_4609765292341",
:questions=>
[{:question_type=>"question_reference",
:migration_id=>"ID_4609823478341",
@ -277,13 +278,11 @@ module VistaExpected
{:question_type=>"question_reference",
:migration_id=>"ID_4609885376341",
:points_possible=>10.0}],
:points_possible=>"237.0",
:grading=>
{
:migration_id=>"ID_2f207fc5-0a34-0287-01c7-bcc0a626db16.4609765293341_R",
:migration_id=>"ID_4609765292341",
:title=>"Blackboard Vista Export Test",
:points_possible=>"237.0",
:grade_type=>"numeric",
:points_possible=>nil,
:due_date=>nil,
:weight=>nil
}