160 lines
6.4 KiB
Ruby
160 lines
6.4 KiB
Ruby
#
|
|
# Copyright (C) 2011 Instructure, Inc.
|
|
#
|
|
# This file is part of Canvas.
|
|
#
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
# Software Foundation, version 3 of the License.
|
|
#
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
class ImportedHtmlConverter
|
|
include TextHelper
|
|
def self.convert(html, context, remove_outer_nodes_if_one_child = false)
|
|
doc = Nokogiri::HTML(html || "")
|
|
attrs = ['rel', 'href', 'src', 'data', 'value']
|
|
course_path = "/#{context.class.to_s.underscore.pluralize}/#{context.id}"
|
|
doc.search("*").each do |node|
|
|
attrs.each do |attr|
|
|
if node[attr]
|
|
val = URI.unescape(node[attr])
|
|
if val =~ /wiki_page_migration_id=(.*)/
|
|
# This would be from a BB9 migration.
|
|
#todo: refactor migration systems to use new $CANVAS...$ flags
|
|
#todo: FLAG UNFOUND REFERENCES TO re-attempt in second loop?
|
|
if wiki_migration_id = $1
|
|
if linked_wiki = context.wiki.wiki_pages.find_by_migration_id(wiki_migration_id)
|
|
node[attr] = URI::escape("#{course_path}/wiki/#{linked_wiki.url}")
|
|
end
|
|
end
|
|
elsif val =~ /discussion_topic_migration_id=(.*)/
|
|
if topic_migration_id = $1
|
|
if linked_topic = context.discussion_topics.find_by_migration_id(topic_migration_id)
|
|
node[attr] = URI::escape("#{course_path}/discussion_topics/#{linked_topic.id}")
|
|
end
|
|
end
|
|
elsif val =~ %r{(?:\$CANVAS_OBJECT_REFERENCE\$|\$WIKI_REFERENCE\$)/([^/]*)/(.*)}
|
|
type = $1
|
|
migration_id = $2
|
|
type_for_url = type
|
|
type = 'context_modules' if type == 'modules'
|
|
if type == 'wiki'
|
|
if page = context.wiki.wiki_pages.find_by_url(migration_id)
|
|
node[attr] = URI::escape("#{course_path}/wiki/#{page.url}")
|
|
end
|
|
elsif type == 'attachments'
|
|
if att = context.attachments.find_by_migration_id(migration_id)
|
|
node[attr] = URI::escape("#{course_path}/files/#{att.id}/preview")
|
|
end
|
|
elsif context.respond_to?(type) && context.send(type).respond_to?(:find_by_migration_id)
|
|
if object = context.send(type).find_by_migration_id(migration_id)
|
|
node[attr] = URI::escape("#{course_path}/#{type_for_url}/#{object.id}")
|
|
end
|
|
end
|
|
elsif val =~ %r{\$CANVAS_COURSE_REFERENCE\$/(.*)}
|
|
section = $1
|
|
node[attr] = URI::escape("#{course_path}/#{section}")
|
|
elsif val =~ %r{\$IMS_CC_FILEBASE\$/(.*)}
|
|
rel_path = $1
|
|
if attr == 'href' && node['class'] && node['class'] =~ /instructure_inline_media_comment/
|
|
replace_media_comment_data(node, rel_path, context, course_path)
|
|
else
|
|
node[attr] = replace_relative_file_url(rel_path, context, course_path)
|
|
end
|
|
elsif relative_url?(node[attr])
|
|
node[attr] = replace_relative_file_url(node[attr], context, course_path)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
node = doc.at_css('body')
|
|
if remove_outer_nodes_if_one_child
|
|
node = node.child while node.children.size == 1 && node.child.child
|
|
end
|
|
node.inner_html
|
|
rescue
|
|
""
|
|
end
|
|
|
|
def self.replace_relative_file_url(rel_path, context, course_path)
|
|
new_url = nil
|
|
rel_path, qs = rel_path.split('?', 2)
|
|
# This is for backward-compatibility: canvas attachment filenames are escaped
|
|
# with '+' for spaces and older exports have files with that instead of %20
|
|
alt_rel_path = rel_path.gsub('+', ' ')
|
|
if context.respond_to?(:attachment_path_id_lookup) &&
|
|
context.attachment_path_id_lookup &&
|
|
(context.attachment_path_id_lookup[rel_path] || context.attachment_path_id_lookup[alt_rel_path])
|
|
if context.attachment_path_id_lookup[rel_path]
|
|
file = context.attachments.find_by_migration_id(context.attachment_path_id_lookup[rel_path])
|
|
else
|
|
file = context.attachments.find_by_migration_id(context.attachment_path_id_lookup[alt_rel_path])
|
|
end
|
|
if file
|
|
new_url = "/courses/#{context.id}/files/#{file.id}"
|
|
# support other params in the query string, that were exported from the
|
|
# original path components and query string. see
|
|
# CCHelper::file_query_string
|
|
params = Rack::Utils.parse_nested_query(qs.presence || "")
|
|
qs = []
|
|
params.each do |k,v|
|
|
case k
|
|
when /canvas_qs_(.*)/
|
|
qs << "#{Rack::Utils.escape($1)}=#{Rack::Utils.escape(v)}"
|
|
when /canvas_(.*)/
|
|
new_url += "/#{$1}"
|
|
end
|
|
end
|
|
new_url += "?#{qs.join("&")}" if qs.present?
|
|
if params.blank?
|
|
new_url += "/preview"
|
|
end
|
|
end
|
|
end
|
|
unless new_url
|
|
# the rel_path should already be escaped
|
|
new_url = URI::escape("#{course_path}/file_contents/#{Folder.root_folders(context).first.name}/") + rel_path
|
|
end
|
|
new_url
|
|
end
|
|
|
|
def self.replace_media_comment_data(node, rel_path, context, course_path)
|
|
if context.respond_to?(:attachment_path_id_lookup) &&
|
|
context.attachment_path_id_lookup &&
|
|
context.attachment_path_id_lookup[rel_path]
|
|
file = context.attachments.find_by_migration_id(context.attachment_path_id_lookup[rel_path])
|
|
if file && file.media_object
|
|
media_id = file.media_object.media_id
|
|
node['href'] = "/media_objects/#{media_id}"
|
|
node['id'] = "media_comment_#{media_id}"
|
|
return
|
|
end
|
|
end
|
|
node['href'] = replace_relative_file_url(rel_path, context, course_path)
|
|
node.delete('class')
|
|
node.delete('id')
|
|
node.delete('style')
|
|
end
|
|
|
|
def self.relative_url?(url)
|
|
(url.match(/[\/#\?]/) || (url.match(/\./) && !url.match(/@/))) && !url.match(/\A\w+:/) && !url.match(/\A\//)
|
|
end
|
|
|
|
def self.convert_text(text, context, import_source=:webct)
|
|
instance.format_message(text || "")[0]
|
|
end
|
|
|
|
def self.instance
|
|
@@instance ||= self.new
|
|
end
|
|
end
|