canvas_link_migrator 0.2.0 → 1.0.1
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 +12 -2
- data/lib/canvas_link_migrator/link_resolver.rb +7 -5
- data/spec/canvas_link_migrator/imported_html_converter_spec.rb +22 -9
- data/spec/canvas_link_migrator/link_resolver_spec.rb +1 -1
- data/spec/fixtures/canvas_resource_map.json +24 -4
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d147093c7e6b397c3eb184aba4af1595f782e14735a50e9d4986be628af75f3
|
4
|
+
data.tar.gz: cb48c35f35dd333b02ff7dcba5e3bd79d1a1a7b736b7bb14c56de11b6c91565e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4074cbb1bfa20b00f4843327d62ee0e1cf739f7450b46698ee1a6a240054f27acd34046605e2ae4f54bbdf02b529272ba165769352e10abff1f5950c08af6ad8
|
7
|
+
data.tar.gz: e1deecf7b1d6586c432234092e338c9d3059f26b744072eab1cb6e644c25dbcec9ffacfb53239b6c9ffc0610c210bf80399f097f2d7efa2265686caf314a8fee
|
@@ -19,6 +19,7 @@
|
|
19
19
|
|
20
20
|
require "nokogiri"
|
21
21
|
require "digest"
|
22
|
+
require "addressable"
|
22
23
|
|
23
24
|
module CanvasLinkMigrator
|
24
25
|
class LinkParser
|
@@ -181,6 +182,14 @@ module CanvasLinkMigrator
|
|
181
182
|
|
182
183
|
# returns a hash with resolution status and data to hold onto if unresolved
|
183
184
|
def parse_url(url, node, attr)
|
185
|
+
parsed_url = Addressable::URI.parse(url)
|
186
|
+
query_values = parsed_url.query_values
|
187
|
+
media_attachment = query_values.try(:delete, "media_attachment") == "true"
|
188
|
+
if media_attachment
|
189
|
+
parsed_url.query_values = query_values.present? ? query_values : nil
|
190
|
+
url = Addressable::URI.unencode(parsed_url)
|
191
|
+
end
|
192
|
+
|
184
193
|
if url =~ /wiki_page_migration_id=(.*)/
|
185
194
|
unresolved(:wiki_page, migration_id: $1)
|
186
195
|
elsif url =~ /discussion_topic_migration_id=(.*)/
|
@@ -191,7 +200,8 @@ module CanvasLinkMigrator
|
|
191
200
|
unresolved(:file_ref,
|
192
201
|
migration_id: $1,
|
193
202
|
rest: $2,
|
194
|
-
in_media_iframe: attr == "src" && ["iframe", "source"].include?(node.name) && node["data-media-id"]
|
203
|
+
in_media_iframe: attr == "src" && ["iframe", "source"].include?(node.name) && node["data-media-id"],
|
204
|
+
media_attachment: media_attachment)
|
195
205
|
elsif url =~ %r{(?:\$CANVAS_OBJECT_REFERENCE\$|\$WIKI_REFERENCE\$)/([^/]*)/([^?]*)(\?.*)?}
|
196
206
|
if KNOWN_REFERENCE_TYPES.include?($1)
|
197
207
|
unresolved(:object, type: $1, migration_id: $2, query: $3)
|
@@ -207,7 +217,7 @@ module CanvasLinkMigrator
|
|
207
217
|
rel_path = URI::DEFAULT_PARSER.unescape($1)
|
208
218
|
if (attr == "href" && node["class"]&.include?("instructure_inline_media_comment")) ||
|
209
219
|
(attr == "src" && ["iframe", "source"].include?(node.name) && node["data-media-id"])
|
210
|
-
unresolved(:media_object, rel_path: rel_path)
|
220
|
+
unresolved(:media_object, rel_path: rel_path, media_attachment: media_attachment)
|
211
221
|
else
|
212
222
|
unresolved(:file, rel_path: rel_path)
|
213
223
|
end
|
@@ -68,7 +68,8 @@ module CanvasLinkMigrator
|
|
68
68
|
type = "pages" if type == "wiki"
|
69
69
|
if type == "pages"
|
70
70
|
query = resolve_module_item_query(nil, link[:query])
|
71
|
-
|
71
|
+
linked_wiki_url = @migration_id_converter.convert_wiki_page_migration_id_to_slug(migration_id) || migration_id
|
72
|
+
link[:new_value] = "#{context_path}/pages/#{linked_wiki_url}#{query}"
|
72
73
|
elsif type == "attachments"
|
73
74
|
att_id = @migration_id_converter.convert_attachment_migration_id(migration_id)
|
74
75
|
if att_id
|
@@ -91,7 +92,7 @@ module CanvasLinkMigrator
|
|
91
92
|
# see LinkParser for details
|
92
93
|
rel_path = link[:rel_path]
|
93
94
|
node = Nokogiri::HTML5.fragment(link[:old_value]).children.first
|
94
|
-
new_url = resolve_media_comment_data(node, rel_path)
|
95
|
+
new_url = resolve_media_comment_data(node, rel_path, link[:media_attachment])
|
95
96
|
new_url ||= resolve_relative_file_url(rel_path)
|
96
97
|
|
97
98
|
unless new_url
|
@@ -123,6 +124,8 @@ module CanvasLinkMigrator
|
|
123
124
|
# during a file fetch
|
124
125
|
if rest.include?("icon_maker_icon=1")
|
125
126
|
link[:new_value] = "/files/#{file_id}#{rest}"
|
127
|
+
elsif link[:in_media_iframe] && link[:media_attachment]
|
128
|
+
link[:new_value] = "/media_attachments_iframe/#{file_id}#{rest}"
|
126
129
|
else
|
127
130
|
link[:new_value] = "#{context_path}/files/#{file_id}#{rest}"
|
128
131
|
link[:new_value] = "/media_objects_iframe?mediahref=#{link[:new_value]}" if link[:in_media_iframe]
|
@@ -222,14 +225,13 @@ module CanvasLinkMigrator
|
|
222
225
|
url
|
223
226
|
end
|
224
227
|
|
225
|
-
def resolve_media_comment_data(node, rel_path)
|
228
|
+
def resolve_media_comment_data(node, rel_path, media_attachment)
|
226
229
|
if (file = find_file_in_context(rel_path[/^[^?]+/])) # strip query string for this search
|
227
230
|
media_id = file.try(:media_object)&.media_id || file["media_entry_id"]
|
228
231
|
if media_id && media_id != "maybe"
|
229
232
|
if ["iframe", "source"].include?(node.name)
|
230
233
|
node["data-media-id"] = media_id
|
231
|
-
if
|
232
|
-
node.delete("data-is-media-attachment")
|
234
|
+
if media_attachment
|
233
235
|
return media_attachment_iframe_url(file["id"], node["data-media-type"])
|
234
236
|
else
|
235
237
|
return media_iframe_url(media_id, node["data-media-type"])
|
@@ -37,6 +37,13 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
37
37
|
expect(bad_links).to be_nil
|
38
38
|
end
|
39
39
|
|
40
|
+
it "converts a wiki reference with migration id" do
|
41
|
+
test_string = %(<a href="%24WIKI_REFERENCE%24/pages/A?query=blah">Test Wiki Page</a>)
|
42
|
+
html, bad_links = @converter.convert_exported_html(test_string)
|
43
|
+
expect(html).to eq %(<a href="#{@path}pages/slug-a?query=blah">Test Wiki Page</a>)
|
44
|
+
expect(bad_links).to be_nil
|
45
|
+
end
|
46
|
+
|
40
47
|
context "when course attachments exist" do
|
41
48
|
subject { @converter.convert_exported_html(test_string) }
|
42
49
|
|
@@ -214,22 +221,28 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
214
221
|
end
|
215
222
|
|
216
223
|
it "converts source tags to RCE media attachment iframes" do
|
217
|
-
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="$
|
218
|
-
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-
|
224
|
+
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>)
|
225
|
+
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?type=video"></iframe>)
|
219
226
|
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
220
227
|
|
221
|
-
test_string = %(<audio
|
222
|
-
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-
|
228
|
+
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>)
|
229
|
+
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?type=audio"></iframe>)
|
223
230
|
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
224
231
|
end
|
225
232
|
|
226
|
-
it "converts
|
227
|
-
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-
|
228
|
-
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-
|
233
|
+
it "converts course copy style media attachmet iframe links" do
|
234
|
+
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>)
|
235
|
+
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?type=video"></iframe>)
|
229
236
|
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
230
237
|
|
231
|
-
test_string = %(<audio
|
232
|
-
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-
|
238
|
+
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>)
|
239
|
+
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?type=audio"></iframe>)
|
240
|
+
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
241
|
+
end
|
242
|
+
|
243
|
+
it "converts mediahref iframes" do
|
244
|
+
test_string = %(<iframe data-media-type="video" src="/media_objects_iframe?mediahref=$CANVAS_COURSE_REFERENCE$/file_ref/I/download" data-media-id="m-yodawg"></iframe>)
|
245
|
+
converted_string = %(<iframe data-media-type="video" src="/media_objects_iframe?mediahref=/courses/2/files/9/download" data-media-id="m-yodawg"></iframe>)
|
233
246
|
expect(@converter.convert_exported_html(test_string)).to eq([converted_string, nil])
|
234
247
|
end
|
235
248
|
|
@@ -75,7 +75,7 @@ describe CanvasLinkMigrator::LinkResolver do
|
|
75
75
|
expect(link[:new_value]).to eq("/courses/2/modules/36?foo=bar")
|
76
76
|
end
|
77
77
|
|
78
|
-
it "
|
78
|
+
it "converts other links" do
|
79
79
|
link = { link_type: :object, type: "assignments", migration_id: "I", query: "#fie" }
|
80
80
|
resolver.resolve_link!(link)
|
81
81
|
expect(link[:new_value]).to eq("/courses/2/assignments/12#fie")
|
@@ -2,7 +2,9 @@
|
|
2
2
|
"attachment_path_id_lookup": {
|
3
3
|
"subfolder/test.png": "G",
|
4
4
|
"subfolder/with a space/test.png": "F",
|
5
|
+
"subfolder/with a space/yodawg.mov": "I",
|
5
6
|
"subfolder/withCapital/test.png": "migration_id!",
|
7
|
+
"lolcat.mp3": "H",
|
6
8
|
"test.png": "E"
|
7
9
|
},
|
8
10
|
"contains_migration_ids": true,
|
@@ -66,12 +68,30 @@
|
|
66
68
|
},
|
67
69
|
"G": {
|
68
70
|
"destination": {
|
69
|
-
"id": "7"
|
70
|
-
"media_entry_id": "m-stuff"
|
71
|
+
"id": "7"
|
71
72
|
},
|
72
73
|
"source": {
|
73
|
-
"id": "2"
|
74
|
-
|
74
|
+
"id": "2"
|
75
|
+
}
|
76
|
+
},
|
77
|
+
"H": {
|
78
|
+
"destination": {
|
79
|
+
"id": "8",
|
80
|
+
"media_entry_id": "m-lolcat"
|
81
|
+
},
|
82
|
+
"source": {
|
83
|
+
"id": "3",
|
84
|
+
"media_entry_id": "m-lolcat"
|
85
|
+
}
|
86
|
+
},
|
87
|
+
"I": {
|
88
|
+
"destination": {
|
89
|
+
"id": "9",
|
90
|
+
"media_entry_id": "m-yodawg"
|
91
|
+
},
|
92
|
+
"source": {
|
93
|
+
"id": "4",
|
94
|
+
"media_entry_id": "m-yodawg"
|
75
95
|
}
|
76
96
|
}
|
77
97
|
},
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canvas_link_migrator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mysti Lilla
|
8
8
|
- James Logan
|
9
|
+
- Sarah Gerard
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2023-
|
13
|
+
date: 2023-11-04 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: activesupport
|
@@ -53,6 +54,20 @@ dependencies:
|
|
53
54
|
- - ">="
|
54
55
|
- !ruby/object:Gem::Version
|
55
56
|
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: addressable
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
type: :runtime
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
56
71
|
- !ruby/object:Gem::Dependency
|
57
72
|
name: bundler
|
58
73
|
requirement: !ruby/object:Gem::Requirement
|
@@ -113,6 +128,7 @@ description:
|
|
113
128
|
email:
|
114
129
|
- mysti@instructure.com
|
115
130
|
- james.logan@instructure.com
|
131
|
+
- sarah.gerard@instructure.com
|
116
132
|
executables: []
|
117
133
|
extensions: []
|
118
134
|
extra_rdoc_files: []
|