canvas_link_migrator 1.0.9 → 1.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/canvas_link_migrator/link_parser.rb +4 -10
- data/lib/canvas_link_migrator/link_resolver.rb +36 -18
- data/lib/canvas_link_migrator/resource_map_service.rb +13 -13
- data/lib/canvas_link_migrator/version.rb +1 -1
- data/spec/canvas_link_migrator/imported_html_converter_spec.rb +151 -117
- data/spec/canvas_link_migrator/link_resolver_spec.rb +4 -4
- data/spec/fixtures/canvas_resource_map.json +21 -10
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7cbc11edecf38395bcf3dfda752a5a2946e9f691f86f95f35d80fe12a28f228
|
4
|
+
data.tar.gz: d55a7c3509ce6da3b423e20b119f17ad5dbfd61f32d8f4f6a926ae0e84da343f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f54e3e63f1a47b50f0568bfcfce57f2b15c59a7097e7ea4fde9a89433554cba0a24bc60a854e267d2efab49c4cceec532d2c3a99e2b2b779cadbcc379a0c349
|
7
|
+
data.tar.gz: 5b290e62a21a044efea17939e03ab3cd197e9acf7030fda2683b8f4c9a0033ef4ff72fa5f82b8dfe09affb1f3a86d8c4c55c21ef853768b93e16a6f19041a0ac
|
@@ -19,7 +19,6 @@
|
|
19
19
|
|
20
20
|
require "nokogiri"
|
21
21
|
require "digest"
|
22
|
-
require "addressable"
|
23
22
|
|
24
23
|
module CanvasLinkMigrator
|
25
24
|
class LinkParser
|
@@ -85,7 +84,7 @@ module CanvasLinkMigrator
|
|
85
84
|
doc = Nokogiri::HTML5.fragment(html || "")
|
86
85
|
|
87
86
|
# Replace source tags with iframes
|
88
|
-
doc.search("source[data-media-id]").each do |source|
|
87
|
+
doc.search("source[data-media-type],source[data-media-id]").each do |source|
|
89
88
|
next unless RCE_MEDIA_TYPES.include?(source.parent.name)
|
90
89
|
|
91
90
|
media_node = source.parent
|
@@ -144,12 +143,7 @@ module CanvasLinkMigrator
|
|
144
143
|
url.gsub!("%24#{ref}%24", "$#{ref}$")
|
145
144
|
end
|
146
145
|
|
147
|
-
|
148
|
-
result = parse_url(url, node, attr)
|
149
|
-
rescue Addressable::URI::InvalidURIError
|
150
|
-
return
|
151
|
-
end
|
152
|
-
|
146
|
+
result = parse_url(url, node, attr)
|
153
147
|
if result[:resolved]
|
154
148
|
# resolved, just replace and carry on
|
155
149
|
new_url = result[:new_url] || url
|
@@ -238,12 +232,12 @@ module CanvasLinkMigrator
|
|
238
232
|
elsif url =~ %r{\$IMS(?:-|_)CC(?:-|_)FILEBASE\$/(.*)}
|
239
233
|
rel_path = URI::DEFAULT_PARSER.unescape($1)
|
240
234
|
if (attr == "href" && node["class"]&.include?("instructure_inline_media_comment")) ||
|
241
|
-
(attr == "src" && ["iframe", "source"].include?(node.name)
|
235
|
+
(attr == "src" && ["iframe", "source"].include?(node.name))
|
242
236
|
unresolved(:media_object, rel_path: rel_path)
|
243
237
|
else
|
244
238
|
unresolved(:file, rel_path: rel_path)
|
245
239
|
end
|
246
|
-
elsif (attr == "src" && ["iframe", "source"].include?(node.name) && node["data-media-id"])
|
240
|
+
elsif (attr == "src" && ["iframe", "source"].include?(node.name) && (node["data-media-id"] || node["data-media-type"]))
|
247
241
|
# media_objects_iframe course copy reference without an attachment id, change to media_attachments_iframe
|
248
242
|
unresolved(:media_object, rel_path: node["src"])
|
249
243
|
elsif @migration_query_service.supports_embedded_images && attr == "src" && (info_match = url.match(%r{\Adata:(?<mime_type>[-\w]+/[-\w+.]+)?;base64,(?<image>.*)}m))
|
@@ -18,6 +18,7 @@
|
|
18
18
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
20
|
require "active_support/core_ext/object"
|
21
|
+
require "addressable"
|
21
22
|
require "rack"
|
22
23
|
|
23
24
|
module CanvasLinkMigrator
|
@@ -44,6 +45,14 @@ module CanvasLinkMigrator
|
|
44
45
|
@attachment_path_id_lookup_lower ||= attachment_path_id_lookup&.transform_keys(&:downcase)
|
45
46
|
end
|
46
47
|
|
48
|
+
def add_verifier_to_query(url, uuid)
|
49
|
+
parsed_url = Addressable::URI.parse(url)
|
50
|
+
parsed_url.query_values = (parsed_url.query_values || {}).merge("verifier" => uuid)
|
51
|
+
parsed_url.to_s
|
52
|
+
rescue Addressable::InvalidURIError
|
53
|
+
url
|
54
|
+
end
|
55
|
+
|
47
56
|
# finds the :new_value to use to replace the placeholder
|
48
57
|
def resolve_link!(link)
|
49
58
|
case link[:link_type]
|
@@ -71,13 +80,17 @@ module CanvasLinkMigrator
|
|
71
80
|
linked_wiki_url = @migration_id_converter.convert_wiki_page_migration_id_to_slug(migration_id) || migration_id
|
72
81
|
link[:new_value] = "#{context_path}/pages/#{linked_wiki_url}#{query}"
|
73
82
|
elsif type == "attachments"
|
74
|
-
att_id = @migration_id_converter.convert_attachment_migration_id(migration_id)
|
83
|
+
att_id, uuid = @migration_id_converter.convert_attachment_migration_id(migration_id)
|
75
84
|
if att_id
|
76
|
-
|
85
|
+
new_url = "#{context_path}/files/#{att_id}/preview"
|
86
|
+
new_url = add_verifier_to_query(new_url, uuid) if uuid
|
87
|
+
link[:new_value] = new_url
|
77
88
|
end
|
78
89
|
elsif type == "media_attachments_iframe"
|
79
|
-
att_id = @migration_id_converter.convert_attachment_migration_id(migration_id)
|
80
|
-
|
90
|
+
att_id, uuid = @migration_id_converter.convert_attachment_migration_id(migration_id)
|
91
|
+
new_url = att_id ? "/media_attachments_iframe/#{att_id}#{link[:query]}" : link[:old_value]
|
92
|
+
new_url = add_verifier_to_query(new_url, uuid) if uuid
|
93
|
+
link[:new_value] = new_url
|
81
94
|
else
|
82
95
|
object_id = @migration_id_converter.convert_migration_id(type, migration_id)
|
83
96
|
if object_id
|
@@ -116,7 +129,7 @@ module CanvasLinkMigrator
|
|
116
129
|
end
|
117
130
|
link[:new_value] = new_url
|
118
131
|
when :file_ref
|
119
|
-
file_id = @migration_id_converter.convert_attachment_migration_id(link[:migration_id])
|
132
|
+
file_id, uuid = @migration_id_converter.convert_attachment_migration_id(link[:migration_id])
|
120
133
|
if file_id
|
121
134
|
rest = link[:rest].presence
|
122
135
|
rest ||= "/preview" unless link[:target_blank]
|
@@ -125,13 +138,15 @@ module CanvasLinkMigrator
|
|
125
138
|
# context prepended to the URL. This prevents
|
126
139
|
# redirects to non cross-origin friendly urls
|
127
140
|
# during a file fetch
|
128
|
-
if rest&.include?("icon_maker_icon=1")
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
141
|
+
new_url = if rest&.include?("icon_maker_icon=1")
|
142
|
+
"/files/#{file_id}#{rest}"
|
143
|
+
elsif link[:in_media_iframe]
|
144
|
+
"/media_attachments_iframe/#{file_id}#{rest}"
|
145
|
+
else
|
146
|
+
"#{context_path}/files/#{file_id}#{rest}"
|
147
|
+
end
|
148
|
+
new_url = add_verifier_to_query(new_url, uuid) if uuid
|
149
|
+
link[:new_value] = new_url
|
135
150
|
else
|
136
151
|
link[:missing_url] = link[:old_value].partition("$CANVAS_COURSE_REFERENCE$").last
|
137
152
|
end
|
@@ -200,6 +215,7 @@ module CanvasLinkMigrator
|
|
200
215
|
# CCHelper::file_query_string
|
201
216
|
params = Rack::Utils.parse_nested_query(qs.presence || "")
|
202
217
|
qs = []
|
218
|
+
qs << "verifier=#{file["uuid"]}" if file["uuid"].present?
|
203
219
|
new_action = ""
|
204
220
|
params.each do |k, v|
|
205
221
|
case k
|
@@ -217,23 +233,25 @@ module CanvasLinkMigrator
|
|
217
233
|
new_url
|
218
234
|
end
|
219
235
|
|
220
|
-
def media_attachment_iframe_url(file_id, media_type = nil)
|
236
|
+
def media_attachment_iframe_url(file_id, uuid = nil, media_type = nil)
|
221
237
|
url = "/media_attachments_iframe/#{file_id}?embedded=true"
|
222
238
|
url += "&type=#{media_type}" if media_type.present?
|
239
|
+
url += "&verifier=#{uuid}" if uuid.present?
|
223
240
|
url
|
224
241
|
end
|
225
242
|
|
226
243
|
def resolve_media_data(node, rel_path)
|
227
244
|
if rel_path && (file = find_file_in_context(rel_path[/^[^?]+/])) # strip query string for this search
|
228
|
-
media_id = file
|
245
|
+
media_id = file["media_entry_id"]
|
229
246
|
node["data-media-id"] = media_id # safe to delete?
|
230
|
-
media_attachment_iframe_url(file["id"], node["data-media-type"])
|
247
|
+
media_attachment_iframe_url(file["id"], file["uuid"], node["data-media-type"])
|
231
248
|
elsif rel_path&.match(/\/media_attachments_iframe\/\d+/)
|
232
249
|
# media attachment from another course or something
|
233
250
|
rel_path
|
234
|
-
elsif node["data-media-id"]
|
235
|
-
|
236
|
-
|
251
|
+
elsif (file_id, uuid = @migration_id_converter.convert_attachment_media_id(node["data-media-id"]))
|
252
|
+
file_id ? media_attachment_iframe_url(file_id, uuid, node["data-media-type"]) : nil
|
253
|
+
elsif (file_id, uuid = @migration_id_converter.convert_attachment_media_id(rel_path.match(/media_objects(?:_iframe)?\/([^?.]+)/)&.[](1)))
|
254
|
+
file_id ? media_attachment_iframe_url(file_id, uuid, node["data-media-type"]) : nil
|
237
255
|
else
|
238
256
|
node.delete("class")
|
239
257
|
node.delete("id")
|
@@ -89,7 +89,19 @@ module CanvasLinkMigrator
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def convert_attachment_migration_id(migration_id)
|
92
|
-
resources.dig("files", migration_id, "destination", "
|
92
|
+
resources.dig("files", migration_id, "destination")&.slice("id", "uuid")&.values
|
93
|
+
end
|
94
|
+
|
95
|
+
def media_map
|
96
|
+
@media_map ||= resources["files"].each_with_object({}) do |(_mig_id, file), map|
|
97
|
+
media_id = file.dig("destination", "media_entry_id")
|
98
|
+
next unless media_id
|
99
|
+
map[media_id] = file
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def convert_attachment_media_id(media_id)
|
104
|
+
media_map.dig(media_id, "destination")&.slice("id", "uuid")&.values
|
93
105
|
end
|
94
106
|
|
95
107
|
def convert_migration_id(type, migration_id)
|
@@ -106,17 +118,5 @@ module CanvasLinkMigrator
|
|
106
118
|
def lookup_attachment_by_migration_id(migration_id)
|
107
119
|
resources.dig("files", migration_id, "destination")
|
108
120
|
end
|
109
|
-
|
110
|
-
def media_map
|
111
|
-
@media_map ||= resources["files"].each_with_object({}) do |(_mig_id, file), map|
|
112
|
-
media_id = file.dig("destination", "media_entry_id")
|
113
|
-
next unless media_id
|
114
|
-
map[media_id] = file
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def lookup_attachment_by_media_id(media_id)
|
119
|
-
media_map.dig(media_id, "destination")
|
120
|
-
end
|
121
121
|
end
|
122
122
|
end
|
@@ -75,7 +75,7 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
75
75
|
it "converts data-download-url for files without appending a context" do
|
76
76
|
html, bad_links = subject
|
77
77
|
expect(html).to eq(
|
78
|
-
"<img src=\"#{@path}files/5/download?download_frd=1\" alt=\"\" data-inst-icon-maker-icon=\"true\" data-download-url=\"/files/5/download?download_frd=1&icon_maker_icon=1\">"
|
78
|
+
"<img src=\"#{@path}files/5/download?download_frd=1&verifier=u5\" alt=\"\" data-inst-icon-maker-icon=\"true\" data-download-url=\"/files/5/download?download_frd=1&icon_maker_icon=1&verifier=u5\">"
|
79
79
|
)
|
80
80
|
expect(bad_links).to be_nil
|
81
81
|
end
|
@@ -83,7 +83,7 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
83
83
|
|
84
84
|
it "finds an attachment by migration id" do
|
85
85
|
test_string = %{<p>This is an image: <br /><img src="%24CANVAS_OBJECT_REFERENCE%24/attachments/F" alt=":(" /></p>}
|
86
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/6/preview" alt=":("></p>}, nil])
|
86
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/6/preview?verifier=u6" alt=":("></p>}, nil])
|
87
87
|
end
|
88
88
|
|
89
89
|
it "leaves relative user attachments alone" do
|
@@ -106,20 +106,20 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
106
106
|
expect(bad_links[0]).to include({ link_type: :file, missing_url: "/courses/2/file_contents/course%20files/test.png" })
|
107
107
|
|
108
108
|
expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_call_original
|
109
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/5/preview" alt=":("></p>}, nil])
|
109
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/5/preview?verifier=u5" alt=":("></p>}, nil])
|
110
110
|
end
|
111
111
|
|
112
112
|
it "finds an attachment by a path with a space" do
|
113
113
|
test_string = %(<img src="subfolder/with%20a%20space/test.png" alt="nope" />)
|
114
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
|
114
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview?verifier=u6" alt="nope">), nil])
|
115
115
|
|
116
116
|
test_string = %(<img src="subfolder/with+a+space/test.png" alt="nope" />)
|
117
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
|
117
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview?verifier=u6" alt="nope">), nil])
|
118
118
|
end
|
119
119
|
|
120
120
|
it "finds an attachment even if the link has an extraneous folder" do
|
121
121
|
test_string = %(<img src="anotherfolder/subfolder/test.png" alt="nope" />)
|
122
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/7/preview" alt="nope">), nil])
|
122
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/7/preview?verifier=u7" alt="nope">), nil])
|
123
123
|
end
|
124
124
|
|
125
125
|
it "finds an attachment by path if capitalization is different" do
|
@@ -127,18 +127,18 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
127
127
|
expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_return({ "subfolder/withcapital/test.png" => "F" })
|
128
128
|
|
129
129
|
test_string = %(<img src="subfolder/WithCapital/TEST.png" alt="nope" />)
|
130
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
|
130
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview?verifier=u6" alt="nope">), nil])
|
131
131
|
end
|
132
132
|
|
133
133
|
it "finds an attachment with query params" do
|
134
134
|
test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?canvas_customaction=1&canvas_qs_customparam=1" alt="nope" />)
|
135
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/customaction?customparam=1" alt="nope">), nil])
|
135
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/customaction?verifier=u5&customparam=1" alt="nope">), nil])
|
136
136
|
|
137
137
|
test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?canvas_qs_customparam2=3" alt="nope" />)
|
138
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview?customparam2=3" alt="nope">), nil])
|
138
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview?verifier=u5&customparam2=3" alt="nope">), nil])
|
139
139
|
|
140
140
|
test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?notarelevantparam" alt="nope" />)
|
141
|
-
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview" alt="nope">), nil])
|
141
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview?verifier=u5" alt="nope">), nil])
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -210,130 +210,164 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
210
210
|
expect(bad_links[0]).to include({ link_type: :file, missing_url: "/courses/2/file_contents/course%20files/relative/path/to/file%20with%20space.html" })
|
211
211
|
end
|
212
212
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
213
|
+
context "with media links" do
|
214
|
+
it "changes old media URL types into media_attachments_iframe" do
|
215
|
+
test_string = <<~HTML.strip
|
216
|
+
<p>
|
217
|
+
with media object url: <a id="media_comment_m-stuff" class="instructure_inline_media_comment video_comment" href="/media_objects/m-stuff">this is a media comment</a>
|
218
|
+
with file content url: <a id="media_comment_0_bq09qam2" class="instructure_inline_media_comment video_comment" href="/courses/2/file_contents/course%20files/media_objects/0_bq09qam2">this is a media comment</a>
|
219
|
+
with mediahref url: <iframe data-media-type="video" src="/media_objects_iframe?mediahref=$CANVAS_COURSE_REFERENCE$/file_ref/I/download" data-media-id="m-yodawg"></iframe>
|
220
|
+
</p>
|
221
|
+
HTML
|
222
|
+
|
223
|
+
expected_string = <<~HTML.strip
|
224
|
+
<p>
|
225
|
+
with media object url: <iframe id="media_comment_m-stuff" class="instructure_inline_media_comment video_comment" style="width: 320px; height: 240px; display: inline-block;" title="this is a media comment" data-media-type="video" src="/media_attachments_iframe/5?embedded=true&type=video&verifier=u5" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-stuff"></iframe>
|
226
|
+
with file content url: <iframe id="media_comment_0_bq09qam2" class="instructure_inline_media_comment video_comment" style="width: 320px; height: 240px; display: inline-block;" title="this is a media comment" data-media-type="video" src="/media_attachments_iframe/6?embedded=true&type=video&verifier=u6" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="0_bq09qam2"></iframe>
|
227
|
+
with mediahref url: <iframe data-media-type="video" src="/media_attachments_iframe/9?embedded=true&type=video&verifier=u9" data-media-id="m-yodawg"></iframe>
|
228
|
+
</p>
|
229
|
+
HTML
|
230
|
+
|
231
|
+
expect(@converter.convert_exported_html(test_string)).to eq([expected_string, nil])
|
232
|
+
end
|
221
233
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
HTML
|
234
|
+
it "finds attachments for media_object_iframes that don't have valid data-media-ids" do
|
235
|
+
test_string = <<~HTML.strip
|
236
|
+
<p>
|
237
|
+
in video format: <video style="width: 599px; height: 337px; display: inline-block;" title="0_bq09qam2" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="undefined"><source src="/media_objects_iframe/0_bq09qam2?type=video?type=video" data-media-id="undefined" data-media-type="video"></video>
|
238
|
+
</p>
|
239
|
+
HTML
|
229
240
|
|
230
|
-
|
231
|
-
|
241
|
+
expected_string = <<~HTML.strip
|
242
|
+
<p>
|
243
|
+
in video format: <iframe style="width: 599px; height: 337px; display: inline-block;" title="0_bq09qam2" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="undefined" src="/media_attachments_iframe/6?embedded=true&type=video&verifier=u6"></iframe>
|
244
|
+
</p>
|
245
|
+
HTML
|
232
246
|
|
233
|
-
|
234
|
-
|
235
|
-
<p>
|
236
|
-
with media object url: <a id="media_comment_m-stuff1" class="instructure_inline_media_comment video_comment" href="/media_objects/m-stuff1">this is a media comment</a>
|
237
|
-
with file content url: <a id="media_comment_0_bq09qam3" class="instructure_inline_media_comment video_comment" href="/courses/2/file_contents/course%20files/media_objects/0_bq09qam3">this is a media comment</a>
|
238
|
-
with mediahref url: <iframe data-media-type="video" src="/media_objects_iframe?mediahref=$CANVAS_COURSE_REFERENCE$/file_ref/yarg/download" data-media-id="m-yodawg"></iframe>
|
239
|
-
</p>
|
240
|
-
HTML
|
247
|
+
expect(@converter.convert_exported_html(test_string)).to eq([expected_string, nil])
|
248
|
+
end
|
241
249
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
HTML
|
250
|
+
it "finds attachments for media_object_iframes that don't have data-media-ids" do
|
251
|
+
test_string = <<~HTML.strip
|
252
|
+
<p>
|
253
|
+
in video format: <video style="width: 599px; height: 337px; display: inline-block;" title="0_bq09qam2" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen"><source src="/media_objects_iframe/0_bq09qam2?type=video?type=video" data-media-id="undefined" data-media-type="video"></video>
|
254
|
+
</p>
|
255
|
+
HTML
|
249
256
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
{
|
256
|
-
link_type: :media_object,
|
257
|
-
missing_url: "/courses/2/file_contents/course%20files/media_objects/0_bq09qam3"
|
258
|
-
},
|
259
|
-
{
|
260
|
-
link_type: :file_ref, missing_url: "/file_ref/yarg/download"
|
261
|
-
}
|
262
|
-
]
|
263
|
-
expect(@converter.convert_exported_html(test_string)).to eq([expected_string, expected_errors])
|
264
|
-
end
|
257
|
+
expected_string = <<~HTML.strip
|
258
|
+
<p>
|
259
|
+
in video format: <iframe style="width: 599px; height: 337px; display: inline-block;" title="0_bq09qam2" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" src="/media_attachments_iframe/6?embedded=true&type=video&verifier=u6"></iframe>
|
260
|
+
</p>
|
261
|
+
HTML
|
265
262
|
|
266
|
-
|
267
|
-
|
268
|
-
<p>
|
269
|
-
with wrong file in href: <a href="/courses/2/file_contents/%24IMS_CC_FILEBASE%24/#" class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff">this is a media comment</a><br><br>
|
270
|
-
with no href: <a class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff" href="#"></a><br><br>
|
271
|
-
</p>
|
272
|
-
HTML
|
273
|
-
expected_string = <<~HTML.strip
|
274
|
-
<p>
|
275
|
-
with wrong file in href: <iframe class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff" style="width: 320px; height: 240px; display: inline-block;" title="this is a media comment" data-media-type="video" src="/media_attachments_iframe/5?embedded=true&type=video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-stuff"></iframe><br><br>
|
276
|
-
with no href: <iframe class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff" style="width: 320px; height: 240px; display: inline-block;" title="" data-media-type="video" src="/media_attachments_iframe/5?embedded=true&type=video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-stuff"></iframe><br><br>
|
277
|
-
</p>
|
278
|
-
HTML
|
279
|
-
expect(@converter.convert_exported_html(test_string)).to eq([expected_string, nil])
|
280
|
-
end
|
263
|
+
expect(@converter.convert_exported_html(test_string)).to eq([expected_string, nil])
|
264
|
+
end
|
281
265
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
266
|
+
it "handles old media types where we can't find the file" do
|
267
|
+
test_string = <<~HTML.strip
|
268
|
+
<p>
|
269
|
+
with media object url: <a id="media_comment_m-stuff1" class="instructure_inline_media_comment video_comment" href="/media_objects/m-stuff1">this is a media comment</a>
|
270
|
+
with file content url: <a id="media_comment_0_bq09qam3" class="instructure_inline_media_comment video_comment" href="/courses/2/file_contents/course%20files/media_objects/0_bq09qam3">this is a media comment</a>
|
271
|
+
with mediahref url: <iframe data-media-type="video" src="/media_objects_iframe?mediahref=$CANVAS_COURSE_REFERENCE$/file_ref/yarg/download" data-media-id="m-yodawg"></iframe>
|
272
|
+
</p>
|
273
|
+
HTML
|
274
|
+
|
275
|
+
expected_string = <<~HTML.strip
|
276
|
+
<p>
|
277
|
+
with media object url: <iframe title="this is a media comment" data-media-type="video" src="/courses/2/file_contents/course%20files/media_objects/m-stuff1" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-stuff1"></iframe>
|
278
|
+
with file content url: <iframe title="this is a media comment" data-media-type="video" src="/courses/2/file_contents/course%20files/media_objects/0_bq09qam3" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="0_bq09qam3"></iframe>
|
279
|
+
with mediahref url: <iframe data-media-type="video" src="/media_objects_iframe?mediahref=$CANVAS_COURSE_REFERENCE$/file_ref/yarg/download" data-media-id="m-yodawg"></iframe>
|
280
|
+
</p>
|
281
|
+
HTML
|
282
|
+
|
283
|
+
expected_errors = [
|
284
|
+
{
|
285
|
+
link_type: :media_object,
|
286
|
+
missing_url: "/courses/2/file_contents/course%20files/media_objects/m-stuff1"
|
287
|
+
},
|
288
|
+
{
|
289
|
+
link_type: :media_object,
|
290
|
+
missing_url: "/courses/2/file_contents/course%20files/media_objects/0_bq09qam3"
|
291
|
+
},
|
292
|
+
{
|
293
|
+
link_type: :file_ref, missing_url: "/file_ref/yarg/download"
|
294
|
+
}
|
295
|
+
]
|
296
|
+
expect(@converter.convert_exported_html(test_string)).to eq([expected_string, expected_errors])
|
297
|
+
end
|
287
298
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
299
|
+
it "handles and repair half broken media links" do
|
300
|
+
test_string = <<~HTML.strip
|
301
|
+
<p>
|
302
|
+
with wrong file in href: <a href="/courses/2/file_contents/%24IMS_CC_FILEBASE%24/#" class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff">this is a media comment</a><br><br>
|
303
|
+
with no href: <a class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff" href="#"></a><br><br>
|
304
|
+
</p>
|
305
|
+
HTML
|
306
|
+
expected_string = <<~HTML.strip
|
307
|
+
<p>
|
308
|
+
with wrong file in href: <iframe class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff" style="width: 320px; height: 240px; display: inline-block;" title="this is a media comment" data-media-type="video" src="/media_attachments_iframe/5?embedded=true&type=video&verifier=u5" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-stuff"></iframe><br><br>
|
309
|
+
with no href: <iframe class="instructure_inline_media_comment video_comment" id="media_comment_m-stuff" style="width: 320px; height: 240px; display: inline-block;" title="" data-media-type="video" src="/media_attachments_iframe/5?embedded=true&type=video&verifier=u5" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-stuff"></iframe><br><br>
|
310
|
+
</p>
|
311
|
+
HTML
|
312
|
+
expect(@converter.convert_exported_html(test_string)).to eq([expected_string, nil])
|
313
|
+
end
|
293
314
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
315
|
+
it "converts old RCE media object iframes" do
|
316
|
+
test_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" src="/media_objects_iframe/m-lolcat?type=video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-lolcat"></iframe>)
|
317
|
+
replacement_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" src="/media_attachments_iframe/8?embedded=true&type=video&verifier=u8" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-lolcat"></iframe>)
|
318
|
+
expect(@converter.convert_exported_html(test_string)).to eq([replacement_string, nil])
|
319
|
+
end
|
298
320
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
321
|
+
it "handles and repair half broken new RCE media iframes" do
|
322
|
+
test_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" src="%24IMS_CC_FILEBASE%24/#" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-lolcat"></iframe>)
|
323
|
+
repaired_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" src="/media_attachments_iframe/8?embedded=true&type=video&verifier=u8" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-lolcat"></iframe>)
|
324
|
+
expect(@converter.convert_exported_html(test_string)).to eq([repaired_string, nil])
|
325
|
+
end
|
303
326
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
327
|
+
it "converts source tags to RCE media iframes" do
|
328
|
+
test_string = %(<video style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-lolcat"><source src="/media_objects_iframe/m-lolcat?type=video" data-media-id="m-lolcat" data-media-type="video"></video>)
|
329
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-lolcat" src="/media_attachments_iframe/8?embedded=true&type=video&verifier=u8"></iframe>)
|
330
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
308
331
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
332
|
+
test_string = %(<audio style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="m-yodawg"><source src="/media_objects_iframe/m-yodawg?type=audio" data-media-id="m-yodawg" data-media-type="audio"></audio>)
|
333
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="m-yodawg" src="/media_attachments_iframe/9?embedded=true&type=audio&verifier=u9"></iframe>)
|
334
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
335
|
+
end
|
313
336
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
337
|
+
it "converts source tags to RCE media attachment iframes" do
|
338
|
+
test_string = %(<video style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-stuff"><source src="$IMS-CC-FILEBASE$/subfolder/with a space/yodawg.mov?canvas_=1&canvas_qs_type=video&canvas_qs_amp=&canvas_qs_embedded=true&media_attachment=true" data-media-id="m-stuff" data-media-type="video"></video>)
|
339
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-yodawg" src="/media_attachments_iframe/9?embedded=true&type=video&verifier=u9"></iframe>)
|
340
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
318
341
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
342
|
+
test_string = %(<audio style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="m-stuff"><source src="$IMS-CC-FILEBASE$/lolcat.mp3?canvas_=1&canvas_qs_type=audio&canvas_qs_amp=&canvas_qs_embedded=true&media_attachment=true" data-media-id="m-stuff" data-media-type="audio"></video>)
|
343
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="m-lolcat" src="/media_attachments_iframe/8?embedded=true&type=audio&verifier=u8"></iframe>)
|
344
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
345
|
+
end
|
323
346
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
347
|
+
it "converts source tags to RCE media attachment iframes when link is an unknown media attachment reference (link from a public file in another course)" do
|
348
|
+
test_string = %(<video style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="0_l4l5n0wt"><source src="/media_attachments_iframe/18?type=video" data-media-id="0_l4l5n0wt" data-media-type="video"></video>)
|
349
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="0_l4l5n0wt" src="/media_attachments_iframe/18?type=video"></iframe>)
|
350
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
328
351
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
352
|
+
test_string = %(<audio style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="0_l4l5n0wu"><source src="/media_attachments_iframe/19?type=audio" data-media-id="0_l4l5n0wu" data-media-type="audio"></video>)
|
353
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="0_l4l5n0wu" src="/media_attachments_iframe/19?type=audio"></iframe>)
|
354
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
355
|
+
end
|
333
356
|
|
334
|
-
|
335
|
-
|
336
|
-
|
357
|
+
it "converts course copy style media attachmet iframe links" do
|
358
|
+
test_string = %(<video style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-yodawg"><source src="$CANVAS_COURSE_REFERENCE$/file_ref/I?media_attachment=true&type=video" data-media-id="m-yodawg" data-media-type="video"></video>)
|
359
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="video" allowfullscreen="allowfullscreen" allow="fullscreen" data-media-id="m-yodawg" src="/media_attachments_iframe/9?embedded=true&type=video&verifier=u9"></iframe>)
|
360
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
361
|
+
|
362
|
+
test_string = %(<audio style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="m-lolcat"><source src="$CANVAS_COURSE_REFERENCE$/file_ref/H?media_attachment=true&type=audio" data-media-id="m-lolcat" data-media-type="audio"></audio>)
|
363
|
+
converted_string = %(<iframe style="width: 400px; height: 225px; display: inline-block;" title="this is a media comment" data-media-type="audio" data-media-id="m-lolcat" src="/media_attachments_iframe/8?embedded=true&type=audio&verifier=u8"></iframe>)
|
364
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
365
|
+
end
|
366
|
+
|
367
|
+
it "leaves source tags without data-media-id alone" do
|
368
|
+
test_string = %(<video style="width: 400px; height: 225px; display: inline-block;" title="this is a non-canvas video" allowfullscreen="allowfullscreen" allow="fullscreen"><source src="http://www.example.com/video.mov"></video>)
|
369
|
+
expect(@converter.convert_exported_html(test_string)).to eq([test_string, nil])
|
370
|
+
end
|
337
371
|
end
|
338
372
|
|
339
373
|
it "only converts url params" do
|
@@ -48,25 +48,25 @@ describe CanvasLinkMigrator::LinkResolver do
|
|
48
48
|
it "converts file_ref urls" do
|
49
49
|
link = { link_type: :file_ref, migration_id: "F" }
|
50
50
|
resolver.resolve_link!(link)
|
51
|
-
expect(link[:new_value]).to eq("/courses/2/files/6/preview")
|
51
|
+
expect(link[:new_value]).to eq("/courses/2/files/6/preview?verifier=u6")
|
52
52
|
end
|
53
53
|
|
54
54
|
it "does not suffix /preview to target blank links" do
|
55
55
|
link = { link_type: :file_ref, target_blank: true, migration_id: "F" }
|
56
56
|
resolver.resolve_link!(link)
|
57
|
-
expect(link[:new_value]).to eq("/courses/2/files/6")
|
57
|
+
expect(link[:new_value]).to eq("/courses/2/files/6?verifier=u6")
|
58
58
|
end
|
59
59
|
|
60
60
|
it "converts attachment urls" do
|
61
61
|
link = { link_type: :object, type: "attachments", migration_id: "E", query: "?foo=bar" }
|
62
62
|
resolver.resolve_link!(link)
|
63
|
-
expect(link[:new_value]).to eq("/courses/2/files/5/preview")
|
63
|
+
expect(link[:new_value]).to eq("/courses/2/files/5/preview?verifier=u5")
|
64
64
|
end
|
65
65
|
|
66
66
|
it "converts media_attachments_iframe urls" do
|
67
67
|
link = { link_type: :object, type: "media_attachments_iframe", migration_id: "F", query: "?foo=bar" }
|
68
68
|
resolver.resolve_link!(link)
|
69
|
-
expect(link[:new_value]).to eq("/media_attachments_iframe/6?foo=bar")
|
69
|
+
expect(link[:new_value]).to eq("/media_attachments_iframe/6?foo=bar&verifier=u6")
|
70
70
|
end
|
71
71
|
|
72
72
|
it "converts discussion_topic links" do
|
@@ -50,49 +50,60 @@
|
|
50
50
|
"E": {
|
51
51
|
"destination": {
|
52
52
|
"id": "5",
|
53
|
-
"media_entry_id": "m-stuff"
|
53
|
+
"media_entry_id": "m-stuff",
|
54
|
+
"uuid": "u5"
|
54
55
|
},
|
55
56
|
"source": {
|
56
57
|
"id": "3",
|
57
|
-
"media_entry_id": "m-stuff"
|
58
|
+
"media_entry_id": "m-stuff",
|
59
|
+
"uuid": "u3"
|
58
60
|
}
|
59
61
|
},
|
60
62
|
"F": {
|
61
63
|
"destination": {
|
62
64
|
"id": "6",
|
63
|
-
"media_entry_id": "0_bq09qam2"
|
65
|
+
"media_entry_id": "0_bq09qam2",
|
66
|
+
"uuid": "u6"
|
64
67
|
},
|
65
68
|
"source": {
|
66
69
|
"id": "4",
|
67
|
-
"media_entry_id": "0_bq09qam2"
|
70
|
+
"media_entry_id": "0_bq09qam2",
|
71
|
+
"uuid": "u4"
|
68
72
|
}
|
69
73
|
},
|
70
74
|
"G": {
|
71
75
|
"destination": {
|
72
|
-
"id": "7"
|
76
|
+
"id": "7",
|
77
|
+
"uuid": "u7"
|
73
78
|
},
|
74
79
|
"source": {
|
75
|
-
"id": "2"
|
80
|
+
"id": "2",
|
81
|
+
"uuid": "u2"
|
76
82
|
}
|
77
83
|
},
|
78
84
|
"H": {
|
79
85
|
"destination": {
|
80
86
|
"id": "8",
|
81
|
-
"media_entry_id": "m-lolcat"
|
87
|
+
"media_entry_id": "m-lolcat",
|
88
|
+
"uuid": "u8"
|
89
|
+
|
82
90
|
},
|
83
91
|
"source": {
|
84
92
|
"id": "3",
|
85
|
-
"media_entry_id": "m-lolcat"
|
93
|
+
"media_entry_id": "m-lolcat",
|
94
|
+
"uuid": "u3"
|
86
95
|
}
|
87
96
|
},
|
88
97
|
"I": {
|
89
98
|
"destination": {
|
90
99
|
"id": "9",
|
91
|
-
"media_entry_id": "m-yodawg"
|
100
|
+
"media_entry_id": "m-yodawg",
|
101
|
+
"uuid": "u9"
|
92
102
|
},
|
93
103
|
"source": {
|
94
104
|
"id": "4",
|
95
|
-
"media_entry_id": "m-yodawg"
|
105
|
+
"media_entry_id": "m-yodawg",
|
106
|
+
"uuid": "u4"
|
96
107
|
}
|
97
108
|
}
|
98
109
|
},
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canvas_link_migrator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mysti Lilla
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2024-
|
14
|
+
date: 2024-06-14 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -162,7 +162,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
162
162
|
requirements:
|
163
163
|
- - ">="
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: '
|
165
|
+
version: '2.7'
|
166
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
167
|
requirements:
|
168
168
|
- - ">="
|