Recurring calendar events
fixes CNVS-22005 CNVS-22033 (refs CNVS-19381) test plan: - With user calendar do - a recurring calendar event with 1-90 repeats - event with no repeats - With a course calendar do - repeats with all sections different dates - repeats with all sections same dates - all sections different dates no repeats - all sections same dates no repeats - regular calendar event with repeats - regular calendar event with no repeats - As a teacher, go to the Calendar - Click the "+" (Create New Event) button - Add some event details, then check the "Repeat" checkbox - Additional fields should appear regarding repeat information - Change the repeat fields, then save the event - The event should create, then the calendar should reload and show the duplicated events Change-Id: If8c90870d5c4b885a60810dc18868190a5639a5c Reviewed-on: https://gerrit.instructure.com/61209 Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> Tested-by: Jenkins QA-Review: Adrian Russell <arussell@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
This commit is contained in:
parent
0b06f93ef4
commit
8cca48a9fb
|
@ -509,6 +509,7 @@ define [
|
|||
# This is another reason to do a refetchEvents instead of just an update.
|
||||
delete event._id
|
||||
@calendar.fullCalendar('refetchEvents')
|
||||
@reloadClick() if event?.object?.duplicates?.length > 0
|
||||
# We'd like to just add the event to the calendar rather than fetching,
|
||||
# but the save may be as a result of moving an event from being undated
|
||||
# to dated, and in that case we don't know whether to just update it or
|
||||
|
|
|
@ -13,7 +13,7 @@ define [
|
|||
|
||||
_filterAttributes: (obj) ->
|
||||
filtered = _(obj).pick 'start_at', 'end_at', 'title', 'description',
|
||||
'context_code', 'remove_child_events', 'location_name', 'location_address'
|
||||
'context_code', 'remove_child_events', 'location_name', 'location_address', 'duplicate'
|
||||
if obj.use_section_dates && obj.child_event_data
|
||||
filtered.child_event_data = _.chain(obj.child_event_data)
|
||||
.compact()
|
||||
|
@ -61,6 +61,7 @@ define [
|
|||
.done(combinedSuccess)
|
||||
|
||||
@mergeSectionsIntoCalendarEvent = (eventData = {}, sections) ->
|
||||
eventData.recurring_calendar_events = ENV.RECURRING_CALENDAR_EVENTS_ENABLED
|
||||
eventData.course_sections = sections
|
||||
eventData.use_section_dates = !!eventData.child_events?.length
|
||||
_(eventData.child_events).each (child, index) ->
|
||||
|
|
|
@ -28,11 +28,12 @@ define [
|
|||
@$form.submit @formSubmit
|
||||
@$form.find(".more_options_link").click @moreOptionsClick
|
||||
@$form.find("select.context_id").change @contextChange
|
||||
@$form.find("#duplicate_event").change @duplicateCheckboxChanged
|
||||
@$form.find("select.context_id").triggerHandler('change', false)
|
||||
|
||||
# Hide the context selector completely if this is an existing event, since it can't be changed.
|
||||
if !@event.isNewEvent()
|
||||
@$form.find(".context_select").hide()
|
||||
# Context can't be changed, and duplication only works on create
|
||||
unless @event.isNewEvent()
|
||||
@$form.find(".context_select, .duplicate_event_row, .duplicate_event_toggle_row").hide()
|
||||
|
||||
contextInfoForCode: (code) ->
|
||||
for context in @event.possibleContexts()
|
||||
|
@ -45,7 +46,9 @@ define [
|
|||
|
||||
getFormData: =>
|
||||
data = @$form.getFormData(object_name: 'calendar_event')
|
||||
data = _.omit(data, 'date', 'start_time', 'end_time')
|
||||
data = _.omit(data,
|
||||
'date', 'start_time', 'end_time',
|
||||
'duplicate', 'duplicate_count', 'duplicate_interval', 'duplicate_frequency', 'append_iterator')
|
||||
|
||||
# check if input box was cleared for explicitly undated
|
||||
date = @$form.find('input[name=date]').data('date') if @$form.find('input[name=date]').val()
|
||||
|
@ -60,6 +63,14 @@ define [
|
|||
end_at += end_time.toString(' HH:mm') if end_time
|
||||
data.end_at = tz.parse(end_at)
|
||||
|
||||
if duplicate = @$form.find('#duplicate_event').prop('checked')
|
||||
data.duplicate = {
|
||||
count: @$form.find('#duplicate_count').val()
|
||||
interval: @$form.find('#duplicate_interval').val()
|
||||
frequency: @$form.find('#duplicate_frequency').val()
|
||||
append_iterator: @$form.find('#append_iterator').is(":checked")
|
||||
}
|
||||
|
||||
data
|
||||
|
||||
moreOptionsClick: (jsEvent) =>
|
||||
|
@ -80,6 +91,7 @@ define [
|
|||
if data.start_date then params['start_date'] = data.start_date
|
||||
if data.start_time then params['start_time'] = data.start_time
|
||||
if data.end_time then params['end_time'] = data.end_time
|
||||
if data.duplicate then params['duplicate'] = data.duplicate
|
||||
|
||||
pieces = $(jsEvent.target).attr('href').split("#")
|
||||
pieces[0] += "?" + $.param(params)
|
||||
|
@ -105,6 +117,15 @@ define [
|
|||
moreOptionsHref = @event.fullDetailsURL() + '/edit'
|
||||
@$form.find(".more_options_link").attr 'href', moreOptionsHref
|
||||
|
||||
duplicateCheckboxChanged: (jsEvent, propagate) =>
|
||||
@enableDuplicateFields(jsEvent.target.checked)
|
||||
|
||||
enableDuplicateFields: (shouldEnable) =>
|
||||
elts = @$form.find(".duplicate_fields").find('input')
|
||||
disableValue = !shouldEnable
|
||||
elts.prop("disabled", disableValue)
|
||||
@$form.find('.duplicate_event_row').toggle(!disableValue)
|
||||
|
||||
setupTimeAndDatePickers: () =>
|
||||
# select the appropriate fields
|
||||
$date = @$form.find(".date_field")
|
||||
|
@ -140,6 +161,8 @@ define [
|
|||
'calendar_event[location_name]': location_name
|
||||
}
|
||||
|
||||
params['calendar_event[duplicate]'] = data.duplicate if data.duplicate?
|
||||
|
||||
if @event.isNewEvent()
|
||||
params['calendar_event[context_code]'] = data.context_code
|
||||
objectData =
|
||||
|
|
|
@ -27,11 +27,15 @@ define [
|
|||
'change #use_section_dates': 'toggleUseSectionDates'
|
||||
'click .delete_link': 'destroyModel'
|
||||
'click .switch_event_description_view': 'toggleHtmlView'
|
||||
'change "#duplicate_event': 'duplicateCheckboxChanged'
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
@model.fetch().done =>
|
||||
picked_params = _.pick(deparam(), 'start_date', 'start_time', 'end_time', 'title', 'description', 'location_name', 'location_address')
|
||||
picked_params = _.pick(deparam(),
|
||||
'start_date', 'start_time', 'end_time',
|
||||
'title', 'description', 'location_name', 'location_address',
|
||||
'duplicate')
|
||||
|
||||
attrs = @model.parse(picked_params)
|
||||
# if start and end are at the beginning of a day, assume it is an all day date
|
||||
|
@ -41,9 +45,23 @@ define [
|
|||
@render()
|
||||
|
||||
# populate inputs with params passed through the url
|
||||
if picked_params.duplicate
|
||||
_.each _.keys(picked_params.duplicate), (key) =>
|
||||
oldKey = key
|
||||
key = "duplicate_#{key}" unless key is "append_iterator"
|
||||
picked_params[key] = picked_params.duplicate[oldKey]
|
||||
delete picked_params.duplicate[key]
|
||||
|
||||
picked_params.duplicate = !!picked_params.duplicate
|
||||
|
||||
_.each _.keys(picked_params), (key) =>
|
||||
$e = @$el.find("input[name='#{key}']")
|
||||
$e.val(picked_params[key])
|
||||
$e = @$el.find("input[name='#{key}'], select[name='#{key}']")
|
||||
value = if $e.prop('type') is "checkbox"
|
||||
[picked_params[key]]
|
||||
else
|
||||
picked_params[key]
|
||||
$e.val(value)
|
||||
@enableDuplicateFields($e.val()) if key is "duplicate"
|
||||
$e.change()
|
||||
|
||||
@model.on 'change:use_section_dates', @toggleUsingSectionClass
|
||||
|
@ -58,11 +76,14 @@ define [
|
|||
wikiSidebar.attachToEditor($textarea).show()
|
||||
|
||||
_.defer(@attachKeyboardShortcuts)
|
||||
_.defer(@toggleDuplicateOptions)
|
||||
this
|
||||
|
||||
attachKeyboardShortcuts: =>
|
||||
$('.switch_event_description_view').first().before((new KeyboardShortcuts()).render().$el)
|
||||
|
||||
toggleDuplicateOptions: =>
|
||||
@$el.find(".duplicate_event_toggle_row").toggle(@model.isNew())
|
||||
|
||||
destroyModel: =>
|
||||
msg = I18n.t "confirm_delete_calendar_event", "Are you sure you want to delete this calendar event?"
|
||||
|
@ -145,7 +166,24 @@ define [
|
|||
end_at += end_time.toString(' HH:mm') if end_time
|
||||
data[end_at_key] = tz.parse(end_at)
|
||||
|
||||
if @$el.find('#duplicate_event').prop('checked')
|
||||
data.duplicate = {
|
||||
count: @$el.find('#duplicate_count').val()
|
||||
interval: @$el.find('#duplicate_interval').val()
|
||||
frequency: @$el.find('#duplicate_frequency').val()
|
||||
append_iterator: @$el.find('#append_iterator').is(":checked")
|
||||
}
|
||||
|
||||
data
|
||||
|
||||
@type: 'event'
|
||||
@title: -> super 'event', 'Event'
|
||||
|
||||
enableDuplicateFields: (shouldEnable) =>
|
||||
elts = @$el.find(".duplicate_fields").find('input')
|
||||
disableValue = !shouldEnable
|
||||
elts.prop("disabled", disableValue)
|
||||
@$el.find('.duplicate_event_row').toggle(!disableValue)
|
||||
|
||||
duplicateCheckboxChanged: (jsEvent, propagate) =>
|
||||
@enableDuplicateFields(jsEvent.target.checked)
|
|
@ -350,6 +350,15 @@ class CalendarEventsApiController < ApplicationController
|
|||
# Section-level end time(s) if this is a course event.
|
||||
# @argument calendar_event[child_event_data][X][context_code] [String]
|
||||
# Context code(s) corresponding to the section-level start and end time(s).
|
||||
# @argument calendar_event[duplicate][count] [Number]
|
||||
# Number of times to copy/duplicate the event.
|
||||
# @argument calendar_event[duplicate][interval] [Number]
|
||||
# Defaults to 1 if duplicate `count` is set. The interval between the duplicated events.
|
||||
# @argument calendar_event[duplicate][frequency] [String, "daily"|"weekly"|"monthly"]
|
||||
# Defaults to "weekly". The frequency at which to duplicate the event
|
||||
# @argument calendar_event[duplicate][append_iterator] [Boolean]
|
||||
# Defaults to false. If set to `true`, an increasing counter number will be appended to the event title
|
||||
# when the event is duplicated. (e.g. Event 1, Event 2, Event 3, etc)
|
||||
#
|
||||
# @example_request
|
||||
#
|
||||
|
@ -364,14 +373,50 @@ class CalendarEventsApiController < ApplicationController
|
|||
if params[:calendar_event][:description].present?
|
||||
params[:calendar_event][:description] = process_incoming_html_content(params[:calendar_event][:description])
|
||||
end
|
||||
|
||||
@event = @context.calendar_events.build(params[:calendar_event])
|
||||
@event.updating_user = @current_user
|
||||
@event.validate_context! if @context.is_a?(AppointmentGroup)
|
||||
|
||||
if authorized_action(@event, @current_user, :create)
|
||||
@event.validate_context! if @context.is_a?(AppointmentGroup)
|
||||
@event.updating_user = @current_user
|
||||
if @event.save
|
||||
render :json => event_json(@event, @current_user, session), :status => :created
|
||||
# Create duplicates if necessary
|
||||
events = []
|
||||
dup_options = get_duplicate_params(params[:calendar_event])
|
||||
title = dup_options[:title]
|
||||
|
||||
if dup_options[:count] > 0
|
||||
section_events = params[:calendar_event].delete(:child_event_data)
|
||||
# handles multiple section repeast
|
||||
section_events.each do |event|
|
||||
event[:title] = title
|
||||
section_dup_options = get_duplicate_params(event)
|
||||
events += create_event_and_duplicates(section_dup_options)
|
||||
end if section_events.present?
|
||||
|
||||
events += create_event_and_duplicates(dup_options) unless section_events.present?
|
||||
else
|
||||
render :json => @event.errors, :status => :bad_request
|
||||
events = [@event]
|
||||
end
|
||||
|
||||
if dup_options[:count] > 100
|
||||
return render :json => {
|
||||
message: t("only a maximum of 100 events can be created")
|
||||
}, :status => :bad_request
|
||||
end
|
||||
|
||||
CalendarEvent.transaction do
|
||||
error = events.detect { |event| !event.save }
|
||||
|
||||
if error
|
||||
render :json => error.errors, :status => :bad_request
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
original_event = events.shift
|
||||
render :json => event_json(
|
||||
original_event,
|
||||
@current_user,
|
||||
session, { :duplicates => events }), :status => :created
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -379,6 +424,7 @@ class CalendarEventsApiController < ApplicationController
|
|||
# @API Get a single calendar event or assignment
|
||||
#
|
||||
# @returns CalendarEvent
|
||||
|
||||
def show
|
||||
get_event(true)
|
||||
if authorized_action(@event, @current_user, :read)
|
||||
|
@ -848,6 +894,59 @@ class CalendarEventsApiController < ApplicationController
|
|||
map(&:asset_string)
|
||||
end
|
||||
|
||||
def select_public_codes(codes)
|
||||
def duplicate(options = {})
|
||||
@context ||= @current_user
|
||||
|
||||
if @current_user
|
||||
get_all_pertinent_contexts(include_groups: true)
|
||||
end
|
||||
|
||||
options[:iterator] ||= 0
|
||||
params = set_duplicate_params(options)
|
||||
event = @context.calendar_events.build(params[:calendar_event])
|
||||
event.validate_context! if @context.is_a?(AppointmentGroup)
|
||||
event.updating_user = @current_user
|
||||
event
|
||||
end
|
||||
end
|
||||
|
||||
def create_event_and_duplicates(options = {})
|
||||
events = []
|
||||
total_count = options[:count] + 1
|
||||
total_count.times do |i|
|
||||
events << duplicate({iterator: i}.merge!(options))
|
||||
end
|
||||
events
|
||||
end
|
||||
|
||||
def get_duplicate_params(event_data = {})
|
||||
duplicate_data = params[:calendar_event][:duplicate]
|
||||
duplicate_data ||= {}
|
||||
|
||||
{
|
||||
title: event_data[:title],
|
||||
start_at: event_data[:start_at],
|
||||
end_at: event_data[:end_at],
|
||||
count: duplicate_data.fetch(:count, 0).to_i,
|
||||
interval: duplicate_data.fetch(:interval, 1).to_i,
|
||||
add_count: value_to_boolean(duplicate_data[:append_iterator]),
|
||||
frequency: duplicate_data.fetch(:frequency, "weekly")
|
||||
}
|
||||
end
|
||||
|
||||
def set_duplicate_params(options = {})
|
||||
options[:iterator] ||= 0
|
||||
offset_interval = options[:interval] * options[:iterator]
|
||||
offset = if options[:frequency] == "monthly"
|
||||
offset_interval.months
|
||||
elsif options[:frequency] == "daily"
|
||||
offset_interval.days
|
||||
else
|
||||
offset_interval.weeks
|
||||
end
|
||||
|
||||
params[:calendar_event][:title] = "#{options[:title]} #{options[:iterator] + 1}" if options[:add_count]
|
||||
params[:calendar_event][:start_at] = Time.iso8601(options[:start_at]) + offset unless options[:start_at].blank?
|
||||
params[:calendar_event][:end_at] = Time.iso8601(options[:end_at]) + offset unless options[:end_at].blank?
|
||||
params
|
||||
end
|
||||
end
|
|
@ -48,7 +48,8 @@ class CalendarEventsController < ApplicationController
|
|||
@event = @context.calendar_events.scoped.new
|
||||
add_crumb(t('crumbs.new', "New Calendar Event"), named_context_url(@context, :new_context_calendar_event_url))
|
||||
@event.assign_attributes(params.slice(:title, :start_at, :end_at, :location_name, :location_address))
|
||||
js_env(:DIFFERENTIATED_ASSIGNMENTS_ENABLED => @context.feature_enabled?(:differentiated_assignments))
|
||||
js_env(:DIFFERENTIATED_ASSIGNMENTS_ENABLED => @context.feature_enabled?(:differentiated_assignments),
|
||||
:RECURRING_CALENDAR_EVENTS_ENABLED => @context.feature_enabled?(:recurring_calendar_events))
|
||||
authorized_action(@event, @current_user, :create)
|
||||
end
|
||||
|
||||
|
|
|
@ -59,3 +59,47 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.duplicate_div{
|
||||
float: left;
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
line-height: 38px;
|
||||
width: 35px;
|
||||
text-align: right;
|
||||
}
|
||||
.duplicate_td{
|
||||
vertical-align: top;
|
||||
padding-left: 20px;
|
||||
min-width: 300px;
|
||||
}
|
||||
#duplicate_interval{
|
||||
width: 50px;
|
||||
float: left;
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
}
|
||||
.duplicate_for_div{
|
||||
float: left;
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
line-height: 38px;
|
||||
width: 35px;
|
||||
text-align: right;
|
||||
}
|
||||
#duplicate_count{
|
||||
width: 50px;
|
||||
float: left;
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
}
|
||||
.occurences_div{
|
||||
float: left;
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
line-height: 38px;
|
||||
}
|
||||
.duplicate_tooltip_td{
|
||||
vertical-align: top;
|
||||
padding-left: 20px;
|
||||
width: 35px;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
{{#t}}Event Date:{{/t}}
|
||||
{{datepickerScreenreaderPrompt 'date'}}
|
||||
</label>
|
||||
<input id="calendar_event_date" type="text"
|
||||
<input id="calendar_event_date" type="text"
|
||||
name="date" style="width: 100px;" class="date_field"
|
||||
aria-labelledby='calendar_event_date_accessible_label'
|
||||
data-tooltip title="{{accessibleDateFormat 'date'}}"/>
|
||||
|
|
|
@ -105,6 +105,39 @@
|
|||
<input id="calendar_event_location_address" name="location_address" size="30" maxlength="255" type="text" value="{{location_address}}"/>
|
||||
</td>
|
||||
</tr>
|
||||
{{#if recurring_calendar_events}}
|
||||
<tr class="duplicate_event_toggle_row hide">
|
||||
<td style="vertical-align: top;"><label for="duplicate_event">{{#t "repeat"}}Repeat{{/t}}</label> <input type="checkbox" id="duplicate_event" name="duplicate" value="true" style="margin-left: 10px;" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="duplicate_event_row duplicate_fields" style="display: none">
|
||||
<td class="duplicate_td" colspan="2">
|
||||
<label for="duplicate_interval">
|
||||
<div class="duplicate_div">{{#t}}Every{{/t}}</div>
|
||||
<input value="1" disabled="true" id="duplicate_interval" name="duplicate_interval" min="1" />
|
||||
<select id="duplicate_frequency" style="width: 100px;" name="duplicate_frequency">
|
||||
<option value="daily">{{#t}}Day(s){{/t}}</option>
|
||||
<option value="weekly" selected>{{#t}}Week(s){{/t}}</option>
|
||||
<option value="monthly">{{#t}}Month(s){{/t}}</option>
|
||||
</select>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="duplicate_event_row duplicate_fields" style="display: none">
|
||||
<td style="vertical-align: top; padding-left: 20px;" colspan="2">
|
||||
<label for="duplicate_count">
|
||||
<div class="duplicate_for_div" >{{#t}}For{{/t}}</div>
|
||||
<input value="1" disabled="true" type="number" id="duplicate_count" name="duplicate_count" min="1" />
|
||||
<div class="occurences_div">{{#t}}occurrence(s){{/t}}</div>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="duplicate_event_row duplicate_fields" style="display: none">
|
||||
<td class="duplicate_tooltip_td"><label data-tooltip title="{{#t}}Appends a number to the end of each event title (e.g. Event 1, Event 2, etc)" for="append_iterator{{/t}}">{{#t "count"}}Count:{{/t}}</label>
|
||||
<input data-tooltip title="{{#t}}Appends a number to the end of each event title (e.g. Event 1, Event 2, etc){{/t}}" value="true" disabled="true" type="checkbox" id="append_iterator" name="append_iterator" />
|
||||
</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -39,6 +39,7 @@ module Api::V1::CalendarEvent
|
|||
include ||= excludes.include?('child_events') ? [] : ['child_events']
|
||||
|
||||
context = (options[:context] || event.context)
|
||||
duplicates = options[:duplicates] || []
|
||||
participant = nil
|
||||
|
||||
hash = api_json(event, user, session, :only => %w(id created_at updated_at start_at end_at all_day all_day_date title location_address location_name workflow_state))
|
||||
|
@ -135,6 +136,7 @@ module Api::V1::CalendarEvent
|
|||
|
||||
hash['url'] = api_v1_calendar_event_url(event) if options.has_key?(:url_override) ? options[:url_override] || hash['own_reservation'] : event.grants_right?(user, session, :read)
|
||||
hash['html_url'] = calendar_url_for(options[:effective_context] || event.effective_context, :event => event)
|
||||
hash['duplicates'] = duplicates
|
||||
hash
|
||||
end
|
||||
|
||||
|
|
|
@ -200,6 +200,14 @@ END
|
|||
root_opt_in: true,
|
||||
beta: true
|
||||
},
|
||||
'recurring_calendar_events' =>
|
||||
{
|
||||
display_name: -> { I18n.t('Recurring Calendar Events') },
|
||||
description: -> { I18n.t("Allows the scheduling of recurring calendar events") },
|
||||
applies_to: 'Course',
|
||||
state: 'allowed',
|
||||
beta: true
|
||||
},
|
||||
'student_groups_next' =>
|
||||
{
|
||||
display_name: -> { I18n.t('features.student_groups', 'New Student Groups Page') },
|
||||
|
|
|
@ -27,7 +27,7 @@ describe CalendarEventsApiController, type: :request do
|
|||
context 'events' do
|
||||
expected_fields = [
|
||||
'all_day', 'all_day_date', 'child_events', 'child_events_count',
|
||||
'context_code', 'created_at', 'description', 'end_at', 'hidden', 'html_url',
|
||||
'context_code', 'created_at', 'description', 'duplicates', 'end_at', 'hidden', 'html_url',
|
||||
'id', 'location_address', 'location_name', 'parent_event_id', 'start_at',
|
||||
'title', 'updated_at', 'url', 'workflow_state'
|
||||
]
|
||||
|
@ -631,6 +631,40 @@ describe CalendarEventsApiController, type: :request do
|
|||
expect(json['title']).to eql 'ohai'
|
||||
end
|
||||
|
||||
it 'should create recurring events if options have been specified' do
|
||||
start_at = Time.zone.now.utc.change(hour: 0, min: 1) # For pre-Normandy bug with all_day method in calendar_event.rb
|
||||
end_at = Time.zone.now.utc.change(hour: 23)
|
||||
json = api_call(:post, "/api/v1/calendar_events",
|
||||
{:controller => 'calendar_events_api', :action => 'create', :format => 'json'},
|
||||
{:calendar_event => {
|
||||
:context_code => @course.asset_string,
|
||||
:title => "ohai",
|
||||
:start_at => start_at.iso8601,
|
||||
:end_at => end_at.iso8601,
|
||||
:duplicate => {
|
||||
:count => "3",
|
||||
:interval => "1",
|
||||
:frequency => "weekly"
|
||||
}
|
||||
}
|
||||
})
|
||||
assert_status(201)
|
||||
expect(json.keys.sort).to eq expected_fields
|
||||
expect(json['title']).to eq 'ohai'
|
||||
|
||||
duplicates = json['duplicates']
|
||||
expect(duplicates.count).to eq 3
|
||||
|
||||
duplicates.to_a.each_with_index do |duplicate, i|
|
||||
start_result = Time.iso8601(duplicate['calendar_event']['start_at'])
|
||||
end_result = Time.iso8601(duplicate['calendar_event']['end_at'])
|
||||
expect(duplicate['calendar_event']['title']).to eql 'ohai'
|
||||
expect(start_result).to eq(start_at + (i + 1).weeks)
|
||||
expect(end_result).to eq(end_at + (i + 1).weeks)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
it 'should process html content in description on create' do
|
||||
should_process_incoming_user_content(@course) do |content|
|
||||
json = api_call(:post, "/api/v1/calendar_events",
|
||||
|
|
|
@ -127,7 +127,7 @@ def create_assignment_event(assignment_title, should_add_date = false, publish =
|
|||
end
|
||||
|
||||
# Creates event from clicking on the mini calendar
|
||||
def create_calendar_event(event_title, should_add_date = false, should_add_location = false)
|
||||
def create_calendar_event(event_title, should_add_date = false, should_add_location = false, should_duplicate = false)
|
||||
middle_number = find_middle_day.find_element(:css, '.fc-day-number').text
|
||||
find_middle_day.click
|
||||
edit_event_dialog = f('#edit_event_tabs')
|
||||
|
@ -138,9 +138,29 @@ def create_calendar_event(event_title, should_add_date = false, should_add_locat
|
|||
replace_content(title, event_title)
|
||||
add_date(middle_number) if should_add_date
|
||||
replace_content(f('#calendar_event_location_name'), 'location title') if should_add_location
|
||||
|
||||
if should_duplicate
|
||||
f('#duplicate_event').click
|
||||
duplicate_options = edit_event_form.find_element(:id, 'duplicate_interval')
|
||||
keep_trying_until { duplicate_options.displayed? }
|
||||
duplicate_interval = edit_event_form.find_element(:id, 'duplicate_interval')
|
||||
duplicate_count = edit_event_form.find_element(:id, 'duplicate_count')
|
||||
replace_content(duplicate_interval, "1")
|
||||
replace_content(duplicate_count, "3")
|
||||
f('#append_iterator').click
|
||||
end
|
||||
|
||||
submit_form(edit_event_form)
|
||||
wait_for_ajax_requests
|
||||
keep_trying_until { expect(f('.fc-view-month .fc-event-title')).to include_text(event_title) }
|
||||
keep_trying_until do
|
||||
if should_duplicate
|
||||
4.times do |i|
|
||||
expect(ff('.fc-view-month .fc-event-title')[i]).to include_text("#{event_title} #{i + 1}")
|
||||
end
|
||||
else
|
||||
expect(f('.fc-view-month .fc-event-title')).to include_text(event_title)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -163,9 +183,9 @@ def get_header_text
|
|||
header.text
|
||||
end
|
||||
|
||||
def create_middle_day_event(name = 'new event', with_date = false, with_location = false)
|
||||
def create_middle_day_event(name = 'new event', with_date = false, with_location = false, with_duplicates = false)
|
||||
get "/calendar2"
|
||||
create_calendar_event(name, with_date, with_location)
|
||||
create_calendar_event(name, with_date, with_location, with_duplicates)
|
||||
end
|
||||
|
||||
def create_middle_day_assignment(name = 'new assignment')
|
||||
|
|
Loading…
Reference in New Issue