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>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -22,27 +22,10 @@
|
||||||
<%= f.text_field :partner_key %>
|
<%= f.text_field :partner_key %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td><%= f.blabel :common_core_guid, :en => "Common Core GUID (optional)" %></td>
|
<td><%= f.blabel :common_core_guid, :en => "Common Core GUID (optional)" %></td>
|
||||||
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -41,44 +41,18 @@ module AcademicBenchmark
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.check_config
|
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
|
if !self.config
|
||||||
"(needs partner_key and partner_id)"
|
"(needs partner_key and partner_id)"
|
||||||
elsif !self.config[:partner_key].present?
|
elsif self.config[:partner_key].blank?
|
||||||
"(needs partner_key)"
|
"(needs partner_key)"
|
||||||
elsif !self.config[:partner_id].present?
|
elsif self.config[:partner_id].blank?
|
||||||
"(needs partner_id)"
|
"(needs partner_id)"
|
||||||
end
|
end
|
||||||
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)
|
def self.extract_nat_stds(api, nat_stds_guid)
|
||||||
return [] if nat_stds_guid.nil?
|
return [] if nat_stds_guid.nil?
|
||||||
if AcademicBenchmark.v3?
|
|
||||||
api.standards.authority_documents(nat_stds_guid)
|
api.standards.authority_documents(nat_stds_guid)
|
||||||
else
|
|
||||||
api.browse_guid(nat_stds_guid).first["itm"].first["itm"]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -86,12 +60,8 @@ module AcademicBenchmark
|
||||||
# National Standards are also known as Common Core and NGSS
|
# National Standards are also known as Common Core and NGSS
|
||||||
##
|
##
|
||||||
def self.nat_stds_guid_from_auths(authorities)
|
def self.nat_stds_guid_from_auths(authorities)
|
||||||
if AcademicBenchmark.v3?
|
|
||||||
stds = authorities.find{|a| a.description == NATIONAL_STANDARDS_TITLE}
|
stds = authorities.find{|a| a.description == NATIONAL_STANDARDS_TITLE}
|
||||||
stds.try(:guid)
|
stds.try(:guid)
|
||||||
else
|
|
||||||
authorities.find{|a| a["title"] == NATIONAL_STANDARDS_TITLE}["guid"]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -103,12 +73,7 @@ module AcademicBenchmark
|
||||||
# browsed in order to retrieve specifics like NGSS and Common Core
|
# browsed in order to retrieve specifics like NGSS and Common Core
|
||||||
##
|
##
|
||||||
def self.retrieve_authorities(api)
|
def self.retrieve_authorities(api)
|
||||||
if AcademicBenchmark.v3?
|
|
||||||
self.sort_authorities(api.standards.authorities)
|
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
|
end
|
||||||
|
|
||||||
# sort national standards at the top, followed by country standards,
|
# sort national standards at the top, followed by country standards,
|
||||||
|
@ -138,17 +103,12 @@ module AcademicBenchmark
|
||||||
# prepend the common core, next gen science standards,
|
# prepend the common core, next gen science standards,
|
||||||
# and the ISTE (NETS) standards to the list
|
# and the ISTE (NETS) standards to the list
|
||||||
auth_list.unshift(self.extract_nat_stds(api, self.nat_stds_guid_from_auths(auth_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(NGSS_AUTHORITY))
|
||||||
auth_list.unshift(api.standards.authority_documents(COMMON_CORE_AUTHORITY))
|
auth_list.unshift(api.standards.authority_documents(COMMON_CORE_AUTHORITY))
|
||||||
|
|
||||||
# flatten down the list of authorities and hashify it
|
# flatten down the list of authorities and hashify it
|
||||||
auth_list.flatten!
|
auth_list.flatten!
|
||||||
auth_list.map(&:to_h)
|
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
|
end
|
||||||
|
|
||||||
# The UK standards are now available to us as well,
|
# The UK standards are now available to us as well,
|
||||||
|
@ -159,7 +119,6 @@ module AcademicBenchmark
|
||||||
class APIError < StandardError; end
|
class APIError < StandardError; end
|
||||||
|
|
||||||
def self.import(guid, options = {})
|
def self.import(guid, options = {})
|
||||||
if self.v3?
|
|
||||||
is_auth = self.auth?(guid)
|
is_auth = self.auth?(guid)
|
||||||
authority = is_auth ? guid : nil
|
authority = is_auth ? guid : nil
|
||||||
document = is_auth ? nil : guid
|
document = is_auth ? nil : guid
|
||||||
|
@ -172,9 +131,6 @@ module AcademicBenchmark
|
||||||
user: self.authorized?,
|
user: self.authorized?,
|
||||||
options: options
|
options: options
|
||||||
).first
|
).first
|
||||||
else
|
|
||||||
AcademicBenchmarkV1.import(Array(guid), options).first
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.queue_migration_for(authority:, document:, user:, options: {})
|
def self.queue_migration_for(authority:, document:, user:, options: {})
|
||||||
|
@ -195,28 +151,22 @@ module AcademicBenchmark
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_common_core_setting!
|
def self.set_common_core_setting!
|
||||||
unless self.v3?
|
if (guid = AcademicBenchmark.config[:common_core_guid])
|
||||||
AcademicBenchmarkV1.set_common_core_setting!
|
if (group = LearningOutcomeGroup.where(migration_id: guid).first)
|
||||||
|
Setting.set(common_core_setting_key, group.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.common_core_setting_key
|
def self.common_core_setting_key
|
||||||
unless self.v3?
|
"common_core_outcome_group_id:#{Shard.current.id}"
|
||||||
AcademicBenchmarkV1.common_core_setting_key
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.api_handle
|
def self.api_handle
|
||||||
# create a new api connection. Note that this does not actually
|
# create a new api connection. Note that this does not actually
|
||||||
# make a request to the API
|
# make a request to the API
|
||||||
if AcademicBenchmark.v3?
|
|
||||||
AcademicBenchmarks::Api::Handle.new(partner_id: config[:partner_id], partner_key: config[:partner_key])
|
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
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def self.auth?(guid)
|
def self.auth?(guid)
|
||||||
self.api_handle.standards.authorities.map(&:guid).include?(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
|
module AcademicBenchmark
|
||||||
class Converter < Canvas::Migration::Migrator
|
class Converter < Canvas::Migration::Migrator
|
||||||
|
COMMON_CORE_GUID = 'A83297F2-901A-11DF-A622-0C319DFF4B22'.freeze
|
||||||
|
|
||||||
def initialize(settings={})
|
def initialize(settings={})
|
||||||
super(settings, "academic_benchmark")
|
super(settings, "academic_benchmark")
|
||||||
@ratings_overrides = settings[:migration_options] || {}
|
@ratings_overrides = settings[:migration_options] || {}
|
||||||
@course[:learning_outcomes] = []
|
@course[:learning_outcomes] = []
|
||||||
@converter_v1 = ConverterV1.new(settings)
|
|
||||||
@partner_id = settings[:partner_id]
|
@partner_id = settings[:partner_id]
|
||||||
@partner_key = settings[:partner_key]
|
@partner_key = settings[:partner_key]
|
||||||
end
|
end
|
||||||
|
|
||||||
def export
|
def export
|
||||||
if AcademicBenchmark.v3?
|
|
||||||
unless content_migration
|
unless content_migration
|
||||||
raise Canvas::Migration::Error,
|
raise Canvas::Migration::Error,
|
||||||
"Missing required content_migration settings"
|
"Missing required content_migration settings"
|
||||||
|
@ -38,12 +38,14 @@ module AcademicBenchmark
|
||||||
raise Canvas::Migration::Error,
|
raise Canvas::Migration::Error,
|
||||||
"User isn't allowed to edit global outcomes"
|
"User isn't allowed to edit global outcomes"
|
||||||
end
|
end
|
||||||
|
unless @archive_file
|
||||||
unless @partner_id.present? || AcademicBenchmark.ensure_partner_id.nil?
|
unless @partner_id.present? || AcademicBenchmark.ensure_partner_id.nil?
|
||||||
raise Canvas::Migration::Error, I18n.t("A partner ID is required to use Academic Benchmarks")
|
raise Canvas::Migration::Error, I18n.t("A partner ID is required to use Academic Benchmarks")
|
||||||
end
|
end
|
||||||
unless @partner_key.present? || AcademicBenchmark.ensure_partner_key.nil?
|
unless @partner_key.present? || AcademicBenchmark.ensure_partner_key.nil?
|
||||||
raise Canvas::Migration::Error, I18n.t("A partner key is required to use Academic Benchmarks")
|
raise Canvas::Migration::Error, I18n.t("A partner key is required to use Academic Benchmarks")
|
||||||
end
|
end
|
||||||
|
end
|
||||||
if outcome_data.present?
|
if outcome_data.present?
|
||||||
if outcome_data.instance_of? AcademicBenchmarks::Standards::StandardsForest
|
if outcome_data.instance_of? AcademicBenchmarks::Standards::StandardsForest
|
||||||
outcome_data.trees.each do |t|
|
outcome_data.trees.each do |t|
|
||||||
|
@ -55,16 +57,9 @@ module AcademicBenchmark
|
||||||
end
|
end
|
||||||
save_to_file
|
save_to_file
|
||||||
@course
|
@course
|
||||||
else
|
|
||||||
@converter_v1.export
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def post_process
|
def post_process; end
|
||||||
unless AcademicBenchmark.v3?
|
|
||||||
@converter_v1.post_process
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def outcome_data
|
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',
|
:settings_partial => 'academic_benchmark/plugin_settings',
|
||||||
:hide_from_users => true,
|
:hide_from_users => true,
|
||||||
:settings => {
|
:settings => {
|
||||||
:api_key => nil,
|
:common_core_guid => AcademicBenchmark::Converter::COMMON_CORE_GUID,
|
||||||
:api_url => AcademicBenchmark::Api::API_BASE_URL,
|
|
||||||
:common_core_guid => AcademicBenchmark::ConverterV1::COMMON_CORE_GUID,
|
|
||||||
:partner_id => nil,
|
:partner_id => nil,
|
||||||
:partner_key => nil,
|
:partner_key => nil,
|
||||||
:worker => 'CCWorker',
|
: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.
|
# This file is part of Canvas.
|
||||||
#
|
#
|
||||||
|
@ -28,18 +27,17 @@ describe AcademicBenchmark::Converter do
|
||||||
@cm.converter_class = @plugin.settings['converter_class']
|
@cm.converter_class = @plugin.settings['converter_class']
|
||||||
@cm.migration_settings[:migration_type] = 'academic_benchmark_importer'
|
@cm.migration_settings[:migration_type] = 'academic_benchmark_importer'
|
||||||
@cm.migration_settings[:import_immediately] = true
|
@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,
|
@cm.migration_settings[:migration_options] = {points_possible: 10, mastery_points: 6,
|
||||||
ratings: [{description: 'Bad', points: 0}, {description: 'Awesome', points: 10}]}
|
ratings: [{description: 'Bad', points: 0}, {description: 'Awesome', points: 10}]}
|
||||||
@cm.user = @user
|
@cm.user = @user
|
||||||
@cm.save!
|
@cm.save!
|
||||||
|
|
||||||
@level_0_browse = File.join(File.dirname(__FILE__) + '/fixtures', 'example.json')
|
current_settings = @plugin.settings
|
||||||
@a_levels_3 = File.join(File.dirname(__FILE__) + '/fixtures', 'a_levels_3.json')
|
new_settings = current_settings.merge(:partner_id => "instructure", :partner_key => "secret")
|
||||||
@d_levels_3 = File.join(File.dirname(__FILE__) + '/fixtures', 'd_levels_3.json')
|
allow(@plugin).to receive(:settings).and_return(new_settings)
|
||||||
@j_levels_3 = File.join(File.dirname(__FILE__) + '/fixtures', 'j_levels_3.json')
|
|
||||||
@authority_list = File.join(File.dirname(__FILE__) + '/fixtures', 'auth_list.json')
|
@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.json')
|
@florida_auth_list = File.join(File.dirname(__FILE__) + '/fixtures', 'florida_auth_list_v3.json')
|
||||||
File.open(@level_0_browse, 'r') do |file|
|
File.open(@level_0_browse, 'r') do |file|
|
||||||
@att = Attachment.create!(
|
@att = Attachment.create!(
|
||||||
:filename => 'standards.json',
|
:filename => 'standards.json',
|
||||||
|
@ -61,78 +59,85 @@ describe AcademicBenchmark::Converter do
|
||||||
|
|
||||||
def verify_full_import
|
def verify_full_import
|
||||||
@root_group = LearningOutcomeGroup.global_root_outcome_group
|
@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
|
a = @root_group.child_outcome_groups.first
|
||||||
expect(a.migration_id).to eq "aaaaaaaaaa"
|
expect(a.migration_id).to eq "CEC2CF6C-67AD-11DF-AB5F-995D9DFF4B22"
|
||||||
expect(a.title).to eq "NGA Center/CCSSO"
|
expect(a.title).to eq "CCSS.ELA-Literacy.CCRA.R - Reading"
|
||||||
b = a.child_outcome_groups.first
|
b = a.child_outcome_groups.first
|
||||||
expect(b.migration_id).to eq "bbbbbbbbbbbb"
|
expect(b.migration_id).to eq "CEB79A48-67AD-11DF-AB5F-995D9DFF4B22"
|
||||||
expect(b.title).to eq "Common Core State Standards"
|
expect(b.title).to eq "Key Ideas and Details"
|
||||||
c = b.child_outcome_groups.first
|
g = LearningOutcome.global.where(migration_id: "CEB87C92-67AD-11DF-AB5F-995D9DFF4B22").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
|
|
||||||
verify_rubric_criterion(g)
|
verify_rubric_criterion(g)
|
||||||
expect(g.short_description).to eq "K.CC.1"
|
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.1"
|
||||||
expect(g.description).to eq "Count to 100 by ones and by tens."
|
expect(g.description).to eq "Read closely to determine what the text says explicitly and to make logical" \
|
||||||
g = LearningOutcome.global.where(migration_id: "hhhhhhhhhhhhhhhh").first
|
" 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)
|
verify_rubric_criterion(g)
|
||||||
expect(g.short_description).to eq "K.CC.2"
|
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.2"
|
||||||
expect(g.description).to eq "Count forward beginning from a given number within the known sequence (instead of having to begin at 1)."
|
expect(g.description).to eq "Determine central ideas or themes of a text and analyze their development;" \
|
||||||
g = LearningOutcome.global.where(migration_id: "iiiiiiiiiiiiiiiii").first
|
" summarize the key supporting details and ideas."
|
||||||
|
g = LearningOutcome.global.where(migration_id: "CEB96684-67AD-11DF-AB5F-995D9DFF4B22").first
|
||||||
verify_rubric_criterion(g)
|
verify_rubric_criterion(g)
|
||||||
expect(g.short_description).to eq "K.CC.3"
|
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.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)."
|
expect(g.description).to eq "Analyze how and why individuals, events, and ideas develop and interact over" \
|
||||||
|
" the course of a text."
|
||||||
j = c.child_outcome_groups.where(migration_id: "jjjjjjjjjjj").first
|
g = LearningOutcome.global.where(migration_id: "CEBAB958-67AD-11DF-AB5F-995D9DFF4B22").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
|
|
||||||
verify_rubric_criterion(g)
|
verify_rubric_criterion(g)
|
||||||
expect(m.short_description).to eq "1.DD.1"
|
expect(g.short_description).to eq "CCSS.ELA-Literacy.CCRA.R.4"
|
||||||
expect(m.description).to eq "And something else"
|
expect(g.description).to eq "Interpret words and phrases as they are used in a text, including determining" \
|
||||||
expect(m.title).to eq "1.DD.1"
|
" 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
|
end
|
||||||
|
|
||||||
def check_for_parent_num_duplication(outcome)
|
def check_for_parent_num_duplication(outcome)
|
||||||
parent = outcome.instance_variable_get('@parent')
|
parent = outcome.instance_variable_get('@parent')
|
||||||
if outcome.num && parent && parent.is_standard? && parent.title && outcome.num.include?(parent.title)
|
if outcome.number && parent && parent.build_title && outcome.number.include?(parent.build_title)
|
||||||
outcome.title == "#{parent.title}.#{outcome.num}"
|
outcome.title == "#{parent.title}.#{outcome.number}"
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
@ -165,108 +170,38 @@ describe AcademicBenchmark::Converter do
|
||||||
expect(@cm.workflow_state).to eq 'failed'
|
expect(@cm.workflow_state).to eq 'failed'
|
||||||
end
|
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
|
context "using the API" do
|
||||||
append_before do
|
append_before do
|
||||||
@plugin.settings['api_key'] = "oioioi"
|
|
||||||
@cm.attachment = nil
|
@cm.attachment = nil
|
||||||
@cm.migration_settings[:no_archive_file] = true
|
@cm.migration_settings[:no_archive_file] = true
|
||||||
@cm.migration_settings[:authorities] = ["CC"]
|
@cm.migration_settings[:authorities] = ["CC"]
|
||||||
@cm.save!
|
@cm.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_and_check
|
it "should fail with no partner ID" do
|
||||||
@cm.export_content
|
@plugin.settings[:partner_id] = nil
|
||||||
run_jobs
|
@plugin.settings[:partner_key] = "a"
|
||||||
@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
|
|
||||||
@cm.export_content
|
@cm.export_content
|
||||||
run_jobs
|
run_jobs
|
||||||
@cm.reload
|
@cm.reload
|
||||||
|
|
||||||
expect(@cm.migration_issues.count).to eq 1
|
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'
|
expect(@cm.workflow_state).to eq 'failed'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should fail with an empty string API key" do
|
it "should fail with an empty string partner ID" do
|
||||||
@plugin.settings['api_key'] = ""
|
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
|
@cm.export_content
|
||||||
run_jobs
|
run_jobs
|
||||||
@cm.reload
|
@cm.reload
|
||||||
|
|
||||||
expect(@cm.migration_issues.count).to eq 1
|
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'
|
expect(@cm.workflow_state).to eq 'failed'
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# This test came about because the titles being generated for
|
# This test came about because the titles being generated for
|
||||||
|
@ -277,10 +212,28 @@ describe AcademicBenchmark::Converter do
|
||||||
#
|
#
|
||||||
# instead of this:
|
# 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
|
it "doesn't duplicate the base numbers when building a title" do
|
||||||
json_data = JSON.parse(File.read(@florida_auth_list))
|
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
|
||||||
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
|
it "requires the AcademicBenchmark config to be set" do
|
||||||
stub_ab_config_with(nil)
|
stub_ab_config_with(nil)
|
||||||
# Since :partner_key is missing above, we default to using AB API v1.
|
expect(request.call(type: request_type)["error"]).to match(/needs partner_key and partner_id/i)
|
||||||
# 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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "requires the AcademicBenchmark config api_key or partner_key to be set" do
|
context "requires the AcademicBenchmark config 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/
|
|
||||||
it "rejects a missing/nil key" do
|
it "rejects a missing/nil key" do
|
||||||
stub_ab_config_with({ "api_url" => "http://a.real.url.com" })
|
stub_ab_config_with({})
|
||||||
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
|
||||||
# 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
|
it "rejects a partner key that is the empty string" do
|
||||||
stub_ab_config_with({
|
stub_ab_config_with({
|
||||||
partner_id: "instructure",
|
partner_id: "instructure",
|
||||||
partner_key: ""
|
partner_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
|
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -391,36 +378,6 @@ describe "Outcomes Import API", type: :request do
|
||||||
end
|
end
|
||||||
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
|
def stub_ab_import
|
||||||
cm_mock = double("content_migration")
|
cm_mock = double("content_migration")
|
||||||
allow(cm_mock).to receive(:id).and_return(3)
|
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").
|
and_return(filename_to_hash("available_authorities.json").
|
||||||
map{ |a| AcademicBenchmarks::Standards::Authority.from_hash(a) })
|
map{ |a| AcademicBenchmarks::Standards::Authority.from_hash(a) })
|
||||||
allow(standards_mock).to receive(:authority_documents).
|
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").
|
and_return(filename_to_hash("national_standards_authority_docs.json").
|
||||||
map{ |d| AcademicBenchmarks::Standards::Document.from_hash(d) })
|
map{ |d| AcademicBenchmarks::Standards::Document.from_hash(d) })
|
||||||
allow(standards_mock).to receive(:authority_documents).
|
allow(standards_mock).to receive(:authority_documents).
|
||||||
|
@ -457,5 +414,3 @@ describe "Outcomes Import API", type: :request do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -98,12 +98,8 @@ module OutcomeCommon
|
||||||
|
|
||||||
def state_outcome
|
def state_outcome
|
||||||
state_outcome = [
|
state_outcome = [
|
||||||
'NGA Center/CCSSO',
|
'CCSS.ELA-Literacy.CCRA.R - Reading',
|
||||||
'Common Core State Standards',
|
'Craft and Structure'
|
||||||
'College- and Career-Readiness Standards and K-12 Mathematics',
|
|
||||||
'First Grade',
|
|
||||||
'1.DD - zééééééééééééééééééééééééééééééééééééééééééééééééé',
|
|
||||||
'Something else'
|
|
||||||
]
|
]
|
||||||
state_outcome
|
state_outcome
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,8 +40,7 @@ describe "account admin outcomes" do
|
||||||
@cm.user = @user
|
@cm.user = @user
|
||||||
@cm.save!
|
@cm.save!
|
||||||
|
|
||||||
@level_0_browse = File.join(File.dirname(__FILE__) + "/../../../gems/plugins/academic_benchmark/spec_canvas/fixtures", 'example.json')
|
@level_0_browse = File.join(File.dirname(__FILE__) + "/../../../gems/plugins/academic_benchmark/spec_canvas/fixtures", 'api_all_standards_response.json')
|
||||||
@authority_list = File.join(File.dirname(__FILE__) + "/../../../gems/plugins/academic_benchmark/spec_canvas/fixtures", 'auth_list.json')
|
|
||||||
File.open(@level_0_browse, 'r') do |file|
|
File.open(@level_0_browse, 'r') do |file|
|
||||||
@att = Attachment.create!(:filename => 'standards.json', :display_name => 'standards.json', :uploaded_data => file, :context => @cm)
|
@att = Attachment.create!(:filename => 'standards.json', :display_name => 'standards.json', :uploaded_data => file, :context => @cm)
|
||||||
end
|
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
|
it "should have state standards available for outcomes through find", priority: "2", test_id: 250008 do
|
||||||
state_outcome_setup
|
state_outcome_setup
|
||||||
goto_state_outcomes
|
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
|
end
|
||||||
|
|
||||||
it "should import state standards to course groups and all nested outcomes", priority: "2", test_id: 56584 do
|
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)
|
import_state_standards_to_account(state_outcome)
|
||||||
el1 = fj(".outcome-level:first .outcome-group .ellipsis")
|
el1 = fj(".outcome-level:first .outcome-group .ellipsis")
|
||||||
el2 = fj(".outcome-level:last .outcome-link .ellipsis")
|
el2 = fj(".outcome-level:last .outcome-link .ellipsis")
|
||||||
expect(el1).to have_attribute("title", 'Something else')
|
expect(el1).to have_attribute("title", 'Craft and Structure')
|
||||||
expect(el2).to have_attribute("title", '1.DD.1')
|
expect(el2).to have_attribute("title", 'CCSS.ELA-Literacy.CCRA.R.4')
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should import a state standard into account level", priority: "2", test_id: 56017 do
|
it "should import a state standard into account level", priority: "2", test_id: 56017 do
|
||||||
skip_if_safari(:alert)
|
skip_if_safari(:alert)
|
||||||
outcome = ['NGA Center/CCSSO']
|
outcome = ['CCSS.ELA-Literacy.CCRA.R - Reading']
|
||||||
import_state_standards_to_account(outcome)
|
import_state_standards_to_account(outcome)
|
||||||
el = fj('.outcome-level:first .outcome-group .ellipsis')
|
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
|
end
|
||||||
|
|
||||||
it "should import account outcomes into course", priority: "1", test_id: 56585 do
|
it "should import account outcomes into course", priority: "1", test_id: 56585 do
|
||||||
skip_if_safari(:alert)
|
skip_if_safari(:alert)
|
||||||
import_state_standards_to_account(state_outcome)
|
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")
|
goto_state_outcomes("/courses/#{@course.id}/outcomes")
|
||||||
traverse_nested_outcomes(outcome)
|
traverse_nested_outcomes(outcome)
|
||||||
import_account_level_outcomes
|
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
|
it "should delete state standards outcome groups from course listing", priority: "2", test_id: 250009 do
|
||||||
skip_if_safari(:alert)
|
skip_if_safari(:alert)
|
||||||
import_state_standards_to_account(state_outcome)
|
import_state_standards_to_account(state_outcome)
|
||||||
f(".ellipsis[title='Something else']").click
|
f(".ellipsis[title='Craft and Structure']").click
|
||||||
wait_for_ajaximations
|
wait_for_ajaximations
|
||||||
|
|
||||||
f('.delete_button').click
|
f('.delete_button').click
|
||||||
|
|
Loading…
Reference in New Issue