Remove Academic Benchmark v1 code
closes OUT-1006 flag = none test plan: - follow steps on the Confluence page "Academic Benchmark Importing" and confirm that importing using Academic Benchmarks still works Change-Id: I3c0db27221ea3424a78b5f4e503db919a18d690b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/222016 Product-Review: Augusto Callejas <acallejas@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Michael Brewer-Davis <mbd@instructure.com> QA-Review: Michael Brewer-Davis <mbd@instructure.com>
This commit is contained in:
parent
7ee06de561
commit
69151329da
|
@ -7,7 +7,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<%= t "These credentials are for Academic Benchmark API v3. Leaving the Partner Key empty will default the importer to use Academic Benchmark API v1." %>
|
||||
<%= t "These credentials are for Academic Benchmark API v3." %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -22,27 +22,10 @@
|
|||
<%= f.text_field :partner_key %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<%= t "These credentials are for Academic Benchmark API v1, which will be deprecated in a future release." %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= f.blabel :api_url, :en => "Api Url" %></td>
|
||||
<td>
|
||||
<%= f.text_field :api_url,:size => "90" %> <%= t :api_url_description, "(e.g. %{url})", :url => AcademicBenchmark::Api::API_BASE_URL %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= f.blabel :api_key, :en => "API Key" %></td>
|
||||
<td>
|
||||
<%= f.text_field :api_key %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= f.blabel :common_core_guid, :en => "Common Core GUID (optional)" %></td>
|
||||
<td>
|
||||
<%= f.text_field :common_core_guid %> <%= t :common_core_guid, "(e.g. %{guid})", :guid => AcademicBenchmark::ConverterV1::COMMON_CORE_GUID %>
|
||||
<%= f.text_field :common_core_guid %> <%= t :common_core_guid, "(e.g. %{guid})", :guid => AcademicBenchmark::Converter::COMMON_CORE_GUID %>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -41,44 +41,18 @@ module AcademicBenchmark
|
|||
end
|
||||
|
||||
def self.check_config
|
||||
if self.v3?
|
||||
self.check_v3_config
|
||||
else
|
||||
self.check_v1_config
|
||||
end
|
||||
end
|
||||
|
||||
def self.check_v3_config
|
||||
if !self.config
|
||||
"(needs partner_key and partner_id)"
|
||||
elsif !self.config[:partner_key].present?
|
||||
elsif self.config[:partner_key].blank?
|
||||
"(needs partner_key)"
|
||||
elsif !self.config[:partner_id].present?
|
||||
elsif self.config[:partner_id].blank?
|
||||
"(needs partner_id)"
|
||||
end
|
||||
end
|
||||
|
||||
def self.check_v1_config
|
||||
if !self.config
|
||||
"(needs api_key and api_url)"
|
||||
elsif !self.config["api_key"] || self.config["api_key"].empty?
|
||||
"(needs api_key)"
|
||||
elsif !self.config["api_url"] || self.config["api_url"].empty?
|
||||
"(needs api_url)"
|
||||
end
|
||||
end
|
||||
|
||||
def self.v3?
|
||||
self.config.present? && self.config[:partner_key].present?
|
||||
end
|
||||
|
||||
def self.extract_nat_stds(api, nat_stds_guid)
|
||||
return [] if nat_stds_guid.nil?
|
||||
if AcademicBenchmark.v3?
|
||||
api.standards.authority_documents(nat_stds_guid)
|
||||
else
|
||||
api.browse_guid(nat_stds_guid).first["itm"].first["itm"]
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -86,12 +60,8 @@ module AcademicBenchmark
|
|||
# National Standards are also known as Common Core and NGSS
|
||||
##
|
||||
def self.nat_stds_guid_from_auths(authorities)
|
||||
if AcademicBenchmark.v3?
|
||||
stds = authorities.find{|a| a.description == NATIONAL_STANDARDS_TITLE}
|
||||
stds.try(:guid)
|
||||
else
|
||||
authorities.find{|a| a["title"] == NATIONAL_STANDARDS_TITLE}["guid"]
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -103,12 +73,7 @@ module AcademicBenchmark
|
|||
# browsed in order to retrieve specifics like NGSS and Common Core
|
||||
##
|
||||
def self.retrieve_authorities(api)
|
||||
if AcademicBenchmark.v3?
|
||||
self.sort_authorities(api.standards.authorities)
|
||||
else
|
||||
authorities = api.list_available_authorities.select { |a| a.key?("title") }
|
||||
authorities.sort_by {|b| b["title"]}
|
||||
end
|
||||
end
|
||||
|
||||
# sort national standards at the top, followed by country standards,
|
||||
|
@ -138,17 +103,12 @@ module AcademicBenchmark
|
|||
# prepend the common core, next gen science standards,
|
||||
# and the ISTE (NETS) standards to the list
|
||||
auth_list.unshift(self.extract_nat_stds(api, self.nat_stds_guid_from_auths(auth_list)))
|
||||
if self.v3?
|
||||
auth_list.unshift(api.standards.authority_documents(NGSS_AUTHORITY))
|
||||
auth_list.unshift(api.standards.authority_documents(COMMON_CORE_AUTHORITY))
|
||||
|
||||
# flatten down the list of authorities and hashify it
|
||||
auth_list.flatten!
|
||||
auth_list.map(&:to_h)
|
||||
else
|
||||
# append the UK standards to the end of the list and flatten it down
|
||||
auth_list.push(self.uk_guid(api)).flatten
|
||||
end
|
||||
end
|
||||
|
||||
# The UK standards are now available to us as well,
|
||||
|
@ -159,7 +119,6 @@ module AcademicBenchmark
|
|||
class APIError < StandardError; end
|
||||
|
||||
def self.import(guid, options = {})
|
||||
if self.v3?
|
||||
is_auth = self.auth?(guid)
|
||||
authority = is_auth ? guid : nil
|
||||
document = is_auth ? nil : guid
|
||||
|
@ -172,9 +131,6 @@ module AcademicBenchmark
|
|||
user: self.authorized?,
|
||||
options: options
|
||||
).first
|
||||
else
|
||||
AcademicBenchmarkV1.import(Array(guid), options).first
|
||||
end
|
||||
end
|
||||
|
||||
def self.queue_migration_for(authority:, document:, user:, options: {})
|
||||
|
@ -195,28 +151,22 @@ module AcademicBenchmark
|
|||
end
|
||||
|
||||
def self.set_common_core_setting!
|
||||
unless self.v3?
|
||||
AcademicBenchmarkV1.set_common_core_setting!
|
||||
if (guid = AcademicBenchmark.config[:common_core_guid])
|
||||
if (group = LearningOutcomeGroup.where(migration_id: guid).first)
|
||||
Setting.set(common_core_setting_key, group.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.common_core_setting_key
|
||||
unless self.v3?
|
||||
AcademicBenchmarkV1.common_core_setting_key
|
||||
end
|
||||
"common_core_outcome_group_id:#{Shard.current.id}"
|
||||
end
|
||||
|
||||
def self.api_handle
|
||||
# create a new api connection. Note that this does not actually
|
||||
# make a request to the API
|
||||
if AcademicBenchmark.v3?
|
||||
AcademicBenchmarks::Api::Handle.new(partner_id: config[:partner_id], partner_key: config[:partner_key])
|
||||
else
|
||||
AcademicBenchmark::Api.new(self.config["api_key"], base_url: self.config["api_url"])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.auth?(guid)
|
||||
self.api_handle.standards.authorities.map(&:guid).include?(guid)
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2012 - present 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/>.
|
||||
|
||||
module AcademicBenchmark
|
||||
class Api
|
||||
|
||||
API_BASE_URL = "http://api.statestandards.com/services/rest/"
|
||||
BROWSE = "browse"
|
||||
SEARCH = "search"
|
||||
MAINTAIN_ACCESS = "maintainAccess"
|
||||
MA_LIST = 'list'
|
||||
MA_REMOVE = 'remove'
|
||||
MA_ADD = 'add'
|
||||
READ_TIMEOUT = 5.minutes.to_i
|
||||
|
||||
def initialize(api_key, opts={})
|
||||
@api_key = api_key
|
||||
@base_url = opts[:base_url] || API_BASE_URL
|
||||
end
|
||||
|
||||
def browse(opts={})
|
||||
set_defaults!(opts)
|
||||
opts[:levels] ||= 1
|
||||
get_ab_results(@base_url + BROWSE, opts)
|
||||
end
|
||||
|
||||
def search(opts={})
|
||||
set_defaults!(opts)
|
||||
get_ab_results(@base_url + SEARCH, opts)
|
||||
end
|
||||
|
||||
# returns a single list of all authorities across all available countries
|
||||
def list_available_authorities(format = 'json')
|
||||
res = browse({:levels => 2, :format => format})
|
||||
auths = []
|
||||
res.each do |country|
|
||||
next unless country["itm"]
|
||||
auths += country["itm"]
|
||||
end
|
||||
|
||||
auths
|
||||
end
|
||||
|
||||
def browse_authority(auth_code, opts={})
|
||||
opts[:authority] = auth_code
|
||||
browse(opts)
|
||||
end
|
||||
|
||||
def browse_guid(guid, opts={})
|
||||
opts[:guid] = guid
|
||||
browse(opts)
|
||||
end
|
||||
|
||||
def maintain_access(operation, params={})
|
||||
set_defaults!(params)
|
||||
params[:op] ||= operation
|
||||
get_ab_results(@base_url + MAINTAIN_ACCESS, params)
|
||||
end
|
||||
|
||||
def list_ips
|
||||
maintain_access(MA_LIST)
|
||||
end
|
||||
|
||||
def add_ip(ip, note=nil)
|
||||
maintain_access(MA_ADD, :addr => ip, :note => note)
|
||||
end
|
||||
|
||||
def remove_ip(ip)
|
||||
maintain_access(MA_REMOVE, :addr => ip)
|
||||
end
|
||||
|
||||
def get_ab_results(url, params={})
|
||||
res = Api.get_url(url + query_string_from_hash(params))
|
||||
if res.code.to_i == 200
|
||||
parse_ab_data(res.body)
|
||||
else
|
||||
raise APIError.new("HTTP Error: #{res.code} - #{res.body}")
|
||||
end
|
||||
end
|
||||
|
||||
def parse_ab_data(json_string)
|
||||
data = JSON.parse(json_string, :max_nesting => 50)
|
||||
if data["status"] == "ok"
|
||||
return data["itm"] || data["access"] || []
|
||||
else
|
||||
if data["ab_err"]
|
||||
raise APIError.new("responseCode: #{data["ab_err"]["code"]} - #{data["ab_err"]["msg"]}")
|
||||
else
|
||||
raise APIError.new("response: #{data.to_json}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_url(url)
|
||||
uri = URI(url)
|
||||
Net::HTTP.new(uri.host, uri.port).start { |http|
|
||||
http.read_timeout = READ_TIMEOUT
|
||||
http.request_get(uri.request_uri)
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def query_string_from_hash(params)
|
||||
return "" if params.empty?
|
||||
"?".concat(params.map{|k, v| v ? "#{k}=#{CGI::escape(v.to_s)}" : nil}.compact.sort.join('&'))
|
||||
end
|
||||
|
||||
def set_defaults!(opts)
|
||||
opts[:api_key] ||= @api_key
|
||||
opts[:format] ||= 'json'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,152 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2015 - present 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 'httparty'
|
||||
|
||||
module AcademicBenchmark
|
||||
|
||||
class CliTools
|
||||
|
||||
def self.whitelisted_ips
|
||||
HTTParty.get("#{api_url}maintainAccess?api_key=#{api_key}")
|
||||
end
|
||||
|
||||
def self.whitelist_ip(ip, note)
|
||||
HTTParty.get(
|
||||
"#{api_url}maintainAccess?api_key=#{api_key}&op=add&addr=#{ip}¬e=#{note}"
|
||||
)
|
||||
end
|
||||
|
||||
def self.remove_from_whitelist(ip)
|
||||
if self.is_ip_address(ip)
|
||||
self.remove_ip_from_whitelist(ip)
|
||||
else
|
||||
self.remove_note_from_whitelist(ip)
|
||||
end
|
||||
end
|
||||
|
||||
def self.remove_ip_from_whitelist(ip)
|
||||
HTTParty.get(
|
||||
"#{api_url}maintainAccess?api_key=#{api_key}&op=remove&addr=#{ip}"
|
||||
)
|
||||
end
|
||||
|
||||
def self.remove_note_from_whitelist(note)
|
||||
ips = self.whitelisted_ips
|
||||
|
||||
if ips["ab_rsp"] && ips["ab_rsp"]["access"]
|
||||
ips["ab_rsp"]["access"].each do |entry|
|
||||
return remove_ip_from_whitelist(entry["addr"]) if entry["note"] == note
|
||||
end
|
||||
puts "There were no whitelisted IP addresses with a note matching '#{note}'"
|
||||
else
|
||||
puts "Error retrieving list of whitelisted IP addresses: #{ips.to_json}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.whitelisted?(ip)
|
||||
ips = whitelisted_ips
|
||||
ips["ab_rsp"] && ips["ab_rsp"]["access"].any?{ |i| i["addr"] == ip }
|
||||
end
|
||||
|
||||
def self.delete_imported_outcomes(parent_group_title, no_prompt: false, override_shard_restriction: false)
|
||||
unless no_prompt
|
||||
return unless warn_shard
|
||||
return unless warn_deleting(parent_group_title)
|
||||
end
|
||||
Rails.logger.warn("AcademicBenchmark::CliTools - deleting outcomes under #{parent_group_title}")
|
||||
delete_with_children(LearningOutcomeGroup.where(title: parent_group_title).first)
|
||||
Rails.logger.warn("AcademicBenchmark::CliTools - finished deleting outcomes under #{parent_group_title}")
|
||||
end
|
||||
|
||||
# Make sure this account is on its own shard
|
||||
# If it is not, then we could affect other schools
|
||||
def self.own_shard
|
||||
Account.root_accounts.count <= 1
|
||||
end
|
||||
|
||||
private
|
||||
def self.warn_deleting(title)
|
||||
print "WARNING: You are about to delete all imported outcomes under #{title} for this shard. Proceed? (Y/N): "
|
||||
return false unless STDIN.gets.chomp.downcase == "y"
|
||||
return true
|
||||
end
|
||||
|
||||
private
|
||||
def self.warn_shard
|
||||
unless own_shard
|
||||
print "WARNING: This shard has more than one account on it! This means you will affect multiple customers with your actions. Proceed? (Y/N): "
|
||||
return false unless STDIN.gets.chomp.downcase == "y"
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
def self.delete_with_children(item, no_prompt: false, override_shard_restriction: false)
|
||||
expected_types = [LearningOutcomeGroup, ContentTag]
|
||||
if !no_prompt && !expected_types.include?(item.class)
|
||||
puts "Expected #{expected_types.map{|t| t.to_s}.join(" or ") } but received a '#{item.class.to_s}'"
|
||||
return
|
||||
end
|
||||
|
||||
if item.is_a?(LearningOutcomeGroup)
|
||||
# These two queries can be combined when we hit rails 4
|
||||
# and have multi-column pluck
|
||||
child_outcome_links = ContentTag.where(
|
||||
tag_type: 'learning_outcome_association',
|
||||
content_type: 'LearningOutcome',
|
||||
context_id: item.id
|
||||
).pluck(:id)
|
||||
child_outcome_ids = ContentTag.where(
|
||||
tag_type: 'learning_outcome_association',
|
||||
content_type: 'LearningOutcome',
|
||||
context_id: item.id
|
||||
).pluck(:content_id)
|
||||
|
||||
# delete all links to our children
|
||||
ContentTag.destroy(child_outcome_links)
|
||||
# delete all of our children
|
||||
LearningOutcome.destroy(child_outcome_ids)
|
||||
|
||||
item.child_outcome_groups.each do |child|
|
||||
delete_with_children(child)
|
||||
end
|
||||
item.destroy_permanently!
|
||||
else
|
||||
item.destroy_permanently!
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def self.api_key
|
||||
AcademicBenchmark.config["api_key"]
|
||||
end
|
||||
|
||||
private
|
||||
def self.api_url
|
||||
AcademicBenchmark.config["api_url"]
|
||||
end
|
||||
|
||||
private
|
||||
def self.is_ip_address(ip)
|
||||
# this simple and brief regex matches IP addresses strictly
|
||||
ip =~ %r{\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b}
|
||||
end
|
||||
|
||||
end # class CliTools
|
||||
|
||||
end # module AcademicBenchmark
|
|
@ -19,17 +19,17 @@ require 'academic_benchmarks'
|
|||
|
||||
module AcademicBenchmark
|
||||
class Converter < Canvas::Migration::Migrator
|
||||
COMMON_CORE_GUID = 'A83297F2-901A-11DF-A622-0C319DFF4B22'.freeze
|
||||
|
||||
def initialize(settings={})
|
||||
super(settings, "academic_benchmark")
|
||||
@ratings_overrides = settings[:migration_options] || {}
|
||||
@course[:learning_outcomes] = []
|
||||
@converter_v1 = ConverterV1.new(settings)
|
||||
@partner_id = settings[:partner_id]
|
||||
@partner_key = settings[:partner_key]
|
||||
end
|
||||
|
||||
def export
|
||||
if AcademicBenchmark.v3?
|
||||
unless content_migration
|
||||
raise Canvas::Migration::Error,
|
||||
"Missing required content_migration settings"
|
||||
|
@ -38,12 +38,14 @@ module AcademicBenchmark
|
|||
raise Canvas::Migration::Error,
|
||||
"User isn't allowed to edit global outcomes"
|
||||
end
|
||||
unless @archive_file
|
||||
unless @partner_id.present? || AcademicBenchmark.ensure_partner_id.nil?
|
||||
raise Canvas::Migration::Error, I18n.t("A partner ID is required to use Academic Benchmarks")
|
||||
end
|
||||
unless @partner_key.present? || AcademicBenchmark.ensure_partner_key.nil?
|
||||
raise Canvas::Migration::Error, I18n.t("A partner key is required to use Academic Benchmarks")
|
||||
end
|
||||
end
|
||||
if outcome_data.present?
|
||||
if outcome_data.instance_of? AcademicBenchmarks::Standards::StandardsForest
|
||||
outcome_data.trees.each do |t|
|
||||
|
@ -55,16 +57,9 @@ module AcademicBenchmark
|
|||
end
|
||||
save_to_file
|
||||
@course
|
||||
else
|
||||
@converter_v1.export
|
||||
end
|
||||
end
|
||||
|
||||
def post_process
|
||||
unless AcademicBenchmark.v3?
|
||||
@converter_v1.post_process
|
||||
end
|
||||
end
|
||||
def post_process; end
|
||||
|
||||
private
|
||||
def outcome_data
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2012 - present 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/>.
|
||||
|
||||
module AcademicBenchmark
|
||||
class ConverterV1 < Canvas::Migration::Migrator
|
||||
COMMON_CORE_GUID = 'A83297F2-901A-11DF-A622-0C319DFF4B22'.freeze
|
||||
DEFAULT_DEPTH = 3
|
||||
|
||||
def initialize(settings={})
|
||||
super(settings, "academic_benchmark")
|
||||
|
||||
ab_settings = AcademicBenchmark.config
|
||||
@ratings_overrides = settings[:migration_options] || {}
|
||||
|
||||
@api_key = settings[:api_key] || ab_settings[:api_key]
|
||||
@api = AcademicBenchmark::Api.new(@api_key, :base_url => settings[:base_url] || ab_settings[:api_url])
|
||||
|
||||
@common_core_guid = settings[:common_core_guid] || ab_settings[:common_core_guid].presence
|
||||
@course[:learning_outcomes] = []
|
||||
end
|
||||
|
||||
def export
|
||||
if content_migration && !Account.site_admin.grants_right?(content_migration.user, :manage_global_outcomes)
|
||||
raise Canvas::Migration::Error,
|
||||
I18n.t("User isn't allowed to edit global outcomes")
|
||||
end
|
||||
|
||||
if @archive_file
|
||||
convert_file
|
||||
elsif @settings[:authorities] || @settings[:guids]
|
||||
if @api_key && !@api_key.empty?
|
||||
convert_authorities(@settings[:authorities]) if @settings[:authorities]
|
||||
convert_guids(@settings[:guids]) if @settings[:guids]
|
||||
else
|
||||
raise Canvas::Migration::Error,
|
||||
I18n.t("An API key is required to use Academic Benchmarks")
|
||||
end
|
||||
else
|
||||
raise Canvas::Migration::Error, I18n.t("No outcome file or authority given")
|
||||
end
|
||||
|
||||
save_to_file
|
||||
@course
|
||||
end
|
||||
|
||||
def post_process
|
||||
if importing_common_core?
|
||||
AcademicBenchmarkV1.set_common_core_setting!
|
||||
end
|
||||
end
|
||||
|
||||
def importing_common_core?
|
||||
(@settings[:guids] && @settings[:guids].member?(AcademicBenchmark.config[:common_core_guid])) ||
|
||||
(@settings[:authorities] && @settings[:authorities].member?("CC"))
|
||||
end
|
||||
|
||||
def convert_file
|
||||
data = @api.parse_ab_data(@archive_file.read)
|
||||
process_json_data(data)
|
||||
rescue APIError => e
|
||||
add_error(
|
||||
I18n.t("The provided Academic Benchmark file has an error"),
|
||||
{
|
||||
exception: e,
|
||||
error_message: e.message
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def convert_authorities(authorities=[])
|
||||
authorities.each do |auth|
|
||||
refresh_outcomes(:authority => auth)
|
||||
end
|
||||
end
|
||||
|
||||
def convert_guids(guids=[])
|
||||
guids.each do |guid|
|
||||
refresh_outcomes(:guid => guid)
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_outcomes(opts)
|
||||
res = build_full_auth_hash(opts)
|
||||
process_json_data(res)
|
||||
rescue EOFError, APIError => e
|
||||
add_error(
|
||||
I18n.t(
|
||||
"Couldn't update standards for authority %{auth}",
|
||||
:auth => opts[:authority] || opts[:guid]
|
||||
),
|
||||
{
|
||||
exception: e,
|
||||
error_message: e.message
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
# get a shallow tree for the authority then process the leaves
|
||||
def build_full_auth_hash(opts)
|
||||
data = @api.browse({:levels => DEFAULT_DEPTH}.merge(opts))
|
||||
process_leaves!(find_by_prop(data, "type", "authority"))
|
||||
end
|
||||
|
||||
# recursively find leaf nodes with children available to fetch
|
||||
# fetch the children and then process them
|
||||
def process_leaves!(data)
|
||||
if data.is_a? Array
|
||||
data.each do |itm|
|
||||
process_leaves!(itm)
|
||||
end
|
||||
elsif data.is_a? Hash
|
||||
if data["itm"]
|
||||
data["itm"].each do |itm|
|
||||
process_leaves!(itm)
|
||||
end
|
||||
elsif data["chld"]
|
||||
count = data.delete("chld").to_i
|
||||
if count > 0
|
||||
data.delete("chld")
|
||||
children_tree = @api.browse({:levels => DEFAULT_DEPTH, :guid => data["guid"]})
|
||||
dup_with_children = find_by_prop(children_tree, "guid", data["guid"])
|
||||
if data["guid"] == dup_with_children["guid"]
|
||||
data["itm"] = dup_with_children["itm"]
|
||||
process_leaves!(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def process_json_data(data)
|
||||
if data = find_by_prop(data, "type", "authority")
|
||||
outcomes = Standard.new(data).build_outcomes(@ratings_overrides)
|
||||
@course[:learning_outcomes] << outcomes
|
||||
else
|
||||
err_msg = I18n.t("Couldn't find an authority to update")
|
||||
add_error(
|
||||
err_msg, { exception: nil, error_message: err_msg }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def find_by_prop(data, prop, value)
|
||||
return nil unless data
|
||||
if data.is_a? Array
|
||||
data.each do |itm|
|
||||
if found = find_by_prop(itm, prop, value)
|
||||
return found
|
||||
end
|
||||
end
|
||||
elsif data.is_a? Hash
|
||||
if data[prop] && data[prop] == value
|
||||
return data
|
||||
elsif data["itm"]
|
||||
return find_by_prop(data["itm"], prop, value)
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -28,9 +28,7 @@ module AcademicBenchmark
|
|||
:settings_partial => 'academic_benchmark/plugin_settings',
|
||||
:hide_from_users => true,
|
||||
:settings => {
|
||||
:api_key => nil,
|
||||
:api_url => AcademicBenchmark::Api::API_BASE_URL,
|
||||
:common_core_guid => AcademicBenchmark::ConverterV1::COMMON_CORE_GUID,
|
||||
:common_core_guid => AcademicBenchmark::Converter::COMMON_CORE_GUID,
|
||||
:partner_id => nil,
|
||||
:partner_key => nil,
|
||||
:worker => 'CCWorker',
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2012 - present 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/>.
|
||||
|
||||
module AcademicBenchmark
|
||||
|
||||
class Standard
|
||||
def initialize(data, parent=nil)
|
||||
@data = data
|
||||
@parent = parent
|
||||
@children = []
|
||||
|
||||
if has_items?
|
||||
items.each do |itm|
|
||||
Standard.new(itm, self)
|
||||
end
|
||||
end
|
||||
|
||||
# ignore course types and leaves that don't have a num
|
||||
if num || @children.any?
|
||||
@parent.add_child(self) if parent
|
||||
end
|
||||
end
|
||||
|
||||
def build_outcomes(ratings={})
|
||||
hash = {:migration_id => guid, :vendor_guid => guid, :low_grade => low_grade, :high_grade => high_grade, :is_global_standard => true}
|
||||
hash[:description] = description
|
||||
if is_leaf?
|
||||
# create outcome
|
||||
hash[:type] = 'learning_outcome'
|
||||
hash[:title] = build_num_title
|
||||
set_default_ratings(hash, ratings)
|
||||
else
|
||||
#create outcome group
|
||||
hash[:type] = 'learning_outcome_group'
|
||||
hash[:title] = build_title
|
||||
hash[:outcomes] = @children.map {|chld| chld.build_outcomes(ratings)}
|
||||
end
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
def add_child(itm)
|
||||
@children << itm
|
||||
end
|
||||
|
||||
def has_items?
|
||||
!!(items && items.any?)
|
||||
end
|
||||
|
||||
def items
|
||||
@data["itm"]
|
||||
end
|
||||
|
||||
def guid
|
||||
@data["guid"]
|
||||
end
|
||||
|
||||
def type
|
||||
@data["type"]
|
||||
end
|
||||
|
||||
def title
|
||||
@data["title"]
|
||||
end
|
||||
|
||||
# standards don't have titles so they are built from parent standards/groups
|
||||
# it is generated like this:
|
||||
# if I have a num, use it and all parent nums on standards
|
||||
# if I don't have a num, use my description (potentially truncated at 50)
|
||||
def build_num_title
|
||||
# when traversing AB data, "standards" will always be deeper in the data
|
||||
# hierarchy, so this code will always hit the else before a @parent is nil
|
||||
if @parent.is_standard?
|
||||
base = @parent.build_num_title
|
||||
if base && num
|
||||
num.include?(base) ? num : base + '.' + num
|
||||
elsif base
|
||||
base
|
||||
else
|
||||
num
|
||||
end
|
||||
else
|
||||
num
|
||||
end
|
||||
end
|
||||
|
||||
def build_title
|
||||
if num
|
||||
build_num_title + " - " + (title || cropped_description)
|
||||
else
|
||||
title || cropped_description
|
||||
end
|
||||
end
|
||||
|
||||
def num
|
||||
get_meta_field("num")
|
||||
end
|
||||
|
||||
def description
|
||||
get_meta_field("descr")
|
||||
end
|
||||
|
||||
def cropped_description
|
||||
# get the first 50 chars of description in a utf-8 friendly way
|
||||
description && description[/.{0,50}/u]
|
||||
end
|
||||
|
||||
def name
|
||||
get_meta_field("name")
|
||||
end
|
||||
|
||||
def high_grade
|
||||
if @data["meta"] && @data["meta"]["name"]
|
||||
@data["meta"]["hi"]
|
||||
else
|
||||
@parent && @parent.high_grade
|
||||
end
|
||||
end
|
||||
|
||||
def low_grade
|
||||
if @data["meta"] && @data["meta"]["name"]
|
||||
@data["meta"]["lo"]
|
||||
else
|
||||
@parent && @parent.low_grade
|
||||
end
|
||||
end
|
||||
|
||||
def get_meta_field(field)
|
||||
@data["meta"] && @data["meta"][field] && @data["meta"][field]["content"]
|
||||
end
|
||||
|
||||
def is_standard?
|
||||
type == 'standard'
|
||||
end
|
||||
|
||||
# it's only a leaf if it's a standard and has no children, or no children with a 'num'
|
||||
# having a num is to ignore extra description nodes that we want to ignore
|
||||
def is_leaf?
|
||||
num && @children.empty?
|
||||
end
|
||||
|
||||
def set_default_ratings(hash, overrides={})
|
||||
hash[:ratings] = [{:description => "Exceeds Expectations", :points => 5},
|
||||
{:description => "Meets Expectations", :points => 3},
|
||||
{:description => "Does Not Meet Expectations", :points => 0}]
|
||||
hash[:mastery_points] = 3
|
||||
hash[:points_possible] = 5
|
||||
hash.merge!(overrides)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,74 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2012 - present 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 'net/http'
|
||||
require 'cgi'
|
||||
|
||||
module AcademicBenchmarkV1
|
||||
def self.import(guid_or_guids, options={})
|
||||
if !AcademicBenchmark.config[:api_key] || AcademicBenchmark.config[:api_key].empty?
|
||||
raise Canvas::Migration::Error, "Not importing academic benchmark data because no API key is set"
|
||||
end
|
||||
|
||||
# need a user with global outcome management rights
|
||||
user_id = Setting.get("academic_benchmark_migration_user_id", nil)
|
||||
unless user_id.present?
|
||||
raise Canvas::Migration::Error, "Not importing academic benchmark data because no user id set"
|
||||
end
|
||||
|
||||
unless (permissionful_user = User.where(id: user_id).first)
|
||||
raise Canvas::Migration::Error, "Not importing academic benchmark data because no user found"
|
||||
end
|
||||
|
||||
Array(guid_or_guids).map do |guid|
|
||||
AcademicBenchmarkV1.queue_migration_for_guid(guid, permissionful_user, options).first
|
||||
end
|
||||
end
|
||||
|
||||
def self.queue_migration_for_guid(guid, user, options={})
|
||||
unless Account.site_admin.grants_right?(user, :manage_global_outcomes)
|
||||
raise Canvas::Migration::Error,
|
||||
I18n.t("User isn't allowed to edit global outcomes")
|
||||
end
|
||||
|
||||
cm = ContentMigration.new(:context => Account.site_admin)
|
||||
cm.converter_class = AcademicBenchmark.config['converter_class']
|
||||
cm.migration_settings[:migration_type] = 'academic_benchmark_importer'
|
||||
cm.migration_settings[:import_immediately] = true
|
||||
cm.migration_settings[:guids] = [guid]
|
||||
cm.migration_settings[:no_archive_file] = true
|
||||
cm.migration_settings[:skip_import_notification] = true
|
||||
cm.migration_settings[:skip_job_progress] = true
|
||||
cm.migration_settings[:migration_options] = options
|
||||
cm.strand = "academic_benchmark"
|
||||
cm.user = user
|
||||
cm.save!
|
||||
[cm, cm.export_content]
|
||||
end
|
||||
|
||||
def self.set_common_core_setting!
|
||||
if (guid = AcademicBenchmark.config[:common_core_guid])
|
||||
if (group = LearningOutcomeGroup.where(migration_id: guid).first)
|
||||
Setting.set(common_core_setting_key, group.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.common_core_setting_key
|
||||
"common_core_outcome_group_id:#{Shard.current.id}"
|
||||
end
|
||||
end
|
|
@ -1,6 +1,5 @@
|
|||
# encoding: utf-8
|
||||
#
|
||||
# Copyright (C) 2012 - present Instructure, Inc.
|
||||
# Copyright (C) 2015 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
|
@ -28,18 +27,17 @@ describe AcademicBenchmark::Converter do
|
|||
@cm.converter_class = @plugin.settings['converter_class']
|
||||
@cm.migration_settings[:migration_type] = 'academic_benchmark_importer'
|
||||
@cm.migration_settings[:import_immediately] = true
|
||||
@cm.migration_settings[:base_url] = "http://example.com/"
|
||||
@cm.migration_settings[:migration_options] = {points_possible: 10, mastery_points: 6,
|
||||
ratings: [{description: 'Bad', points: 0}, {description: 'Awesome', points: 10}]}
|
||||
@cm.user = @user
|
||||
@cm.save!
|
||||
|
||||
@level_0_browse = File.join(File.dirname(__FILE__) + '/fixtures', 'example.json')
|
||||
@a_levels_3 = File.join(File.dirname(__FILE__) + '/fixtures', 'a_levels_3.json')
|
||||
@d_levels_3 = File.join(File.dirname(__FILE__) + '/fixtures', 'd_levels_3.json')
|
||||
@j_levels_3 = File.join(File.dirname(__FILE__) + '/fixtures', 'j_levels_3.json')
|
||||
@authority_list = File.join(File.dirname(__FILE__) + '/fixtures', 'auth_list.json')
|
||||
@florida_auth_list = File.join(File.dirname(__FILE__) + '/fixtures', 'florida_auth_list.json')
|
||||
current_settings = @plugin.settings
|
||||
new_settings = current_settings.merge(:partner_id => "instructure", :partner_key => "secret")
|
||||
allow(@plugin).to receive(:settings).and_return(new_settings)
|
||||
|
||||
@level_0_browse = File.join(File.dirname(__FILE__) + '/fixtures', 'api_all_standards_response.json')
|
||||
@florida_auth_list = File.join(File.dirname(__FILE__) + '/fixtures', 'florida_auth_list_v3.json')
|
||||
File.open(@level_0_browse, 'r') do |file|
|
||||
@att = Attachment.create!(
|
||||
:filename => 'standards.json',
|
||||
|
@ -61,78 +59,85 @@ describe AcademicBenchmark::Converter do
|
|||
|
||||
def verify_full_import
|
||||
@root_group = LearningOutcomeGroup.global_root_outcome_group
|
||||
expect(@root_group.child_outcome_groups.count).to eq 1
|
||||
expect(@root_group.child_outcome_groups.count).to eq 2
|
||||
a = @root_group.child_outcome_groups.first
|
||||
expect(a.migration_id).to eq "aaaaaaaaaa"
|
||||
expect(a.title).to eq "NGA Center/CCSSO"
|
||||
expect(a.migration_id).to eq "CEC2CF6C-67AD-11DF-AB5F-995D9DFF4B22"
|
||||
expect(a.title).to eq "CCSS.ELA-Literacy.CCRA.R - Reading"
|
||||
b = a.child_outcome_groups.first
|
||||
expect(b.migration_id).to eq "bbbbbbbbbbbb"
|
||||
expect(b.title).to eq "Common Core State Standards"
|
||||
c = b.child_outcome_groups.first
|
||||
expect(c.migration_id).to eq "cccccccccc"
|
||||
expect(c.title).to eq "College- and Career-Readiness Standards and K-12 Mathematics"
|
||||
d = c.child_outcome_groups.where(migration_id: "ddddddddd").first
|
||||
expect(d.migration_id).to eq "ddddddddd"
|
||||
expect(d.title).to eq "Kindergarten"
|
||||
expect(d.low_grade).to eq "K"
|
||||
expect(d.high_grade).to eq "K"
|
||||
e = d.child_outcome_groups.first
|
||||
expect(e.migration_id).to eq "eeeeeeeeeeee"
|
||||
expect(e.title).to eq "K.CC - Counting and Cardinality"
|
||||
expect(e.description).to eq "Counting and Cardinality"
|
||||
expect(e.low_grade).to eq "K"
|
||||
expect(e.high_grade).to eq "K"
|
||||
f = e.child_outcome_groups.first
|
||||
expect(f.migration_id).to eq "ffffffffffffff"
|
||||
expect(f.title).to eq "Know number names and the count sequence."
|
||||
expect(f.description).to eq "Know number names and the count sequence."
|
||||
expect(f.low_grade).to eq "K"
|
||||
expect(f.high_grade).to eq "K"
|
||||
expect(f.child_outcome_links.count).to eq 3
|
||||
|
||||
g = LearningOutcome.global.where(migration_id: "ggggggggggggggggg").first
|
||||
expect(b.migration_id).to eq "CEB79A48-67AD-11DF-AB5F-995D9DFF4B22"
|
||||
expect(b.title).to eq "Key Ideas and Details"
|
||||
g = LearningOutcome.global.where(migration_id: "CEB87C92-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "K.CC.1"
|
||||
expect(g.description).to eq "Count to 100 by ones and by tens."
|
||||
g = LearningOutcome.global.where(migration_id: "hhhhhhhhhhhhhhhh").first
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.1"
|
||||
expect(g.description).to eq "Read closely to determine what the text says explicitly and to make logical" \
|
||||
" inferences from it; cite specific textual evidence when writing or speaking to support conclusions drawn" \
|
||||
" from the text."
|
||||
g = LearningOutcome.global.where(migration_id: "CEB8EE66-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "K.CC.2"
|
||||
expect(g.description).to eq "Count forward beginning from a given number within the known sequence (instead of having to begin at 1)."
|
||||
g = LearningOutcome.global.where(migration_id: "iiiiiiiiiiiiiiiii").first
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.2"
|
||||
expect(g.description).to eq "Determine central ideas or themes of a text and analyze their development;" \
|
||||
" summarize the key supporting details and ideas."
|
||||
g = LearningOutcome.global.where(migration_id: "CEB96684-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "K.CC.3"
|
||||
expect(g.description).to eq "Write numbers from 0 to 20. Represent a number of objects with a written numeral 0-20 (with 0 representing a count of no objects)."
|
||||
|
||||
j = c.child_outcome_groups.where(migration_id: "jjjjjjjjjjj").first
|
||||
expect(j.migration_id).to eq "jjjjjjjjjjj"
|
||||
expect(j.title).to eq "First Grade"
|
||||
expect(j.low_grade).to eq "1"
|
||||
expect(j.high_grade).to eq "1"
|
||||
k = j.child_outcome_groups.last
|
||||
expect(k.migration_id).to eq "kkkkkkkkkkk"
|
||||
expect(k.title).to eq "1.DD - zééééééééééééééééééééééééééééééééééééééééééééééééé"
|
||||
expect(k.description).to eq "zéééééééééééééééééééééééééééééééééééééééééééééééééééééééééé"
|
||||
expect(k.low_grade).to eq "1"
|
||||
expect(k.high_grade).to eq "1"
|
||||
l = k.child_outcome_groups.first
|
||||
expect(l.migration_id).to eq "lllllllll"
|
||||
expect(l.title).to eq "Something else"
|
||||
expect(l.description).to eq "Something else"
|
||||
expect(l.low_grade).to eq "1"
|
||||
expect(l.high_grade).to eq "1"
|
||||
expect(l.child_outcome_links.count).to eq 1
|
||||
|
||||
m = LearningOutcome.global.where(migration_id: "mmmmmmmmmmm").first
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.3"
|
||||
expect(g.description).to eq "Analyze how and why individuals, events, and ideas develop and interact over" \
|
||||
" the course of a text."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBAB958-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(m.short_description).to eq "1.DD.1"
|
||||
expect(m.description).to eq "And something else"
|
||||
expect(m.title).to eq "1.DD.1"
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.4"
|
||||
expect(g.description).to eq "Interpret words and phrases as they are used in a text, including determining" \
|
||||
" technical, connotative, and figurative meanings, and analyze how specific word choices shape meaning or tone."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBB9AA8-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.5"
|
||||
expect(g.description).to eq "Analyze the structure of texts, including how specific sentences, paragraphs," \
|
||||
" and larger portions of the text (e.g., a section, chapter, scene, or stanza) relate to each other and" \
|
||||
" the whole."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBC89F4-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.6"
|
||||
expect(g.description).to eq "Assess how point of view or purpose shapes the content and style of a text."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBDDCA0-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.7"
|
||||
expect(g.description).to eq "Integrate and evaluate content presented in diverse media and formats," \
|
||||
" including visually and quantitatively, as well as in words."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBE4D52-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.8"
|
||||
expect(g.description).to eq "Delineate and evaluate the argument and specific claims in a text," \
|
||||
" including the validity of the reasoning as well as the relevance and sufficiency of the evidence."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBF37B2-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.9"
|
||||
expect(g.description).to eq "Analyze how two or more texts address similar themes or topics in order" \
|
||||
" to build knowledge or to compare the approaches the authors take."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC08B44-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.10"
|
||||
expect(g.description).to eq "Read and comprehend complex literary and informational texts independently" \
|
||||
" and proficiently."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC49A36-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.W.1"
|
||||
expect(g.description).to eq "Write arguments to support claims in an analysis of substantive topics or" \
|
||||
" texts, using valid reasoning and relevant and sufficient evidence."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC57CD0-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.W.2"
|
||||
expect(g.description).to eq "Write informative/explanatory texts to examine and convey complex ideas and" \
|
||||
" information clearly and accurately through the effective selection, organization, and analysis of content."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC665B4-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.W.3"
|
||||
expect(g.description).to eq "Write narratives to develop real or imagined experiences or events" \
|
||||
" using effective technique, well-chosen details, and well-structured event sequences."
|
||||
end
|
||||
|
||||
def check_for_parent_num_duplication(outcome)
|
||||
parent = outcome.instance_variable_get('@parent')
|
||||
if outcome.num && parent && parent.is_standard? && parent.title && outcome.num.include?(parent.title)
|
||||
outcome.title == "#{parent.title}.#{outcome.num}"
|
||||
if outcome.number && parent && parent.build_title && outcome.number.include?(parent.build_title)
|
||||
outcome.title == "#{parent.title}.#{outcome.number}"
|
||||
else
|
||||
false
|
||||
end
|
||||
|
@ -165,108 +170,38 @@ describe AcademicBenchmark::Converter do
|
|||
expect(@cm.workflow_state).to eq 'failed'
|
||||
end
|
||||
|
||||
it "should fail if no file or authority set" do
|
||||
@cm.attachment = nil
|
||||
@cm.migration_settings[:no_archive_file] = true
|
||||
@cm.save!
|
||||
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_issues.count).to eq 1
|
||||
expect(@cm.migration_issues.first.description).to eq "No outcome file or authority given"
|
||||
expect(@cm.workflow_state).to eq 'failed'
|
||||
end
|
||||
|
||||
context "using the API" do
|
||||
append_before do
|
||||
@plugin.settings['api_key'] = "oioioi"
|
||||
@cm.attachment = nil
|
||||
@cm.migration_settings[:no_archive_file] = true
|
||||
@cm.migration_settings[:authorities] = ["CC"]
|
||||
@cm.save!
|
||||
end
|
||||
|
||||
def run_and_check
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_issues.count).to eq 0
|
||||
expect(@cm.workflow_state).to eq 'imported'
|
||||
|
||||
@root_group = LearningOutcomeGroup.global_root_outcome_group
|
||||
expect(@root_group.child_outcome_groups.count).to eq 1
|
||||
a = @root_group.child_outcome_groups.first
|
||||
expect(a.migration_id).to eq "aaaaaaaaaa"
|
||||
end
|
||||
|
||||
it "should fail with no API key" do
|
||||
@plugin.settings['api_key'] = nil
|
||||
it "should fail with no partner ID" do
|
||||
@plugin.settings[:partner_id] = nil
|
||||
@plugin.settings[:partner_key] = "a"
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_issues.count).to eq 1
|
||||
expect(@cm.migration_issues.first.description).to eq "An API key is required to use Academic Benchmarks"
|
||||
expect(@cm.migration_issues.first.description).to eq "A partner ID is required to use Academic Benchmarks"
|
||||
expect(@cm.workflow_state).to eq 'failed'
|
||||
end
|
||||
|
||||
it "should fail with an empty string API key" do
|
||||
@plugin.settings['api_key'] = ""
|
||||
it "should fail with an empty string partner ID" do
|
||||
current_settings = @plugin.settings
|
||||
new_settings = current_settings.merge(:partner_id => "", :partner_key => "a")
|
||||
allow(@plugin).to receive(:settings).and_return(new_settings)
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_issues.count).to eq 1
|
||||
expect(@cm.migration_issues.first.description).to eq "An API key is required to use Academic Benchmarks"
|
||||
expect(@cm.migration_issues.first.description).to eq "A partner ID is required to use Academic Benchmarks"
|
||||
expect(@cm.workflow_state).to eq 'failed'
|
||||
end
|
||||
|
||||
it "should use the API to get the set data with an authority short code" do
|
||||
response = double()
|
||||
allow(response).to receive(:body).and_return(File.read(@level_0_browse))
|
||||
allow(response).to receive(:code).and_return("200")
|
||||
expect(AcademicBenchmark::Api).to receive(:get_url).with("http://example.com/browse?api_key=oioioi&authority=CC&format=json&levels=3").and_return(response)
|
||||
|
||||
run_and_check
|
||||
verify_full_import
|
||||
end
|
||||
|
||||
it "should use the API to get the set data with a guid" do
|
||||
@cm.migration_settings[:authorities] = nil
|
||||
@cm.migration_settings[:guids] = ["aaaaaaaaaa"]
|
||||
response = double('a_levels_3')
|
||||
allow(response).to receive(:body).and_return(File.read(@a_levels_3))
|
||||
allow(response).to receive(:code).and_return("200")
|
||||
expect(AcademicBenchmark::Api).to receive(:get_url).with("http://example.com/browse?api_key=oioioi&format=json&guid=aaaaaaaaaa&levels=3").and_return(response)
|
||||
responsed = double('d_levels_3')
|
||||
allow(responsed).to receive(:body).and_return(File.read(@d_levels_3))
|
||||
allow(responsed).to receive(:code).and_return("200")
|
||||
expect(AcademicBenchmark::Api).to receive(:get_url).with("http://example.com/browse?api_key=oioioi&format=json&guid=ddddddddd&levels=3").and_return(responsed)
|
||||
responsej = double('j_levels_3')
|
||||
allow(responsej).to receive(:body).and_return(File.read(@j_levels_3))
|
||||
allow(responsej).to receive(:code).and_return("200")
|
||||
expect(AcademicBenchmark::Api).to receive(:get_url).with("http://example.com/browse?api_key=oioioi&format=json&guid=jjjjjjjjjjj&levels=3").and_return(responsej)
|
||||
|
||||
run_and_check
|
||||
verify_full_import
|
||||
end
|
||||
|
||||
it "should warn when api returns non-success" do
|
||||
response = double()
|
||||
allow(response).to receive(:body).and_return(%{{"status":"fail","ab_err":{"msg":"API key access violation.","code":"401"}}})
|
||||
allow(response).to receive(:code).and_return("200")
|
||||
expect(AcademicBenchmark::Api).to receive(:get_url).with("http://example.com/browse?api_key=oioioi&authority=CC&format=json&levels=3").and_return(response)
|
||||
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_settings[:last_error]).to be_nil
|
||||
expect(@cm.workflow_state).to eq 'imported'
|
||||
end
|
||||
end
|
||||
|
||||
# This test came about because the titles being generated for
|
||||
|
@ -277,10 +212,28 @@ describe AcademicBenchmark::Converter do
|
|||
#
|
||||
# instead of this:
|
||||
#
|
||||
# LAFS.1.L.1.1.a instead of LAFS.1.L.LAFS.1.L.1.LAFS.1.L.1.1.a
|
||||
# LAFS.1.L.1.1.a
|
||||
#
|
||||
it "doesn't duplicate the base numbers when building a title" do
|
||||
json_data = JSON.parse(File.read(@florida_auth_list))
|
||||
check_built_outcome(AcademicBenchmark::Standard.new(json_data))
|
||||
AcademicBenchmarks::Standards::StandardsForest.new(json_data).trees.each do |tree|
|
||||
tree.children.each do |outcome|
|
||||
check_built_outcome(outcome)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "raises error with invalid user id" do
|
||||
expect { AcademicBenchmark.ensure_real_user(user_id: 0) }.to raise_error(Canvas::Migration::Error,
|
||||
"Not importing academic benchmark data because no user found matching id '0'")
|
||||
end
|
||||
|
||||
it "raises error when crendentials are not set" do
|
||||
allow(AcademicBenchmark).to receive(:config).and_return({})
|
||||
expect{ AcademicBenchmark.ensure_ab_credentials }.to raise_error(Canvas::Migration::Error,
|
||||
"Not importing academic benchmark data because the Academic Benchmarks Partner ID is not set")
|
||||
allow(AcademicBenchmark).to receive(:config).and_return({partner_id: "user"})
|
||||
expect{ AcademicBenchmark.ensure_ab_credentials }.to raise_error(Canvas::Migration::Error,
|
||||
"Not importing academic benchmark data because the Academic Benchmarks Partner key is not set")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,240 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2015 - present 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 File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
||||
|
||||
describe AcademicBenchmark::Converter do
|
||||
|
||||
before(:each) do
|
||||
@root_account = Account.site_admin
|
||||
account_admin_user(:account => @root_account, :active_all => true)
|
||||
@cm = ContentMigration.new(:context => @root_account)
|
||||
@plugin = Canvas::Plugin.find('academic_benchmark_importer')
|
||||
@cm.converter_class = @plugin.settings['converter_class']
|
||||
@cm.migration_settings[:migration_type] = 'academic_benchmark_importer'
|
||||
@cm.migration_settings[:import_immediately] = true
|
||||
@cm.migration_settings[:migration_options] = {points_possible: 10, mastery_points: 6,
|
||||
ratings: [{description: 'Bad', points: 0}, {description: 'Awesome', points: 10}]}
|
||||
@cm.user = @user
|
||||
@cm.save!
|
||||
|
||||
current_settings = @plugin.settings
|
||||
new_settings = current_settings.merge(:partner_id => "instructure", :partner_key => "secret")
|
||||
allow(@plugin).to receive(:settings).and_return(new_settings)
|
||||
|
||||
@level_0_browse = File.join(File.dirname(__FILE__) + '/fixtures', 'api_all_standards_response.json')
|
||||
@florida_auth_list = File.join(File.dirname(__FILE__) + '/fixtures', 'florida_auth_list_v3.json')
|
||||
File.open(@level_0_browse, 'r') do |file|
|
||||
@att = Attachment.create!(
|
||||
:filename => 'standards.json',
|
||||
:display_name => 'standards.json',
|
||||
:uploaded_data => file,
|
||||
:context => @cm
|
||||
)
|
||||
end
|
||||
@cm.attachment = @att
|
||||
@cm.save!
|
||||
end
|
||||
|
||||
def verify_rubric_criterion(outcome)
|
||||
expect(outcome.data[:rubric_criterion][:mastery_points]).to eq 6
|
||||
expect(outcome.data[:rubric_criterion][:points_possible]).to eq 10
|
||||
expect(outcome.data[:rubric_criterion][:ratings]).to eq [{description: 'Bad', points: 0},
|
||||
{description: 'Awesome', points: 10}]
|
||||
end
|
||||
|
||||
def verify_full_import
|
||||
@root_group = LearningOutcomeGroup.global_root_outcome_group
|
||||
expect(@root_group.child_outcome_groups.count).to eq 2
|
||||
a = @root_group.child_outcome_groups.first
|
||||
expect(a.migration_id).to eq "CEC2CF6C-67AD-11DF-AB5F-995D9DFF4B22"
|
||||
expect(a.title).to eq "CCSS.ELA-Literacy.CCRA.R - Reading"
|
||||
b = a.child_outcome_groups.first
|
||||
expect(b.migration_id).to eq "CEB79A48-67AD-11DF-AB5F-995D9DFF4B22"
|
||||
expect(b.title).to eq "Key Ideas and Details"
|
||||
g = LearningOutcome.global.where(migration_id: "CEB87C92-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.1"
|
||||
expect(g.description).to eq "Read closely to determine what the text says explicitly and to make logical" \
|
||||
" inferences from it; cite specific textual evidence when writing or speaking to support conclusions drawn" \
|
||||
" from the text."
|
||||
g = LearningOutcome.global.where(migration_id: "CEB8EE66-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.2"
|
||||
expect(g.description).to eq "Determine central ideas or themes of a text and analyze their development;" \
|
||||
" summarize the key supporting details and ideas."
|
||||
g = LearningOutcome.global.where(migration_id: "CEB96684-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.3"
|
||||
expect(g.description).to eq "Analyze how and why individuals, events, and ideas develop and interact over" \
|
||||
" the course of a text."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBAB958-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.4"
|
||||
expect(g.description).to eq "Interpret words and phrases as they are used in a text, including determining" \
|
||||
" technical, connotative, and figurative meanings, and analyze how specific word choices shape meaning or tone."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBB9AA8-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.5"
|
||||
expect(g.description).to eq "Analyze the structure of texts, including how specific sentences, paragraphs," \
|
||||
" and larger portions of the text (e.g., a section, chapter, scene, or stanza) relate to each other and" \
|
||||
" the whole."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBC89F4-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.6"
|
||||
expect(g.description).to eq "Assess how point of view or purpose shapes the content and style of a text."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBDDCA0-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.7"
|
||||
expect(g.description).to eq "Integrate and evaluate content presented in diverse media and formats," \
|
||||
" including visually and quantitatively, as well as in words."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBE4D52-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.8"
|
||||
expect(g.description).to eq "Delineate and evaluate the argument and specific claims in a text," \
|
||||
" including the validity of the reasoning as well as the relevance and sufficiency of the evidence."
|
||||
g = LearningOutcome.global.where(migration_id: "CEBF37B2-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.9"
|
||||
expect(g.description).to eq "Analyze how two or more texts address similar themes or topics in order" \
|
||||
" to build knowledge or to compare the approaches the authors take."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC08B44-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.10"
|
||||
expect(g.description).to eq "Read and comprehend complex literary and informational texts independently" \
|
||||
" and proficiently."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC49A36-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.W.1"
|
||||
expect(g.description).to eq "Write arguments to support claims in an analysis of substantive topics or" \
|
||||
" texts, using valid reasoning and relevant and sufficient evidence."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC57CD0-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.W.2"
|
||||
expect(g.description).to eq "Write informative/explanatory texts to examine and convey complex ideas and" \
|
||||
" information clearly and accurately through the effective selection, organization, and analysis of content."
|
||||
g = LearningOutcome.global.where(migration_id: "CEC665B4-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||
verify_rubric_criterion(g)
|
||||
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.W.3"
|
||||
expect(g.description).to eq "Write narratives to develop real or imagined experiences or events" \
|
||||
" using effective technique, well-chosen details, and well-structured event sequences."
|
||||
end
|
||||
|
||||
def check_for_parent_num_duplication(outcome)
|
||||
parent = outcome.instance_variable_get('@parent')
|
||||
if outcome.number && parent && parent.build_title && outcome.number.include?(parent.build_title)
|
||||
outcome.title == "#{parent.title}.#{outcome.number}"
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def check_built_outcome(outcome)
|
||||
expect(check_for_parent_num_duplication(outcome)).to be_falsey
|
||||
outcome.instance_variable_get('@children').each { |o| check_built_outcome(o) }
|
||||
end
|
||||
|
||||
it "should successfully import the standards" do
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
expect(@cm.migration_issues.count).to eq 0
|
||||
expect(@cm.workflow_state).to eq 'imported'
|
||||
|
||||
verify_full_import()
|
||||
end
|
||||
|
||||
it "should reject creating global outcomes if no permissions" do
|
||||
@cm.user = nil
|
||||
@cm.save!
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_issues.count).to eq 1
|
||||
expect(@cm.migration_issues.first.description).to eq "User isn't allowed to edit global outcomes"
|
||||
expect(@cm.workflow_state).to eq 'failed'
|
||||
end
|
||||
|
||||
context "using the API" do
|
||||
append_before do
|
||||
@cm.attachment = nil
|
||||
@cm.migration_settings[:no_archive_file] = true
|
||||
@cm.migration_settings[:authorities] = ["CC"]
|
||||
@cm.save!
|
||||
end
|
||||
|
||||
it "should fail with no partner ID" do
|
||||
@plugin.settings['api_key'] = nil
|
||||
@plugin.settings[:partner_id] = nil
|
||||
@plugin.settings[:partner_key] = "a"
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_issues.count).to eq 1
|
||||
expect(@cm.migration_issues.first.description).to eq "A partner ID is required to use Academic Benchmarks"
|
||||
expect(@cm.workflow_state).to eq 'failed'
|
||||
end
|
||||
|
||||
it "should fail with an empty string partner ID" do
|
||||
current_settings = @plugin.settings
|
||||
new_settings = current_settings.merge('api_key' => nil, :partner_id => "", :partner_key => "a")
|
||||
allow(@plugin).to receive(:settings).and_return(new_settings)
|
||||
@cm.export_content
|
||||
run_jobs
|
||||
@cm.reload
|
||||
|
||||
expect(@cm.migration_issues.count).to eq 1
|
||||
expect(@cm.migration_issues.first.description).to eq "A partner ID is required to use Academic Benchmarks"
|
||||
expect(@cm.workflow_state).to eq 'failed'
|
||||
end
|
||||
end
|
||||
|
||||
# This test came about because the titles being generated for
|
||||
# Florida outcomes were long and out of control. They were looking
|
||||
# like this:
|
||||
#
|
||||
# LAFS.1.L.LAFS.1.L.1.LAFS.1.L.1.1.a
|
||||
#
|
||||
# instead of this:
|
||||
#
|
||||
# LAFS.1.L.1.1.a
|
||||
#
|
||||
it "doesn't duplicate the base numbers when building a title" do
|
||||
json_data = JSON.parse(File.read(@florida_auth_list))
|
||||
AcademicBenchmarks::Standards::StandardsForest.new(json_data).trees.each do |tree|
|
||||
tree.children.each do |outcome|
|
||||
check_built_outcome(outcome)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "raises error with invalid user id" do
|
||||
expect { AcademicBenchmark.ensure_real_user(user_id: 0) }.to raise_error(Canvas::Migration::Error,
|
||||
"Not importing academic benchmark data because no user found matching id '0'")
|
||||
end
|
||||
|
||||
it "raises error when crendentials are not set" do
|
||||
allow(AcademicBenchmark).to receive(:config).and_return({})
|
||||
expect{ AcademicBenchmark.ensure_ab_credentials }.to raise_error(Canvas::Migration::Error,
|
||||
"Not importing academic benchmark data because the Academic Benchmarks Partner ID is not set")
|
||||
allow(AcademicBenchmark).to receive(:config).and_return({partner_id: "user"})
|
||||
expect{ AcademicBenchmark.ensure_ab_credentials }.to raise_error(Canvas::Migration::Error,
|
||||
"Not importing academic benchmark data because the Academic Benchmarks Partner key is not set")
|
||||
end
|
||||
end
|
|
@ -1,81 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2012 - present 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 File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
||||
|
||||
describe AcademicBenchmark::Api do
|
||||
|
||||
before do
|
||||
@api = AcademicBenchmark::Api.new("oioioi", :base_url => "http://example.com/")
|
||||
|
||||
@level_0_browse = File.join(File.dirname(__FILE__) + '/fixtures', 'example.json')
|
||||
@authority_list = File.join(File.dirname(__FILE__) + '/fixtures', 'auth_list.json')
|
||||
end
|
||||
|
||||
def mock_api_call(code, body, url)
|
||||
response = double()
|
||||
allow(response).to receive(:body).and_return(body)
|
||||
allow(response).to receive(:code).and_return(code.to_s)
|
||||
expect(AcademicBenchmark::Api).to receive(:get_url).with(url).and_return(response)
|
||||
end
|
||||
|
||||
it "should fail with bad AB response" do
|
||||
mock_api_call(200,
|
||||
%{{"status":"fail","ab_err":{"msg":"API key access violation.","code":"401"}}},
|
||||
"http://example.com/browse?api_key=oioioi&format=json&levels=2")
|
||||
|
||||
expect {
|
||||
@api.list_available_authorities
|
||||
}.to raise_error(AcademicBenchmark::APIError)
|
||||
end
|
||||
|
||||
it "should fail with http error code" do
|
||||
mock_api_call(500,
|
||||
'',
|
||||
"http://example.com/browse?api_key=oioioi&format=json&levels=2")
|
||||
|
||||
expect {
|
||||
@api.list_available_authorities
|
||||
}.to raise_error(AcademicBenchmark::APIError)
|
||||
end
|
||||
|
||||
it "should get authority" do
|
||||
mock_api_call(200,
|
||||
'{"status":"ok", "itm":[{"test":"yep"}]}',
|
||||
"http://example.com/browse?api_key=oioioi&authority=CC&format=json&levels=0")
|
||||
expect(@api.browse_authority("CC", :levels => 0)).to eq [{"test" => "yep"}]
|
||||
end
|
||||
|
||||
it "should get guid" do
|
||||
mock_api_call(200,
|
||||
'{"status":"ok", "itm":[{"test":"yep"}]}',
|
||||
"http://example.com/browse?api_key=oioioi&format=json&guid=gggggg&levels=0")
|
||||
expect(@api.browse_guid("gggggg", :levels => 0)).to eq [{"test" => "yep"}]
|
||||
end
|
||||
|
||||
it "should get available authorities" do
|
||||
mock_api_call(200,
|
||||
File.read(@authority_list),
|
||||
"http://example.com/browse?api_key=oioioi&format=json&levels=2")
|
||||
|
||||
expect(@api.list_available_authorities).to eq [{"chld" => "1", "guid" => "AAA", "title" => "NGA Center/CCSSO", "type" => "authority"},
|
||||
{"chld" => "2", "guid" => "CCC", "title" => "South Carolina", "type" => "authority"},
|
||||
{"chld" => "3", "guid" => "BBB", "title" => "Louisiana", "type" => "authority"},
|
||||
{"chld" => "2", "guid" => "111", "title" => "Good Standards", "type" => "authority"},
|
||||
{"chld" => "3", "guid" => "222", "title" => "Bad Standards", "type" => "authority"}]
|
||||
end
|
||||
end
|
|
@ -1,46 +0,0 @@
|
|||
{"status":"ok", "itm":[
|
||||
{
|
||||
"title":"United States",
|
||||
"guid":"US",
|
||||
"type":"country",
|
||||
"itm":[
|
||||
{
|
||||
"title":"NGA Center/CCSSO",
|
||||
"guid":"AAA",
|
||||
"type":"authority",
|
||||
"chld":"1"
|
||||
},
|
||||
{
|
||||
"title":"South Carolina",
|
||||
"guid":"CCC",
|
||||
"type":"authority",
|
||||
"chld":"2"
|
||||
},
|
||||
{
|
||||
"title":"Louisiana",
|
||||
"guid":"BBB",
|
||||
"type":"authority",
|
||||
"chld":"3"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title":"Canvas Land",
|
||||
"guid":"CL",
|
||||
"type":"country",
|
||||
"itm":[
|
||||
{
|
||||
"title":"Good Standards",
|
||||
"guid":"111",
|
||||
"type":"authority",
|
||||
"chld":"2"
|
||||
},
|
||||
{
|
||||
"title":"Bad Standards",
|
||||
"guid":"222",
|
||||
"type":"authority",
|
||||
"chld":"3"
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
|
@ -1,158 +0,0 @@
|
|||
{"status":"ok", "itm":[
|
||||
{
|
||||
"title":"United States",
|
||||
"guid":"US",
|
||||
"type":"country",
|
||||
"itm":[
|
||||
{
|
||||
"title":"NGA Center/CCSSO",
|
||||
"guid":"aaaaaaaaaa",
|
||||
"type":"authority",
|
||||
"itm":[
|
||||
{
|
||||
"title":"Common Core State Standards",
|
||||
"guid":"bbbbbbbbbbbb",
|
||||
"type":"document",
|
||||
"itm":[
|
||||
{
|
||||
"title":"College- and Career-Readiness Standards and K-12 Mathematics",
|
||||
"guid":"cccccccccc",
|
||||
"type":"subject",
|
||||
"meta":{
|
||||
"content":"2010",
|
||||
"name":"year"
|
||||
},
|
||||
"itm":[
|
||||
{
|
||||
"title":"Kindergarten",
|
||||
"guid":"ddddddddd",
|
||||
"type":"grade",
|
||||
"meta":{
|
||||
"hi":"K",
|
||||
"lo":"K",
|
||||
"name":"grade"
|
||||
},
|
||||
"itm":[
|
||||
{
|
||||
"guid":"eeeeeeeeeeee",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{
|
||||
"content":"K.CC"
|
||||
},
|
||||
"descr":{
|
||||
"content":"Counting and Cardinality"
|
||||
}
|
||||
},
|
||||
"itm":[
|
||||
{
|
||||
"guid":"ffffffffffffff",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{},
|
||||
"descr":{
|
||||
"content":"Know number names and the count sequence."
|
||||
}
|
||||
},
|
||||
"itm":[
|
||||
{
|
||||
"guid":"ggggggggggggggggg",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{
|
||||
"content":"1"
|
||||
},
|
||||
"descr":{
|
||||
"content":"Count to 100 by ones and by tens."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"guid":"hhhhhhhhhhhhhhhh",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{
|
||||
"content":"2"
|
||||
},
|
||||
"descr":{
|
||||
"content":"Count forward beginning from a given number within the known sequence (instead of having to begin at 1)."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"guid":"iiiiiiiiiiiiiiiii",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{
|
||||
"content":"3"
|
||||
},
|
||||
"descr":{
|
||||
"content":"Write numbers from 0 to 20. Represent a number of objects with a written numeral 0-20 (with 0 representing a count of no objects)."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title":"First Grade",
|
||||
"guid":"jjjjjjjjjjj",
|
||||
"type":"grade",
|
||||
"meta":{
|
||||
"hi":"1",
|
||||
"lo":"1",
|
||||
"name":"grade"
|
||||
},
|
||||
"itm":[
|
||||
{
|
||||
"guid":"kkkkkkkkkkk",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{
|
||||
"content":"1.DD"
|
||||
},
|
||||
"descr":{
|
||||
"content":"zéééééééééééééééééééééééééééééééééééééééééééééééééééééééééé"
|
||||
}
|
||||
},
|
||||
"itm":[
|
||||
{
|
||||
"guid":"lllllllll",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{},
|
||||
"descr":{
|
||||
"content":"Something else"
|
||||
}
|
||||
},
|
||||
"itm":[
|
||||
{
|
||||
"guid":"mmmmmmmmmmm",
|
||||
"type":"standard",
|
||||
"meta":{
|
||||
"num":{
|
||||
"content":"1"
|
||||
},
|
||||
"descr":{
|
||||
"content":"And something else"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
|
@ -1,368 +0,0 @@
|
|||
[
|
||||
{
|
||||
"title": "Common Core State Standards",
|
||||
"guid": "89c8ea94",
|
||||
"type": "document",
|
||||
"chld": "2"
|
||||
},
|
||||
{
|
||||
"title": "NGSS Arranged by Topic",
|
||||
"guid": "138c9cb7",
|
||||
"type": "document",
|
||||
"chld": "1"
|
||||
},
|
||||
{
|
||||
"title": "Next Generation Science Standards NGSS Arranged by Disciplinary Core Idea (DCI)",
|
||||
"guid": "923ce7bf",
|
||||
"type": "document",
|
||||
"chld": "1"
|
||||
},
|
||||
{
|
||||
"title": "NETS for Administrators",
|
||||
"guid": "923ce7ba",
|
||||
"type": "document",
|
||||
"chld": "1"
|
||||
},
|
||||
{
|
||||
"title": "NETS for Teachers",
|
||||
"guid": "923ce7bb",
|
||||
"type": "document",
|
||||
"chld": "1"
|
||||
},
|
||||
{
|
||||
"title": "NETS for Students",
|
||||
"guid": "923ce7bc",
|
||||
"type": "document",
|
||||
"chld": "1"
|
||||
},
|
||||
{
|
||||
"title": "Alabama",
|
||||
"guid": "46bb3879",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Alaska",
|
||||
"guid": "21f67573",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Arizona",
|
||||
"guid": "55fb05de",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Arkansas",
|
||||
"guid": "9fadba9f",
|
||||
"type": "authority",
|
||||
"chld": "2"
|
||||
},
|
||||
{
|
||||
"title": "Australia",
|
||||
"guid": "24d23683",
|
||||
"type": "authority",
|
||||
"chld": "1"
|
||||
},
|
||||
{
|
||||
"title": "California",
|
||||
"guid": "51a90b1c",
|
||||
"type": "authority",
|
||||
"chld": "7"
|
||||
},
|
||||
{
|
||||
"title": "Colorado",
|
||||
"guid": "87740e39",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Connecticut",
|
||||
"guid": "ebf5916a",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "Delaware",
|
||||
"guid": "6de6b316",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "District of Columbia",
|
||||
"guid": "7063136c",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "Florida",
|
||||
"guid": "33ed68e9",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "Georgia",
|
||||
"guid": "6eca1d5b",
|
||||
"type": "authority",
|
||||
"chld": "6"
|
||||
},
|
||||
{
|
||||
"title": "Hawaii",
|
||||
"guid": "c4e475d5",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Idaho",
|
||||
"guid": "c4d27bbf",
|
||||
"type": "authority",
|
||||
"chld": "2"
|
||||
},
|
||||
{
|
||||
"title": "Illinois",
|
||||
"guid": "c52909fe",
|
||||
"type": "authority",
|
||||
"chld": "7"
|
||||
},
|
||||
{
|
||||
"title": "Indiana",
|
||||
"guid": "5405f7cd",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Iowa",
|
||||
"guid": "a1408ccf",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "Kansas",
|
||||
"guid": "d9e92a00",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Kentucky",
|
||||
"guid": "e935b719",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Louisiana",
|
||||
"guid": "6b6ab39f",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Maine",
|
||||
"guid": "7aa35836",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Maryland",
|
||||
"guid": "ab7c9a74",
|
||||
"type": "authority",
|
||||
"chld": "8"
|
||||
},
|
||||
{
|
||||
"title": "Massachusetts",
|
||||
"guid": "e47b1fd7",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Michigan",
|
||||
"guid": "f674f704",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Minnesota",
|
||||
"guid": "49412237",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Mississippi",
|
||||
"guid": "16e8ef83",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Missouri",
|
||||
"guid": "7eb6d9c1",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Montana",
|
||||
"guid": "f8b810b0",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "National Standards",
|
||||
"guid": "be4ae687",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Nebraska",
|
||||
"guid": "1d80aef1",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Nevada",
|
||||
"guid": "4ac3bf40",
|
||||
"type": "authority",
|
||||
"chld": "2"
|
||||
},
|
||||
{
|
||||
"title": "New Hampshire",
|
||||
"guid": "b879cab0",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "New Jersey",
|
||||
"guid": "28ccaa7f",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "New Mexico",
|
||||
"guid": "62d48dfb",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "New South Wales",
|
||||
"guid": "dc11940b",
|
||||
"type": "authority",
|
||||
"chld": "1"
|
||||
},
|
||||
{
|
||||
"title": "New York",
|
||||
"guid": "5ba1414e",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "North Carolina",
|
||||
"guid": "60d9162b",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "North Dakota",
|
||||
"guid": "3a254e65",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Ohio",
|
||||
"guid": "3cad1282",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Oklahoma",
|
||||
"guid": "75e44c01",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Oregon",
|
||||
"guid": "b73ef744",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Pennsylvania",
|
||||
"guid": "f049b761",
|
||||
"type": "authority",
|
||||
"chld": "6"
|
||||
},
|
||||
{
|
||||
"title": "Rhode Island",
|
||||
"guid": "182583c5",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "South Carolina",
|
||||
"guid": "dbe6080d",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "South Dakota",
|
||||
"guid": "e4279125",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Tennessee",
|
||||
"guid": "02becaac",
|
||||
"type": "authority",
|
||||
"chld": "5"
|
||||
},
|
||||
{
|
||||
"title": "Texas",
|
||||
"guid": "ce3b417f",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Utah",
|
||||
"guid": "33eb23e4",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Vermont",
|
||||
"guid": "56164380",
|
||||
"type": "authority",
|
||||
"chld": "6"
|
||||
},
|
||||
{
|
||||
"title": "Virginia",
|
||||
"guid": "7ff76448",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Washington",
|
||||
"guid": "fd5eab70",
|
||||
"type": "authority",
|
||||
"chld": "7"
|
||||
},
|
||||
{
|
||||
"title": "West Virginia",
|
||||
"guid": "7f9edddc",
|
||||
"type": "authority",
|
||||
"chld": "3"
|
||||
},
|
||||
{
|
||||
"title": "Wisconsin",
|
||||
"guid": "8b18ea97",
|
||||
"type": "authority",
|
||||
"chld": "4"
|
||||
},
|
||||
{
|
||||
"title": "Wyoming",
|
||||
"guid": "7121df7d",
|
||||
"type": "authority",
|
||||
"chld": "2"
|
||||
},
|
||||
{
|
||||
"title": "United Kingdom",
|
||||
"guid": "e13189f3",
|
||||
"type": "country",
|
||||
"chld": "1"
|
||||
}
|
||||
]
|
|
@ -132,33 +132,20 @@ describe "Outcomes Import API", type: :request do
|
|||
|
||||
it "requires the AcademicBenchmark config to be set" do
|
||||
stub_ab_config_with(nil)
|
||||
# Since :partner_key is missing above, we default to using AB API v1.
|
||||
# Once AB API v3 becomes default, switch the regex below to /needs partner_key and partner_id/
|
||||
expect(request.call(type: request_type)["error"]).to match(/needs api_key and api_url/i)
|
||||
expect(request.call(type: request_type)["error"]).to match(/needs partner_key and partner_id/i)
|
||||
end
|
||||
|
||||
context "requires the AcademicBenchmark config api_key or partner_key to be set" do
|
||||
# Since :partner_key is missing below, we default to using AB API v1.
|
||||
# Once AB API v3 becomes default, switch the regex below to /needs partner_key/
|
||||
context "requires the AcademicBenchmark config partner_key to be set" do
|
||||
it "rejects a missing/nil key" do
|
||||
stub_ab_config_with({ "api_url" => "http://a.real.url.com" })
|
||||
expect(request.call(type: request_type)["error"]).to match(/needs api_key/i)
|
||||
stub_ab_config_with({})
|
||||
expect(request.call(type: request_type)["error"]).to match(/needs partner_key/i)
|
||||
end
|
||||
# Since :partner_key is empty below, we default to using AB API v1.
|
||||
# Once AB API v3 becomes default, switch the regex below to /needs partner_key/
|
||||
it "rejects a partner key that is the empty string" do
|
||||
stub_ab_config_with({
|
||||
partner_id: "instructure",
|
||||
partner_key: ""
|
||||
})
|
||||
expect(request.call(type: request_type)["error"]).to match(/needs api_key/i)
|
||||
end
|
||||
it "rejects an api key that is the empty string" do
|
||||
stub_ab_config_with({
|
||||
"api_url" => "http://a.real.url.com",
|
||||
"api_key" => ""
|
||||
})
|
||||
expect(request.call(type: request_type)["error"]).to match(/needs api_key/i)
|
||||
expect(request.call(type: request_type)["error"]).to match(/needs partner_key/i)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -391,36 +378,6 @@ describe "Outcomes Import API", type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
describe "v1" do
|
||||
def stub_ab_import
|
||||
cm_mock = double("content_migration")
|
||||
allow(cm_mock).to receive(:id).and_return(3)
|
||||
allow(AcademicBenchmark).to receive(:import).and_return(cm_mock)
|
||||
end
|
||||
include_examples "outcomes import" do
|
||||
let(:description_key){ "title" }
|
||||
let(:json_file) { "available_return_val_v1.json" }
|
||||
def stub_ab_api
|
||||
api_mock = double("api")
|
||||
allow(api_mock).to receive(:list_available_authorities).
|
||||
and_return(filename_to_hash("api_list_authorities.json"))
|
||||
allow(api_mock).to receive(:browse_guid).
|
||||
and_return(filename_to_hash("api_browse_guid.json"))
|
||||
allow(api_mock).to receive(:browse).
|
||||
and_return(filename_to_hash("api_browse.json"))
|
||||
allow(AcademicBenchmark::Api).to receive(:new).and_return(api_mock)
|
||||
end
|
||||
|
||||
def stub_ab_config
|
||||
stub_ab_config_with({
|
||||
"api_key" => "<secret-key>",
|
||||
"api_url" => "http://api.statestandards.com/services/rest/"
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "v3" do
|
||||
def stub_ab_import
|
||||
cm_mock = double("content_migration")
|
||||
allow(cm_mock).to receive(:id).and_return(3)
|
||||
|
@ -435,7 +392,7 @@ describe "Outcomes Import API", type: :request do
|
|||
and_return(filename_to_hash("available_authorities.json").
|
||||
map{ |a| AcademicBenchmarks::Standards::Authority.from_hash(a) })
|
||||
allow(standards_mock).to receive(:authority_documents).
|
||||
with(not_eq('CC').and not_eq('NRC')).
|
||||
with(not_eq('CC').and(not_eq('NRC'))).
|
||||
and_return(filename_to_hash("national_standards_authority_docs.json").
|
||||
map{ |d| AcademicBenchmarks::Standards::Document.from_hash(d) })
|
||||
allow(standards_mock).to receive(:authority_documents).
|
||||
|
@ -457,5 +414,3 @@ describe "Outcomes Import API", type: :request do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -98,12 +98,8 @@ module OutcomeCommon
|
|||
|
||||
def state_outcome
|
||||
state_outcome = [
|
||||
'NGA Center/CCSSO',
|
||||
'Common Core State Standards',
|
||||
'College- and Career-Readiness Standards and K-12 Mathematics',
|
||||
'First Grade',
|
||||
'1.DD - zééééééééééééééééééééééééééééééééééééééééééééééééé',
|
||||
'Something else'
|
||||
'CCSS.ELA-Literacy.CCRA.R - Reading',
|
||||
'Craft and Structure'
|
||||
]
|
||||
state_outcome
|
||||
end
|
||||
|
|
|
@ -40,8 +40,7 @@ describe "account admin outcomes" do
|
|||
@cm.user = @user
|
||||
@cm.save!
|
||||
|
||||
@level_0_browse = File.join(File.dirname(__FILE__) + "/../../../gems/plugins/academic_benchmark/spec_canvas/fixtures", 'example.json')
|
||||
@authority_list = File.join(File.dirname(__FILE__) + "/../../../gems/plugins/academic_benchmark/spec_canvas/fixtures", 'auth_list.json')
|
||||
@level_0_browse = File.join(File.dirname(__FILE__) + "/../../../gems/plugins/academic_benchmark/spec_canvas/fixtures", 'api_all_standards_response.json')
|
||||
File.open(@level_0_browse, 'r') do |file|
|
||||
@att = Attachment.create!(:filename => 'standards.json', :display_name => 'standards.json', :uploaded_data => file, :context => @cm)
|
||||
end
|
||||
|
@ -59,7 +58,7 @@ describe "account admin outcomes" do
|
|||
it "should have state standards available for outcomes through find", priority: "2", test_id: 250008 do
|
||||
state_outcome_setup
|
||||
goto_state_outcomes
|
||||
expect(ffj(".outcome-level:last .outcome-group .ellipsis")[0]).to have_attribute("title", 'NGA Center/CCSSO')
|
||||
expect(ffj(".outcome-level:last .outcome-group .ellipsis")[0]).to have_attribute("title", 'CCSS.ELA-Literacy.CCRA.R - Reading')
|
||||
end
|
||||
|
||||
it "should import state standards to course groups and all nested outcomes", priority: "2", test_id: 56584 do
|
||||
|
@ -67,22 +66,22 @@ describe "account admin outcomes" do
|
|||
import_state_standards_to_account(state_outcome)
|
||||
el1 = fj(".outcome-level:first .outcome-group .ellipsis")
|
||||
el2 = fj(".outcome-level:last .outcome-link .ellipsis")
|
||||
expect(el1).to have_attribute("title", 'Something else')
|
||||
expect(el2).to have_attribute("title", '1.DD.1')
|
||||
expect(el1).to have_attribute("title", 'Craft and Structure')
|
||||
expect(el2).to have_attribute("title", 'CCSS.ELA-Literacy.CCRA.R.4')
|
||||
end
|
||||
|
||||
it "should import a state standard into account level", priority: "2", test_id: 56017 do
|
||||
skip_if_safari(:alert)
|
||||
outcome = ['NGA Center/CCSSO']
|
||||
outcome = ['CCSS.ELA-Literacy.CCRA.R - Reading']
|
||||
import_state_standards_to_account(outcome)
|
||||
el = fj('.outcome-level:first .outcome-group .ellipsis')
|
||||
expect(el).to have_attribute("title", 'NGA Center/CCSSO')
|
||||
expect(el).to have_attribute("title", 'CCSS.ELA-Literacy.CCRA.R - Reading')
|
||||
end
|
||||
|
||||
it "should import account outcomes into course", priority: "1", test_id: 56585 do
|
||||
skip_if_safari(:alert)
|
||||
import_state_standards_to_account(state_outcome)
|
||||
outcome = ['Default Account', 'Something else']
|
||||
outcome = ['Default Account', 'Craft and Structure']
|
||||
goto_state_outcomes("/courses/#{@course.id}/outcomes")
|
||||
traverse_nested_outcomes(outcome)
|
||||
import_account_level_outcomes
|
||||
|
@ -91,7 +90,7 @@ describe "account admin outcomes" do
|
|||
it "should delete state standards outcome groups from course listing", priority: "2", test_id: 250009 do
|
||||
skip_if_safari(:alert)
|
||||
import_state_standards_to_account(state_outcome)
|
||||
f(".ellipsis[title='Something else']").click
|
||||
f(".ellipsis[title='Craft and Structure']").click
|
||||
wait_for_ajaximations
|
||||
|
||||
f('.delete_button').click
|
||||
|
|
Loading…
Reference in New Issue