canvas-lms/app/models/context.rb

376 lines
13 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
2011-02-01 09:57:29 +08:00
#
# Copyright (C) 2011 - present Instructure, Inc.
2011-02-01 09:57:29 +08:00
#
# 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/>.
#
# These methods are mixed into the classes that can be considered a "context".
# See Context::CONTEXT_TYPES below.
2011-02-01 09:57:29 +08:00
module Context
CONTEXT_TYPES = [:Account, :Course, :CourseSection, :User, :Group].freeze
ASSET_TYPES = {
Announcement: :Announcement,
AssessmentQuestion: :AssessmentQuestion,
AssessmentQuestionBank: :AssessmentQuestionBank,
Assignment: :Assignment,
AssignmentGroup: :AssignmentGroup,
Attachment: :Attachment,
CalendarEvent: :CalendarEvent,
Collaboration: :Collaboration,
ContentTag: :ContentTag,
ContextExternalTool: :ContextExternalTool,
ContextModule: :ContextModule,
DiscussionEntry: :DiscussionEntry,
DiscussionTopic: :DiscussionTopic,
Folder: :Folder,
LearningOutcome: :LearningOutcome,
LearningOutcomeGroup: :LearningOutcomeGroup,
MediaObject: :MediaObject,
Progress: :Progress,
Quiz: :"Quizzes::Quiz",
QuizGroup: :"Quizzes::QuizGroup",
QuizQuestion: :"Quizzes::QuizQuestion",
QuizSubmission: :"Quizzes::QuizSubmission",
Rubric: :Rubric,
RubricAssociation: :RubricAssociation,
Submission: :Submission,
WebConference: :WebConference,
Wiki: :Wiki,
WikiPage: :WikiPage,
Eportfolio: :Eportfolio
}.freeze
2011-02-01 09:57:29 +08:00
def clear_cached_short_name
self.class.connection.after_transaction_commit do
Rails.cache.delete(['short_name_lookup', self.asset_string].cache_key)
end
end
2011-02-01 09:57:29 +08:00
def add_aggregate_entries(entries, feed)
entries.each do |entry|
user = entry.user || feed.user
# If already existed and has been updated
if entry.entry_changed? && entry.asset
entry.asset.update(
:title => entry.title,
:message => entry.message
)
elsif !entry.asset
announcement = self.announcements.build(
:title => entry.title,
:message => entry.message
)
announcement.external_feed_id = feed.id
announcement.user = user
announcement.save
entry.update(:asset => announcement)
2011-02-01 09:57:29 +08:00
end
end
end
def self.sorted_rubrics(user, context)
add soft-deletion to rubric associations closes EVAL-812 flag=none Test Plan 1: Deleting and Restoring a Rubric Association 1. Create a rubric in a course and attach it to an assignment. 2. In SpeedGrader, use the rubric to assess a couple students. 3. On the assignment show page, click the trash can icon on the rubric to delete the rubric association with the assignment (it says "Delete Rubric" but it's really just deleting the Rubric Association). 4. Go back to SpeedGrader and verify the rubric does not show up for the students that you assessed (the final grade should still be awarded, if you awarded one separate from the rubric). 5. Verify the rubric itself still exists at /courses/:id/rubrics 6. Go to /courses/:id/undelete and verify the RubricAssociation that was deleted is listed there. Click 'restore'. 7. Go back to the assignment show page and note that the rubric is now showing again. 8. Go back to SpeedGrader and note that the rubric assessments have returned. Hallelujah! Test Plan 2: Deleting and Restoring a Rubric 1. Create a rubric in a course and attach it to an assignment. 2. In SpeedGrader, use the rubric to assess a couple students. 3. Go to /courses/:id/rubrics, click on the rubric, and then click 'Delete Rubric'. 4. Go to the assignment show page and verify the rubric does not show as attached to the assignment any more. 5. Go back to SpeedGrader and verify the rubric does not show up for the students that you assessed (the final grade should still be awarded, if you awarded one separate from the rubric). 6. Go to /courses/:id/undelete and verify the Rubric that was deleted is listed there. Click 'restore'. You can also verify that the RubricAssociation for the assignment is listed on the page as well, though you don't need to click 'Restore' for that item. 7. Go back to the assignment show page and note that the rubric is now showing again. 8. Go back to SpeedGrader and note that the rubric assessments have returned. Hallelujah! * Edge case testing: test account rubrics, and using rubrics that were created in other courses. Change-Id: I02745619457f99f760bd9459ab9d85d23bba57bc Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/253739 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Kai Bjorkman <kbjorkman@instructure.com> Product-Review: Syed Hussain <shussain@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> Reviewed-by: Gary Mei <gmei@instructure.com>
2020-11-25 02:46:25 +08:00
associations = RubricAssociation.active.bookmarked.for_context_codes(context.asset_string).preload(:rubric => :context)
Canvas::ICU.collate_by(associations.to_a.uniq(&:rubric_id).select{|r| r.rubric }) { |r| r.rubric.title || CanvasSort::Last }
2011-02-01 09:57:29 +08:00
end
2011-02-01 09:57:29 +08:00
def rubric_contexts(user)
associations = []
course_ids = [self.id]
course_ids = (course_ids + user.participating_instructor_course_with_concluded_ids.map{|id| Shard.relative_id_for(id, user.shard, Shard.current)}).uniq if user
Shard.partition_by_shard(course_ids) do |sharded_course_ids|
context_codes = sharded_course_ids.map{|id| "course_#{id}"}
if Shard.current == self.shard
context = self
while context && context.respond_to?(:account) || context.respond_to?(:parent_account)
context = context.respond_to?(:account) ? context.account : context.parent_account
context_codes << context.asset_string if context
end
end
add soft-deletion to rubric associations closes EVAL-812 flag=none Test Plan 1: Deleting and Restoring a Rubric Association 1. Create a rubric in a course and attach it to an assignment. 2. In SpeedGrader, use the rubric to assess a couple students. 3. On the assignment show page, click the trash can icon on the rubric to delete the rubric association with the assignment (it says "Delete Rubric" but it's really just deleting the Rubric Association). 4. Go back to SpeedGrader and verify the rubric does not show up for the students that you assessed (the final grade should still be awarded, if you awarded one separate from the rubric). 5. Verify the rubric itself still exists at /courses/:id/rubrics 6. Go to /courses/:id/undelete and verify the RubricAssociation that was deleted is listed there. Click 'restore'. 7. Go back to the assignment show page and note that the rubric is now showing again. 8. Go back to SpeedGrader and note that the rubric assessments have returned. Hallelujah! Test Plan 2: Deleting and Restoring a Rubric 1. Create a rubric in a course and attach it to an assignment. 2. In SpeedGrader, use the rubric to assess a couple students. 3. Go to /courses/:id/rubrics, click on the rubric, and then click 'Delete Rubric'. 4. Go to the assignment show page and verify the rubric does not show as attached to the assignment any more. 5. Go back to SpeedGrader and verify the rubric does not show up for the students that you assessed (the final grade should still be awarded, if you awarded one separate from the rubric). 6. Go to /courses/:id/undelete and verify the Rubric that was deleted is listed there. Click 'restore'. You can also verify that the RubricAssociation for the assignment is listed on the page as well, though you don't need to click 'Restore' for that item. 7. Go back to the assignment show page and note that the rubric is now showing again. 8. Go back to SpeedGrader and note that the rubric assessments have returned. Hallelujah! * Edge case testing: test account rubrics, and using rubrics that were created in other courses. Change-Id: I02745619457f99f760bd9459ab9d85d23bba57bc Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/253739 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Kai Bjorkman <kbjorkman@instructure.com> Product-Review: Syed Hussain <shussain@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> Reviewed-by: Gary Mei <gmei@instructure.com>
2020-11-25 02:46:25 +08:00
associations += RubricAssociation.active.bookmarked.for_context_codes(context_codes).include_rubric.preload(:context).to_a
2011-02-01 09:57:29 +08:00
end
associations = associations.select(&:rubric).uniq{|a| [a.rubric_id, a.context.asset_string] }
contexts = associations.group_by{|a| a.context.asset_string}.map do |code, code_associations|
{
:rubrics => code_associations.length,
2011-02-01 09:57:29 +08:00
:context_code => code,
:name => code_associations.first.context_name
2011-02-01 09:57:29 +08:00
}
end
Canvas::ICU.collate_by(contexts) { |r| r[:name] }
2011-02-01 09:57:29 +08:00
end
restore "speed up dashcards by only loading tabs shown" & fix bug Fixes: CORE-1964 This reverts commit 72d558f09554f4e45130c4a508311a1bc0d007f3 this restores the commit (aka, reverts that ^ revert) that was causing us bugs on caturday. the root cause of the bug was that ["active_record_types", [], self].cache_key and ["active_record_types", nil, self].cache_key return the same string. how to replay the buggy scenerio: (as a student, in a course with annnouncements): * right after having "touched" the course (so there's nothing cached), * have one person go to /courses/:course_id/assignments/syllabus * in the controller action for that, it will do: `return unless tab_enabled?(@context.class::TAB_SYLLABUS)` that will call Course::uncached_tabs_available(only_check: @context.class::TAB_SYLLABUS) which would have called @course.active_record_types(only_check: []) (because @context.class::TAB_SYLLABUS is not one of the `tabs_that_can_be_marked_hidden_unused`) which woud have written `{}` to redis at ['active_record_types', [], self].cache_key * now, as a different student, go to /courses/:course_id/annnouncements it will call `tab_enabled?(@context.class::TAB_ANNOUNCEMENTS)` that will call Course::uncached_tabs_available(only_check: @context.class::TAB_ANNOUNCEMENTS) which will call @course.active_record_types(only_check: [:announcements]) it will do a cache read for ['active_record_types', [:announcements], self].cache_key since it it a fresh cach, that will not be found then it would have done a cache read for the "everything" cache at ['active_record_types', nil, self].cache_key THAT WOULD HAVE RETURNED THE CACHED `{}` SINCE `nil.cache_key` and `[].cache_key` ARE THE SAME! * the user would be told the announcement page is not enabled for that course the fix is to explicitly not allow Context::active_record_types to ever be called with `only_check: []` and for good measure, we don't allow the implicit conversion of nil.cache_key to "" and instead use "everything" for the cache cache_key I added specs to spefically catch this bug so that it doesn't happen again. To see the difference, compare the latest patchset of this commit against patchset 1. patchset 1 is the original version of this code without this fix. Change-Id: I513104b90dd94227a04c151ee02a22f4a4ac2832 Reviewed-on: https://gerrit.instructure.com/167400 Tested-by: Jenkins Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com>
2018-10-08 23:36:54 +08:00
def active_record_types(only_check: nil)
only_check = only_check.sort if only_check.present? # so that we always have consistent cache keys
@active_record_types ||= {}
return @active_record_types[only_check] if @active_record_types[only_check]
possible_types = {
files: -> { self.respond_to?(:attachments) && self.attachments.active.exists? },
modules: -> { self.respond_to?(:context_modules) && self.context_modules.active.exists? },
quizzes: -> { (self.respond_to?(:quizzes) && self.quizzes.active.exists?) ||
(self.respond_to?(:assignments) && self.assignments.active.quiz_lti.exists?) },
restore "speed up dashcards by only loading tabs shown" & fix bug Fixes: CORE-1964 This reverts commit 72d558f09554f4e45130c4a508311a1bc0d007f3 this restores the commit (aka, reverts that ^ revert) that was causing us bugs on caturday. the root cause of the bug was that ["active_record_types", [], self].cache_key and ["active_record_types", nil, self].cache_key return the same string. how to replay the buggy scenerio: (as a student, in a course with annnouncements): * right after having "touched" the course (so there's nothing cached), * have one person go to /courses/:course_id/assignments/syllabus * in the controller action for that, it will do: `return unless tab_enabled?(@context.class::TAB_SYLLABUS)` that will call Course::uncached_tabs_available(only_check: @context.class::TAB_SYLLABUS) which would have called @course.active_record_types(only_check: []) (because @context.class::TAB_SYLLABUS is not one of the `tabs_that_can_be_marked_hidden_unused`) which woud have written `{}` to redis at ['active_record_types', [], self].cache_key * now, as a different student, go to /courses/:course_id/annnouncements it will call `tab_enabled?(@context.class::TAB_ANNOUNCEMENTS)` that will call Course::uncached_tabs_available(only_check: @context.class::TAB_ANNOUNCEMENTS) which will call @course.active_record_types(only_check: [:announcements]) it will do a cache read for ['active_record_types', [:announcements], self].cache_key since it it a fresh cach, that will not be found then it would have done a cache read for the "everything" cache at ['active_record_types', nil, self].cache_key THAT WOULD HAVE RETURNED THE CACHED `{}` SINCE `nil.cache_key` and `[].cache_key` ARE THE SAME! * the user would be told the announcement page is not enabled for that course the fix is to explicitly not allow Context::active_record_types to ever be called with `only_check: []` and for good measure, we don't allow the implicit conversion of nil.cache_key to "" and instead use "everything" for the cache cache_key I added specs to spefically catch this bug so that it doesn't happen again. To see the difference, compare the latest patchset of this commit against patchset 1. patchset 1 is the original version of this code without this fix. Change-Id: I513104b90dd94227a04c151ee02a22f4a4ac2832 Reviewed-on: https://gerrit.instructure.com/167400 Tested-by: Jenkins Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com>
2018-10-08 23:36:54 +08:00
assignments: -> { self.respond_to?(:assignments) && self.assignments.active.exists? },
pages: -> { self.respond_to?(:wiki_pages) && self.wiki_pages.active.exists? },
conferences: -> { self.respond_to?(:web_conferences) && self.web_conferences.active.exists? },
announcements: -> { self.respond_to?(:announcements) && self.announcements.active.exists? },
outcomes: -> { self.respond_to?(:has_outcomes?) && self.has_outcomes? },
discussions: -> { self.respond_to?(:discussion_topics) && self.discussion_topics.only_discussion_topics.except(:preload).exists? }
}
types_to_check = if only_check
possible_types.select { |k| only_check.include?(k) }
else
possible_types
end
raise ArgumentError, "only_check is either an empty array or you are aking for invalid types" if types_to_check.empty?
base_cache_key = 'active_record_types3'
cache_key = [base_cache_key, (only_check.present? ? only_check : 'everything'), self].cache_key
# if it exists in redis, return that
if (cached = Rails.cache.read(cache_key))
return @active_record_types[only_check] = cached
end
# if we're only asking for a subset but the full set is cached return that, but filtered with just what we want
if only_check.present? && (cache_with_everything = Rails.cache.read([base_cache_key, 'everything', self].cache_key))
return @active_record_types[only_check] = cache_with_everything.select { |k,_v| only_check.include?(k) }
end
# otherwise compute it and store it in the cache
value_to_cache = nil
ActiveRecord::Base.uncached do
value_to_cache = types_to_check.each_with_object({}) do |(key, type_to_check), memo|
memo[key] = type_to_check.call
end
2011-02-01 09:57:29 +08:00
end
restore "speed up dashcards by only loading tabs shown" & fix bug Fixes: CORE-1964 This reverts commit 72d558f09554f4e45130c4a508311a1bc0d007f3 this restores the commit (aka, reverts that ^ revert) that was causing us bugs on caturday. the root cause of the bug was that ["active_record_types", [], self].cache_key and ["active_record_types", nil, self].cache_key return the same string. how to replay the buggy scenerio: (as a student, in a course with annnouncements): * right after having "touched" the course (so there's nothing cached), * have one person go to /courses/:course_id/assignments/syllabus * in the controller action for that, it will do: `return unless tab_enabled?(@context.class::TAB_SYLLABUS)` that will call Course::uncached_tabs_available(only_check: @context.class::TAB_SYLLABUS) which would have called @course.active_record_types(only_check: []) (because @context.class::TAB_SYLLABUS is not one of the `tabs_that_can_be_marked_hidden_unused`) which woud have written `{}` to redis at ['active_record_types', [], self].cache_key * now, as a different student, go to /courses/:course_id/annnouncements it will call `tab_enabled?(@context.class::TAB_ANNOUNCEMENTS)` that will call Course::uncached_tabs_available(only_check: @context.class::TAB_ANNOUNCEMENTS) which will call @course.active_record_types(only_check: [:announcements]) it will do a cache read for ['active_record_types', [:announcements], self].cache_key since it it a fresh cach, that will not be found then it would have done a cache read for the "everything" cache at ['active_record_types', nil, self].cache_key THAT WOULD HAVE RETURNED THE CACHED `{}` SINCE `nil.cache_key` and `[].cache_key` ARE THE SAME! * the user would be told the announcement page is not enabled for that course the fix is to explicitly not allow Context::active_record_types to ever be called with `only_check: []` and for good measure, we don't allow the implicit conversion of nil.cache_key to "" and instead use "everything" for the cache cache_key I added specs to spefically catch this bug so that it doesn't happen again. To see the difference, compare the latest patchset of this commit against patchset 1. patchset 1 is the original version of this code without this fix. Change-Id: I513104b90dd94227a04c151ee02a22f4a4ac2832 Reviewed-on: https://gerrit.instructure.com/167400 Tested-by: Jenkins Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com>
2018-10-08 23:36:54 +08:00
Rails.cache.write(cache_key, value_to_cache)
@active_record_types[only_check] = value_to_cache
2011-02-01 09:57:29 +08:00
end
2011-02-01 09:57:29 +08:00
def allow_wiki_comments
false
end
def find_asset(asset_string, allowed_types=nil)
return nil unless asset_string
res = Context.find_asset_by_asset_string(asset_string, self, allowed_types)
res = nil if res.respond_to?(:deleted?) && res.deleted?
res
end
# [[context_type, context_id], ...] -> {[context_type, context_id] => name, ...}
def self.names_by_context_types_and_ids(context_types_and_ids)
ids_by_type = Hash.new([])
context_types_and_ids.each do |type, id|
next unless type && CONTEXT_TYPES.include?(type.to_sym)
ids_by_type[type] += [id]
end
result = {}
ids_by_type.each do |type, ids|
klass = Object.const_get(type, false)
klass.where(:id => ids).pluck(:id, :name).map {|id, name| result[[type, id]] = name}
end
result
end
def self.context_code_for(record)
raise ArgumentError unless record.respond_to?(:context_type) && record.respond_to?(:context_id)
"#{record.context_type.underscore}_#{record.context_id}"
end
def self.find_by_asset_string(string)
from_context_codes([string]).first
2011-02-01 09:57:29 +08:00
end
def self.from_context_codes(context_codes)
contexts = {}
context_codes.each do |cc|
type, _, id = cc.rpartition('_')
if CONTEXT_TYPES.include?(type.camelize.to_sym)
contexts[type.camelize] = [] unless contexts[type.camelize]
contexts[type.camelize] << id
end
end
contexts.reduce([]) do |memo, (context, ids)|
memo + context.constantize.where(id: ids)
end
end
def self.asset_type_for_string(string)
ASSET_TYPES[string.to_sym].to_s.constantize if ASSET_TYPES.key?(string.to_sym)
end
2011-02-01 09:57:29 +08:00
def self.find_asset_by_asset_string(string, context=nil, allowed_types=nil)
opts = string.split("_")
id = opts.pop
type = opts.join('_').classify
klass = asset_type_for_string(type)
2011-02-01 09:57:29 +08:00
klass = nil if allowed_types && !allowed_types.include?(klass.to_s.underscore.to_sym)
return nil unless klass
res = nil
if context && klass == ContextExternalTool
res = klass.find_external_tool_by_id(id, context)
elsif context && (klass.column_names & ['context_id', 'context_type']).length == 2
res = klass.where(context_id: context, context_type: context.class.to_s, id: id).first
else
res = klass.where(id: id).first
2011-02-01 09:57:29 +08:00
res = nil if context && res && res.respond_to?(:context) && res.context != context
end
res
rescue => e
nil
end
def self.get_front_wiki_page_for_course_from_url(url)
params = Rails.application.routes.recognize_path(url)
if params[:controller] == "courses" && params[:action] == "show"
course = Course.find(params[:id])
if course.default_view == "wiki"
course.wiki.front_page
end
end
rescue
nil
end
def self.find_asset_by_url(url)
object = nil
params = Rails.application.routes.recognize_path(url)
course = Course.find(params[:course_id]) if params[:course_id]
group = Group.find(params[:group_id]) if params[:group_id]
user = User.find(params[:user_id]) if params[:user_id]
context = course || group || user
media_obj = MediaObject.where(:media_id => params[:media_object_id]).first if params[:media_object_id]
context = media_obj.context if media_obj
return nil unless context
case params[:controller]
when 'files'
rel_path = params[:file_path]
object = rel_path && Folder.find_attachment_in_context_with_path(course, CGI.unescape(rel_path))
file_id = params[:file_id] || params[:id]
query = URI.parse(url)&.query
file_id ||= query && CGI.parse(URI.parse(url)&.query)&.send(:[], "preview")&.first
object ||= context.attachments.find_by_id(file_id) # attachments.find_by_id uses the replacement hackery
when 'wiki_pages'
object = context.wiki.find_page(CGI.unescape(params[:id]), include_deleted: true)
if !object && params[:id].to_s.include?("+") # maybe it really is a "+"
object = context.wiki.find_page(CGI.unescape(params[:id].to_s.gsub("+", "%2B")), include_deleted: true)
end
when 'external_tools'
if params[:action] == "retrieve"
tool_url = CGI.parse(URI.parse(url).query)["url"].first rescue nil
object = ContextExternalTool.find_external_tool(tool_url, context) if tool_url
elsif params[:id]
object = ContextExternalTool.find_external_tool_by_id(params[:id], context)
end
when 'context_modules'
if %w(item_redirect item_redirect_mastery_paths choose_mastery_path).include?(params[:action])
object = context.context_module_tags.find_by(id: params[:id])
else
object = context.context_modules.find_by(id: params[:id])
end
when 'media_objects'
object = media_obj
else
object = context.try(params[:controller].sub(/^.+\//, ''))&.find_by(id: params[:id])
end
object
rescue => e
nil
end
def self.asset_name(asset)
name = asset.display_name.presence if asset.respond_to?(:display_name)
name ||= asset.title.presence if asset.respond_to?(:title)
name ||= asset.short_description.presence if asset.respond_to?(:short_description)
name ||= asset.name if asset.respond_to?(:name)
name || ''
end
def self.asset_body(asset)
asset.try(:body) || asset.try(:message) || asset.try(:description)
end
get sub account branding and custom css/includes working fixes: CNVS-24787 fixes: CNVS-23964 fixes: CNVS-23957 - Handle parent account custom css/js for new_styles test plan: * set up a root account, child account, and grandchild account * use theme editor to set a custom css/js file for each (eg: for css `* {color:red}` and for js 'console.log("from grandchild")` * make a course & a group in the grandchild account * load a page in that course and group and make sure you see grandchild account's branding, and root's, child's, and then grandchild's css loaded on the page (grandchild should be loaded last so you see it's css effects override root or child's and you should see the console.log from root then child then grandchild) * view a page in "child". it should have root and child's css/js but not grandchild * as a user that only has enrollments (account associations) in "child", go to the dashboard. you should see css/js for both root and child but not grandchild fixes: CNVS-25051 Opening Theme Editor for sub-accounts shows incorrect theme preview test plan: * Go to a sub-account in theme editor and change settings so the Branding is different and save. * the preview on the right should reflect your changes both after you "apply" and "save" (and not just show the preview of the root account's branding) fixes: CNVS-23406 - global JS and CSS files are being included when Global CSS/JavaScript includes is false test plan: * go to /accounts/self/, and go to theme editor and upload a css_override * see that that css is loaded on pages * back in root account settings disable Global CSS/JavaScript includes * check that the css is no longer loaded. * do the same thing checking a subaccount's custom css fixes: CNVS-25558 - load whole chain of custom css/js in native app api requests test plan: * make api request for a wiki page in course in a subaccount that has custom css/js within a root account that also has custom css/js * you should see both the root account's css/js and the child account's returned in the response to test grandchild js issue jeremyp found: * go to theme editor for a grandchild account * choose a js override file (like: `console.log('first')`) * preview & apply * you should see "first" in console * go back to theme editor, pick a new file (like: `console.log('second')`) * preview & apply * you should only see "second" in console. not "first" Change-Id: I8d9047948f5da94be41e0205844629a170f980af Reviewed-on: https://gerrit.instructure.com/68249 Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com>
2015-12-05 00:57:07 +08:00
def self.get_account(context)
case context
when Account
get sub account branding and custom css/includes working fixes: CNVS-24787 fixes: CNVS-23964 fixes: CNVS-23957 - Handle parent account custom css/js for new_styles test plan: * set up a root account, child account, and grandchild account * use theme editor to set a custom css/js file for each (eg: for css `* {color:red}` and for js 'console.log("from grandchild")` * make a course & a group in the grandchild account * load a page in that course and group and make sure you see grandchild account's branding, and root's, child's, and then grandchild's css loaded on the page (grandchild should be loaded last so you see it's css effects override root or child's and you should see the console.log from root then child then grandchild) * view a page in "child". it should have root and child's css/js but not grandchild * as a user that only has enrollments (account associations) in "child", go to the dashboard. you should see css/js for both root and child but not grandchild fixes: CNVS-25051 Opening Theme Editor for sub-accounts shows incorrect theme preview test plan: * Go to a sub-account in theme editor and change settings so the Branding is different and save. * the preview on the right should reflect your changes both after you "apply" and "save" (and not just show the preview of the root account's branding) fixes: CNVS-23406 - global JS and CSS files are being included when Global CSS/JavaScript includes is false test plan: * go to /accounts/self/, and go to theme editor and upload a css_override * see that that css is loaded on pages * back in root account settings disable Global CSS/JavaScript includes * check that the css is no longer loaded. * do the same thing checking a subaccount's custom css fixes: CNVS-25558 - load whole chain of custom css/js in native app api requests test plan: * make api request for a wiki page in course in a subaccount that has custom css/js within a root account that also has custom css/js * you should see both the root account's css/js and the child account's returned in the response to test grandchild js issue jeremyp found: * go to theme editor for a grandchild account * choose a js override file (like: `console.log('first')`) * preview & apply * you should see "first" in console * go back to theme editor, pick a new file (like: `console.log('second')`) * preview & apply * you should only see "second" in console. not "first" Change-Id: I8d9047948f5da94be41e0205844629a170f980af Reviewed-on: https://gerrit.instructure.com/68249 Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com>
2015-12-05 00:57:07 +08:00
context
when Course
get sub account branding and custom css/includes working fixes: CNVS-24787 fixes: CNVS-23964 fixes: CNVS-23957 - Handle parent account custom css/js for new_styles test plan: * set up a root account, child account, and grandchild account * use theme editor to set a custom css/js file for each (eg: for css `* {color:red}` and for js 'console.log("from grandchild")` * make a course & a group in the grandchild account * load a page in that course and group and make sure you see grandchild account's branding, and root's, child's, and then grandchild's css loaded on the page (grandchild should be loaded last so you see it's css effects override root or child's and you should see the console.log from root then child then grandchild) * view a page in "child". it should have root and child's css/js but not grandchild * as a user that only has enrollments (account associations) in "child", go to the dashboard. you should see css/js for both root and child but not grandchild fixes: CNVS-25051 Opening Theme Editor for sub-accounts shows incorrect theme preview test plan: * Go to a sub-account in theme editor and change settings so the Branding is different and save. * the preview on the right should reflect your changes both after you "apply" and "save" (and not just show the preview of the root account's branding) fixes: CNVS-23406 - global JS and CSS files are being included when Global CSS/JavaScript includes is false test plan: * go to /accounts/self/, and go to theme editor and upload a css_override * see that that css is loaded on pages * back in root account settings disable Global CSS/JavaScript includes * check that the css is no longer loaded. * do the same thing checking a subaccount's custom css fixes: CNVS-25558 - load whole chain of custom css/js in native app api requests test plan: * make api request for a wiki page in course in a subaccount that has custom css/js within a root account that also has custom css/js * you should see both the root account's css/js and the child account's returned in the response to test grandchild js issue jeremyp found: * go to theme editor for a grandchild account * choose a js override file (like: `console.log('first')`) * preview & apply * you should see "first" in console * go back to theme editor, pick a new file (like: `console.log('second')`) * preview & apply * you should only see "second" in console. not "first" Change-Id: I8d9047948f5da94be41e0205844629a170f980af Reviewed-on: https://gerrit.instructure.com/68249 Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com>
2015-12-05 00:57:07 +08:00
get_account(context.account)
when CourseSection
get_account(context.course)
when Group
get sub account branding and custom css/includes working fixes: CNVS-24787 fixes: CNVS-23964 fixes: CNVS-23957 - Handle parent account custom css/js for new_styles test plan: * set up a root account, child account, and grandchild account * use theme editor to set a custom css/js file for each (eg: for css `* {color:red}` and for js 'console.log("from grandchild")` * make a course & a group in the grandchild account * load a page in that course and group and make sure you see grandchild account's branding, and root's, child's, and then grandchild's css loaded on the page (grandchild should be loaded last so you see it's css effects override root or child's and you should see the console.log from root then child then grandchild) * view a page in "child". it should have root and child's css/js but not grandchild * as a user that only has enrollments (account associations) in "child", go to the dashboard. you should see css/js for both root and child but not grandchild fixes: CNVS-25051 Opening Theme Editor for sub-accounts shows incorrect theme preview test plan: * Go to a sub-account in theme editor and change settings so the Branding is different and save. * the preview on the right should reflect your changes both after you "apply" and "save" (and not just show the preview of the root account's branding) fixes: CNVS-23406 - global JS and CSS files are being included when Global CSS/JavaScript includes is false test plan: * go to /accounts/self/, and go to theme editor and upload a css_override * see that that css is loaded on pages * back in root account settings disable Global CSS/JavaScript includes * check that the css is no longer loaded. * do the same thing checking a subaccount's custom css fixes: CNVS-25558 - load whole chain of custom css/js in native app api requests test plan: * make api request for a wiki page in course in a subaccount that has custom css/js within a root account that also has custom css/js * you should see both the root account's css/js and the child account's returned in the response to test grandchild js issue jeremyp found: * go to theme editor for a grandchild account * choose a js override file (like: `console.log('first')`) * preview & apply * you should see "first" in console * go back to theme editor, pick a new file (like: `console.log('second')`) * preview & apply * you should only see "second" in console. not "first" Change-Id: I8d9047948f5da94be41e0205844629a170f980af Reviewed-on: https://gerrit.instructure.com/68249 Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com>
2015-12-05 00:57:07 +08:00
get_account(context.context)
end
subaccount branding (creation and trickle down) fixes CNVS-21426 changes theme_editor routes to nest under accounts show correct brand_config for subaccount be able to theme subaccounts parent account changes trickle down to subs theme editor default values are that of parent account add not in preview text that subaccounts dont show test plan: simple creation - create a sub-account - brand it differently from parent - if you go to courses belonging to this subaccount, it gets their css - if you go to courses belonging to the parent you get the parent css - if you go to a user dashboard you get the parent branding (maybe we can add smarts to this later in case you only are in the subaccount?) trickle down - rebrand two values on the parent - one that the subaccount explicitly sets - and one that doesnt - apply this config on the parent - wait a little and go to the child account - its theme inherits values for the parent, but... if it explicitly sets those values itself then it doesnt inherit it - go to the editor for the subaccount - the placeholder values are those of the parent account (or the canvas default if the parent hasnt set it) - test trickle down with a sub-account and a sub-sub-account still to do on different patch sets: - account settings to allow subaccount branding - show the progress of all the child compilation Change-Id: Iaddba7036f564965427807c2fd8b0a6a5d524366 Reviewed-on: https://gerrit.instructure.com/61285 Reviewed-by: Rob Orton <rob@instructure.com> QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com> Product-Review: Colleen Palmer <colleen@instructure.com>
2015-08-15 02:42:55 +08:00
end
def self.get_account_or_parent_account_global_id(context)
case context
when Account
context.root_account? ? context.global_id : context.global_parent_account_id
when Course
context.global_account_id
when CourseSection
get_account_or_parent_account_global_id(context.course)
when Group
get_account_or_parent_account_global_id(context.context)
end
end
2011-02-01 09:57:29 +08:00
def is_a_context?
true
end
def concluded?
false
end
# Public: Boolean flag re: whether a feature is enabled
# provides defaults for objects that do not include FeatureFlags
# (note: include Context _before_ FeatureFlags)
#
# Returns false
subaccount branding (creation and trickle down) fixes CNVS-21426 changes theme_editor routes to nest under accounts show correct brand_config for subaccount be able to theme subaccounts parent account changes trickle down to subs theme editor default values are that of parent account add not in preview text that subaccounts dont show test plan: simple creation - create a sub-account - brand it differently from parent - if you go to courses belonging to this subaccount, it gets their css - if you go to courses belonging to the parent you get the parent css - if you go to a user dashboard you get the parent branding (maybe we can add smarts to this later in case you only are in the subaccount?) trickle down - rebrand two values on the parent - one that the subaccount explicitly sets - and one that doesnt - apply this config on the parent - wait a little and go to the child account - its theme inherits values for the parent, but... if it explicitly sets those values itself then it doesnt inherit it - go to the editor for the subaccount - the placeholder values are those of the parent account (or the canvas default if the parent hasnt set it) - test trickle down with a sub-account and a sub-sub-account still to do on different patch sets: - account settings to allow subaccount branding - show the progress of all the child compilation Change-Id: Iaddba7036f564965427807c2fd8b0a6a5d524366 Reviewed-on: https://gerrit.instructure.com/61285 Reviewed-by: Rob Orton <rob@instructure.com> QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com> Product-Review: Colleen Palmer <colleen@instructure.com>
2015-08-15 02:42:55 +08:00
def feature_enabled?(_feature)
false
end
def nickname_for(_user, fallback = :name)
self.send fallback if fallback
end
def self.last_updated_at(klass, ids)
raise ArgumentError unless CONTEXT_TYPES.include?(klass.class_name.to_sym)
klass.where(id: ids)
.where.not(updated_at: nil)
.order("updated_at DESC")
.limit(1)
.pluck(:updated_at)&.first
end
def resolved_root_account_id
self.root_account_id if self.respond_to? :root_account_id
end
2011-02-01 09:57:29 +08:00
end