canvas-lms/lib/sticky_sis_fields.rb

149 lines
5.2 KiB
Ruby
Raw Normal View History

#
# Copyright (C) 2011 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require 'skip_callback'
module StickySisFields
module InstanceMethods
# this method is set as a before_update callback
def set_sis_stickiness
self.class.sis_stickiness_options ||= {}
currently_stuck_sis_fields = if self.class.sis_stickiness_options[:clear_sis_stickiness]
[].to_set
else
calculate_currently_stuck_sis_fields
end
if load_stuck_sis_fields_cache != currently_stuck_sis_fields
write_attribute(:stuck_sis_fields, currently_stuck_sis_fields.map(&:to_s).sort.join(','))
end
@stuck_sis_fields_cache = currently_stuck_sis_fields
@sis_fields_to_stick = [].to_set
@sis_fields_to_unstick = [].to_set
end
# this method is what you want to use to determine which fields are currently stuck
def stuck_sis_fields
self.class.sis_stickiness_options ||= {}
if self.class.sis_stickiness_options[:override_sis_stickiness]
return [].to_set
else
return calculate_currently_stuck_sis_fields
end
end
def stuck_sis_fields=(fields)
[#5773] Ruby 1.9.3 spec fixes [#5773] correctly evaluate the custom_fields_string My impression is that order is not enforced in the hash being used to build the fields string, as this was failing in 1.8.7 for me (but not in 1.9.3), because the string being checked was "b=456\na=123" while the string being returned from the custom_fields_string method was "a=123\nb=456". Testing with a regex instead confirms the content is there without relying on any particular order. [EDIT: Per Brian P, decided to sort the params instead to enforce order] [#5773] fix admin_settings_tab_spec for ruby 1.9.3 String's "each" method was being used, which is gone in 1.9. Fixed by performing a guard clause in the check_box_verifier in the spec file to conditionally take a string argument and convert it to an array. Also converted the rest of the method to assume an array value for that argument. [#5773] fix collaborations selenium spec for 1.9.3 This is an instance of using the "each" method of the string class which is no longer present in 1.9 in one of the helper methods in this spec. Erected a guard clause to check for Array-ness and to replace the argument with an array if necessary. [#5773] fix courses show view There was a spot in this view where it was interpolating "self.id" into an html attribute rather than "@instance_model.id". This sort of worked in ruby 1.8, where it would interpolate the object id of the view instance. In 1.9, that id becomes "object_id", which is what one would have to change the code to in order to preserve the current behavior. However, it seems more correct to simply pull the correct id of the contextual model object instead (which is what I did). [#5773] fix teacher_wiki_and_tiny_images spec This is an instance of using a string as an enumerable; adding a guard clause to lib/sticky_sis_fields.rb to transform the string argument into an array fixes it [#5773] fix selenium/student_submissions_spec.rb This is an issue with SSLCommon's use of net/https. In older ruby versions there are 2 parameters returned (the response, and the body). Now only the response is returned, so the response object has to be asked for the body explicitly. This fix was made in spec/selenium/helpers/files_common.rb Change-Id: I66a25ebbc1d8e5af7b7117375210172d287a77c7 Reviewed-on: https://gerrit.instructure.com/14641 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Brian Palmer <brianp@instructure.com>
2012-10-24 05:08:56 +08:00
fields = [fields] if (fields.is_a? String)
clear_sis_stickiness(*(stuck_sis_fields.to_a))
add_sis_stickiness(*(fields.map(&:to_sym).to_set))
end
# clear stickiness on a set of fields
def clear_sis_stickiness(*fields)
@sis_fields_to_stick ||= [].to_set
@sis_fields_to_unstick ||= [].to_set
fields.map(&:to_sym).each do |field|
@sis_fields_to_stick.delete field
@sis_fields_to_unstick.add field
end
end
# make some fields sticky
def add_sis_stickiness(*fields)
@sis_fields_to_stick ||= [].to_set
@sis_fields_to_unstick ||= [].to_set
fields.map(&:to_sym).each do |field|
@sis_fields_to_stick.add field
@sis_fields_to_unstick.delete field
end
end
private
def load_stuck_sis_fields_cache
@stuck_sis_fields_cache ||= (read_attribute(:stuck_sis_fields) || '').split(',').map(&:to_sym).to_set
end
def calculate_currently_stuck_sis_fields
@sis_fields_to_stick ||= [].to_set
@sis_fields_to_unstick ||= [].to_set
changed_sis_fields = self.class.sticky_sis_fields & (self.changed.map(&:to_sym).to_set | @sis_fields_to_stick)
return (load_stuck_sis_fields_cache | changed_sis_fields) - @sis_fields_to_unstick
end
def reload_with_sis_stickiness(*a)
@stuck_sis_fields_cache = @sis_fields_to_stick = @sis_fields_to_unstick = nil
reload_without_sis_stickiness(*a)
end
end
module ClassMethods
# specify which fields are able to be stuck
def are_sis_sticky(*fields)
self.sticky_sis_fields = fields.map(&:to_sym).to_set
end
# takes a block and runs it with the following options:
# override_sis_stickiness: default false,
# if true, all code inside the block will be run as if the class
# mixing in this module has no stuck sis fields
# add_sis_stickiness: default false,
# unless add_sis_stickiness (or clear_sis_stickiness) is true, the
# set_sis_stickiness callback is skipped, so no sis stickiness is
# modified. if true, the set_sis_stickiness is enabled like normal,
# such that everything is processed like non-sis. it doesn't really
# make tons of sense to use this feature without
# override_sis_stickiness.
# clear_sis_stickiness: default false,
# if true, the set_sis_stickiness callback is enabled and configured
# to write out an empty stickiness list on every save.
def process_as_sis(opts={})
self.sis_stickiness_options ||= {}
old_options = self.sis_stickiness_options.clone
[:override_sis_stickiness, :clear_sis_stickiness].each do |option|
self.sis_stickiness_options[option] = opts[option]
end
begin
if opts[:add_sis_stickiness] || opts[:clear_sis_stickiness]
yield
else
self.skip_callback(:set_sis_stickiness) do
yield
end
end
ensure
self.sis_stickiness_options = old_options
end
end
end
def self.included(klass)
if klass < ActiveRecord::Base
klass.send :extend, ClassMethods
klass.send :include, InstanceMethods
klass.cattr_accessor :sticky_sis_fields
klass.cattr_accessor :sis_stickiness_options
klass.before_update :set_sis_stickiness
klass.alias_method_chain :reload, :sis_stickiness
end
end
end