prevent locked content in ePub from redirecting to Canvas web

fixes CNVS-25569

test plan:
- have a module in a course locked by prerequisites
- embed a link to that module in the description of a course item
- export the ePub
- the link to that module should direct to its proper location in
  the ePub instead of Canvas web
- all other behaviors should be unchanged regarding locked content

Change-Id: I12f9897e73d68ac12c8956fe9231ce35962661ff
Reviewed-on: https://gerrit.instructure.com/69759
Tested-by: Jenkins
Reviewed-by: John Corrigan <jcorrigan@instructure.com>
QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com>
Product-Review: Matt Berns <mberns@instructure.com>
This commit is contained in:
Matthew Berns 2016-01-05 18:07:03 -06:00 committed by Matt Berns
parent 14c8e6a250
commit 1c81f17b5c
5 changed files with 67 additions and 29 deletions

View File

@ -22,7 +22,7 @@ module CC
include TextHelper
ZIP_DIR = 'zip_dir'
attr_accessor :course, :user, :export_dir, :manifest, :zip_file, :for_course_copy
delegate :add_error, :add_item_to_export, :to => :@content_export, :allow_nil => true
@ -61,7 +61,7 @@ module CC
@manifest.close
copy_all_to_zip
@zip_file.close
if @content_export && File.exist?(@zip_path)
att = Attachment.new
att.context = @content_export
@ -88,15 +88,15 @@ module CC
def referenced_files
@manifest ? @manifest.referenced_files : {}
end
def set_progress(progress)
@content_export.fast_update_progress(progress) if @content_export
@content_export.fast_update_progress(progress) if @content_export
end
def errors
@content_export ? @content_export.error_messages : []
end
def export_id
@content_export ? @content_export.id : nil
end
@ -108,9 +108,13 @@ module CC
def export_symbol?(obj)
@content_export ? @content_export.export_symbol?(obj) : true
end
def epub_export?
@content_export ? @content_export.epub_export.present? : nil
end
private
def copy_all_to_zip
Dir["#{@export_dir}/**/**"].each do |file|
file_path = file.sub(@export_dir+'/', '')

View File

@ -20,24 +20,24 @@ require 'nokogiri'
module CC
module CCHelper
CANVAS_NAMESPACE = 'http://canvas.instructure.com/xsd/cccv1p0'
XSD_URI = 'http://canvas.instructure.com/xsd/cccv1p0.xsd'
# IMS formats/types
IMS_DATE = "%Y-%m-%d"
IMS_DATETIME = "%Y-%m-%dT%H:%M:%S"
CC_EXTENSION = 'imscc'
QTI_EXTENSION = ".xml.qti"
CANVAS_PLATFORM = 'canvas.instructure.com'
# Common Cartridge 1.0
# associatedcontent/imscc_xmlv1p0/learning-application-resource
# imsdt_xmlv1p0
# imswl_xmlv1p0
# imsqti_xmlv1p2/imscc_xmlv1p0/assessment
# imsqti_xmlv1p2/imscc_xmlv1p0/question-bank
# Common Cartridge 1.1 (What Canvas exports)
ASSESSMENT_TYPE = 'imsqti_xmlv1p2/imscc_xmlv1p1/assessment'
QUESTION_BANK = 'imsqti_xmlv1p2/imscc_xmlv1p1/question-bank'
@ -47,7 +47,7 @@ module CCHelper
WEBCONTENT = "webcontent"
BASIC_LTI = 'imsbasiclti_xmlv1p0'
BLTI_NAMESPACE = "http://www.imsglobal.org/xsd/imsbasiclti_v1p0"
# Common Cartridge 1.2
# associatedcontent/imscc_xmlv1p2/learning-application-resource
# imsdt_xmlv1p2
@ -63,7 +63,7 @@ module CCHelper
# QTI-only export
QTI_ASSESSMENT_TYPE = 'imsqti_xmlv1p2'
# substitution tokens
OBJECT_TOKEN = "$CANVAS_OBJECT_REFERENCE$"
COURSE_TOKEN = "$CANVAS_COURSE_REFERENCE$"
@ -98,15 +98,15 @@ module CCHelper
def create_key(object, prepend="")
CCHelper.create_key(object, prepend)
end
def ims_date(date=nil)
CCHelper.ims_date(date)
end
def ims_datetime(date=nil)
CCHelper.ims_datetime(date)
end
def self.create_key(object, prepend="")
if object.is_a? ActiveRecord::Base
key = object.asset_string
@ -115,17 +115,17 @@ module CCHelper
end
"i" + Digest::MD5.hexdigest(prepend + key)
end
def self.ims_date(date=nil)
date ||= Time.now
date.respond_to?(:utc) ? date.utc.strftime(IMS_DATE) : date.strftime(IMS_DATE)
end
def self.ims_datetime(date=nil)
date ||= Time.now
date.respond_to?(:utc) ? date.utc.strftime(IMS_DATETIME) : date.strftime(IMS_DATETIME)
end
def get_html_title_and_body_and_id(doc)
id = get_node_val(doc, 'html head meta[name=identifier] @content')
get_html_title_and_body(doc) << id
@ -140,7 +140,7 @@ module CCHelper
end
get_html_title_and_body(doc) << meta_fields
end
def get_html_title_and_body(doc)
title = get_node_val(doc, 'html head title')
body = doc.at_css('html body').to_s.gsub(%r{</?body>}, '').strip
@ -161,6 +161,7 @@ module CCHelper
@user = user
@track_referenced_files = opts[:track_referenced_files]
@for_course_copy = opts[:for_course_copy]
@for_epub_export = opts[:for_epub_export]
@referenced_files = {}
@rewriter.set_handler('file_contents') do |match|
@ -220,7 +221,7 @@ module CCHelper
new_url = match.url
if match.obj_id && match.obj_class
obj = match.obj_class.where(id: match.obj_id).first
if obj && @rewriter.user_can_view_content?(obj)
if obj && (@rewriter.user_can_view_content?(obj) || @for_epub_export)
# for all other types,
# create a migration id for the object, and use that as the new link
migration_id = CCHelper.create_key(obj)

View File

@ -9,7 +9,7 @@
#
# 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
# 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
@ -27,7 +27,7 @@ module CC
include WebResources
include WebLinks
include BasicLTILinks
delegate :add_error, :set_progress, :export_object?, :export_symbol?, :for_course_copy, :add_item_to_export, :to => :@manifest
delegate :referenced_files, :to => :@html_exporter
@ -44,16 +44,17 @@ module CC
@html_exporter = CCHelper::HtmlContentExporter.new(@course,
@manifest.exporter.user,
:for_course_copy => for_course_copy,
:for_epub_export => @manifest.exporter.epub_export?,
:track_referenced_files => true,
:media_object_flavor => Setting.get('exporter_media_object_flavor', nil).presence)
end
def self.create_resources(manifest, manifest_node)
r = new(manifest, manifest_node)
r.create_resources
r
end
def create_resources
@manifest_node.resources do |resources|
@resources = resources
@ -87,6 +88,6 @@ module CC
set_progress(progress) if progress
res
end
end
end

View File

@ -570,6 +570,38 @@ describe "Common Cartridge exporting" do
check_resource_node(@published, CC::CCHelper::LOR)
check_resource_node(@unpublished, CC::CCHelper::LOR, false)
end
it "should always use relevant migration ids in anchor tags when exporting for ePub" do
cm1 = @course.context_modules.create!(name: "unlocked module")
cm1.publish
cm2 = @course.context_modules.create!({
name: "locked module",
prerequisites: [{:id=>cm1.id, :type=>"context_module", :name=>cm1.name}]
})
cm2.publish
cm1link = %{<a href="/courses/#{@course.id}/modules/#{cm1.id}">Mod 1</a>}
cm2link = %{<a href="/courses/#{@course.id}/modules/#{cm2.id}">Mod 2</a>}
assignment = @course.assignments.create!({
title: 'Assignment 1',
description: "go to module 1 at #{cm1link} and module 2 at #{cm2link}"
})
cm1.completion_requirements = [{:id=>assignment.id, :type=>"must_mark_done"}]
cm1.save!
student_in_course(active_all: true, user_name: "a student")
@ce.epub_export = EpubExport.create!({course: @course})
@ce.user = @student
@ce.save!
run_export
assignment_html = @manifest_doc.at_css("file[href$='#{mig_id(assignment)}/assignment-1.html']")
html_content = @zip_file.read(assignment_html["href"])
expect(html_content.match(/\$CANVAS_OBJECT_REFERENCE\$\/modules\/#{mig_id(cm1)}/)).not_to be_nil
expect(html_content.match(/\$CANVAS_OBJECT_REFERENCE\$\/modules\/#{mig_id(cm2)}/)).not_to be_nil
end
end
context 'attachment permissions' do

View File

@ -15,13 +15,13 @@ describe "Exporter" do
@attachment = Attachment.create({
context: course,
filename: 'exortable-test-file',
filename: 'exportable-test-file',
uploaded_data: File.open(cartridge_path)
})
@attachment_without_modules = Attachment.create({
context: course,
filename: 'exortable-test-file',
filename: 'exportable-test-file',
uploaded_data: File.open(cartridge_without_modules_path)
})