canvas_link_migrator 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/canvas_link_migrator/link_resolver.rb +18 -12
- data/lib/canvas_link_migrator/resource_map_service.rb +7 -3
- data/spec/canvas_link_migrator/imported_html_converter_spec.rb +45 -45
- data/spec/canvas_link_migrator/link_resolver_spec.rb +6 -0
- data/spec/fixtures/canvas_resource_map.json +17 -7
- 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: 838d1d2500ee03946b3363f19168d62181e4c40f0456cd6b27d2f6ace817c46d
|
4
|
+
data.tar.gz: e3686d60c231069856722e4f69e436efedd2531aa5cfc156093b2850918d7384
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45520836a340a6a0f111057360299af93bfc39ac241ba31ab5f6c132dec98f75a32443fd4664e1f879f426d43b43e3ad7ee19a7b8eb89a52d2f595a856172b1e
|
7
|
+
data.tar.gz: 5c0fd8cdf1b2ea2c3d8a4e4e7ddf72d6ae8bae51178a9432ffbca3841c4576c18022da5f0802dc9579b37a53a68803e4e08935080dc344950faa56c93baf6f2d
|
@@ -18,9 +18,14 @@
|
|
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 "rack"
|
21
22
|
|
22
23
|
module CanvasLinkMigrator
|
23
24
|
class LinkResolver
|
25
|
+
attr_accessor :migration_id_converter
|
26
|
+
|
27
|
+
delegate :context_path, :attachment_path_id_lookup, to: :migration_id_converter
|
28
|
+
|
24
29
|
def initialize(migration_id_converter)
|
25
30
|
@migration_id_converter = migration_id_converter
|
26
31
|
end
|
@@ -35,8 +40,8 @@ module CanvasLinkMigrator
|
|
35
40
|
end
|
36
41
|
end
|
37
42
|
|
38
|
-
def
|
39
|
-
@
|
43
|
+
def attachment_path_id_lookup_lower
|
44
|
+
@attachment_path_id_lookup_lower ||= attachment_path_id_lookup&.transform_keys(&:downcase)
|
40
45
|
end
|
41
46
|
|
42
47
|
# finds the :new_value to use to replace the placeholder
|
@@ -63,7 +68,8 @@ module CanvasLinkMigrator
|
|
63
68
|
type = "pages" if type == "wiki"
|
64
69
|
if type == "pages"
|
65
70
|
query = resolve_module_item_query(nil, link[:query])
|
66
|
-
|
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}"
|
67
73
|
elsif type == "attachments"
|
68
74
|
att_id = @migration_id_converter.convert_attachment_migration_id(migration_id)
|
69
75
|
if att_id
|
@@ -150,13 +156,13 @@ module CanvasLinkMigrator
|
|
150
156
|
# This is for backward-compatibility: canvas attachment filenames are escaped
|
151
157
|
# with '+' for spaces and older exports have files with that instead of %20
|
152
158
|
alt_rel_path = rel_path.tr("+", " ")
|
153
|
-
if
|
154
|
-
mig_id ||=
|
155
|
-
mig_id ||=
|
159
|
+
if attachment_path_id_lookup
|
160
|
+
mig_id ||= attachment_path_id_lookup[rel_path]
|
161
|
+
mig_id ||= attachment_path_id_lookup[alt_rel_path]
|
156
162
|
end
|
157
|
-
if !mig_id &&
|
158
|
-
mig_id ||=
|
159
|
-
mig_id ||=
|
163
|
+
if !mig_id && attachment_path_id_lookup_lower
|
164
|
+
mig_id ||= attachment_path_id_lookup_lower[rel_path.downcase]
|
165
|
+
mig_id ||= attachment_path_id_lookup_lower[alt_rel_path.downcase]
|
160
166
|
end
|
161
167
|
|
162
168
|
# This md5 comparison is here to handle faulty cartridges with the migration_id equivalent of an empty string
|
@@ -182,7 +188,7 @@ module CanvasLinkMigrator
|
|
182
188
|
while new_url.nil? && !rel_path_parts.empty?
|
183
189
|
sub_path = File.join(rel_path_parts)
|
184
190
|
if (file = find_file_in_context(sub_path))
|
185
|
-
new_url = "#{context_path}/files/#{file
|
191
|
+
new_url = "#{context_path}/files/#{file["id"]}"
|
186
192
|
# support other params in the query string, that were exported from the
|
187
193
|
# original path components and query string. see
|
188
194
|
# CCHelper::file_query_string
|
@@ -219,13 +225,13 @@ module CanvasLinkMigrator
|
|
219
225
|
|
220
226
|
def resolve_media_comment_data(node, rel_path)
|
221
227
|
if (file = find_file_in_context(rel_path[/^[^?]+/])) # strip query string for this search
|
222
|
-
media_id =
|
228
|
+
media_id = file.try(:media_object)&.media_id || file["media_entry_id"]
|
223
229
|
if media_id && media_id != "maybe"
|
224
230
|
if ["iframe", "source"].include?(node.name)
|
225
231
|
node["data-media-id"] = media_id
|
226
232
|
if node["data-is-media-attachment"]
|
227
233
|
node.delete("data-is-media-attachment")
|
228
|
-
return media_attachment_iframe_url(file
|
234
|
+
return media_attachment_iframe_url(file["id"], node["data-media-type"])
|
229
235
|
else
|
230
236
|
return media_iframe_url(media_id, node["data-media-type"])
|
231
237
|
end
|
@@ -52,9 +52,9 @@ module CanvasLinkMigrator
|
|
52
52
|
migration_data["destination_hosts"]
|
53
53
|
end
|
54
54
|
|
55
|
-
def attachment_path_id_lookup
|
56
|
-
|
57
|
-
|
55
|
+
def attachment_path_id_lookup
|
56
|
+
migration_data["attachment_path_id_lookup"]
|
57
|
+
end
|
58
58
|
|
59
59
|
def root_folder_name
|
60
60
|
migration_data["destination_root_folder"]
|
@@ -102,5 +102,9 @@ module CanvasLinkMigrator
|
|
102
102
|
# we'll check both here
|
103
103
|
convert_announcement_migration_id(migration_id) if type == "discussion_topics"
|
104
104
|
end
|
105
|
+
|
106
|
+
def lookup_attachment_by_migration_id(migration_id)
|
107
|
+
resources.dig("files", migration_id, "destination")
|
108
|
+
end
|
105
109
|
end
|
106
110
|
end
|
@@ -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
|
|
@@ -56,62 +63,55 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
|
|
56
63
|
end
|
57
64
|
end
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# it "finds an attachment by path" do
|
65
|
-
# test_string = %{<p>This is an image: <br /><img src="%24IMS_CC_FILEBASE%24/test.png" alt=":(" /></p>}
|
66
|
-
|
67
|
-
# # if there isn't a path->migration id map it'll be a relative course file path
|
68
|
-
# expect(@converter.convert_exported_html(test_string)).to eq %{<p>This is an image: <br><img src="#{@path}file_contents/course%20files/test.png" alt=":("></p>}
|
69
|
-
|
70
|
-
# @migration.attachment_path_id_lookup = { "test.png" => att.migration_id }
|
71
|
-
# expect(@converter.convert_exported_html(test_string)).to eq %{<p>This is an image: <br><img src="#{@path}files/#{att.id}/preview" alt=":("></p>}
|
72
|
-
# end
|
66
|
+
it "finds an attachment by migration id" do
|
67
|
+
test_string = %{<p>This is an image: <br /><img src="%24CANVAS_OBJECT_REFERENCE%24/attachments/F" alt=":(" /></p>}
|
68
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/6/preview" alt=":("></p>}, nil])
|
69
|
+
end
|
73
70
|
|
74
|
-
|
75
|
-
|
76
|
-
# @migration.attachment_path_id_lookup = { "subfolder/with a space/test.png" => att.migration_id }
|
71
|
+
it "finds an attachment by path" do
|
72
|
+
test_string = %{<p>This is an image: <br /><img src="%24IMS_CC_FILEBASE%24/test.png" alt=":(" /></p>}
|
77
73
|
|
78
|
-
|
79
|
-
|
74
|
+
# if there isn't a path->migration id map it'll be a relative course file path
|
75
|
+
expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).exactly(4).times.and_return({})
|
76
|
+
html, bad_links = @converter.convert_exported_html(test_string)
|
77
|
+
expect(html).to eq %{<p>This is an image: <br><img src="#{@path}file_contents/course%20files/test.png" alt=":("></p>}
|
78
|
+
expect(bad_links[0]).to include({ link_type: :file, missing_url: "/courses/2/file_contents/course%20files/test.png" })
|
80
79
|
|
81
|
-
|
82
|
-
|
83
|
-
|
80
|
+
expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_call_original
|
81
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/5/preview" alt=":("></p>}, nil])
|
82
|
+
end
|
84
83
|
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
it "finds an attachment by a path with a space" do
|
85
|
+
test_string = %(<img src="subfolder/with%20a%20space/test.png" alt="nope" />)
|
86
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
|
88
87
|
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
test_string = %(<img src="subfolder/with+a+space/test.png" alt="nope" />)
|
89
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
|
90
|
+
end
|
92
91
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
92
|
+
it "finds an attachment even if the link has an extraneous folder" do
|
93
|
+
test_string = %(<img src="anotherfolder/subfolder/test.png" alt="nope" />)
|
94
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/7/preview" alt="nope">), nil])
|
95
|
+
end
|
97
96
|
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
it "finds an attachment by path if capitalization is different" do
|
98
|
+
expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_return({ "subfolder/withCapital/test.png" => "wrong!" })
|
99
|
+
expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_return({ "subfolder/withcapital/test.png" => "F" })
|
101
100
|
|
102
|
-
|
103
|
-
|
104
|
-
|
101
|
+
test_string = %(<img src="subfolder/WithCapital/TEST.png" alt="nope" />)
|
102
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
|
103
|
+
end
|
105
104
|
|
106
|
-
|
107
|
-
|
105
|
+
it "finds an attachment with query params" do
|
106
|
+
test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?canvas_customaction=1&canvas_qs_customparam=1" alt="nope" />)
|
107
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/customaction?customparam=1" alt="nope">), nil])
|
108
108
|
|
109
|
-
|
110
|
-
|
109
|
+
test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?canvas_qs_customparam2=3" alt="nope" />)
|
110
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview?customparam2=3" alt="nope">), nil])
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?notarelevantparam" alt="nope" />)
|
113
|
+
expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview" alt="nope">), nil])
|
114
|
+
end
|
115
115
|
end
|
116
116
|
|
117
117
|
it "converts picture source srcsets" do
|
@@ -81,4 +81,10 @@ describe CanvasLinkMigrator::LinkResolver do
|
|
81
81
|
expect(link[:new_value]).to eq("/courses/2/assignments/12#fie")
|
82
82
|
end
|
83
83
|
end
|
84
|
+
|
85
|
+
describe "attachment_path_id_lookup_lower" do
|
86
|
+
it "shows correct lowercase paths" do
|
87
|
+
expect(resolver.attachment_path_id_lookup_lower).to include({ "subfolder/withcapital/test.png" => "migration_id!" })
|
88
|
+
end
|
89
|
+
end
|
84
90
|
end
|
@@ -1,4 +1,10 @@
|
|
1
1
|
{
|
2
|
+
"attachment_path_id_lookup": {
|
3
|
+
"subfolder/test.png": "G",
|
4
|
+
"subfolder/with a space/test.png": "F",
|
5
|
+
"subfolder/withCapital/test.png": "migration_id!",
|
6
|
+
"test.png": "E"
|
7
|
+
},
|
2
8
|
"contains_migration_ids": true,
|
3
9
|
"destination_course": "2",
|
4
10
|
"destination_hosts": [
|
@@ -57,6 +63,16 @@
|
|
57
63
|
"id": "4",
|
58
64
|
"media_entry_id": "m-stuff"
|
59
65
|
}
|
66
|
+
},
|
67
|
+
"G": {
|
68
|
+
"destination": {
|
69
|
+
"id": "7",
|
70
|
+
"media_entry_id": "m-stuff"
|
71
|
+
},
|
72
|
+
"source": {
|
73
|
+
"id": "2",
|
74
|
+
"media_entry_id": "m-stuff"
|
75
|
+
}
|
60
76
|
}
|
61
77
|
},
|
62
78
|
"module_items": {
|
@@ -92,12 +108,6 @@
|
|
92
108
|
}
|
93
109
|
}
|
94
110
|
},
|
95
|
-
"file_tree": {
|
96
|
-
"folder 1": {
|
97
|
-
"id": "1",
|
98
|
-
"sub_folders": {}
|
99
|
-
}
|
100
|
-
},
|
101
111
|
"source_course": "1",
|
102
112
|
"source_host": "pineapple.edu"
|
103
|
-
}
|
113
|
+
}
|
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.1
|
4
|
+
version: 0.2.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-08-22 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: activesupport
|
@@ -39,6 +40,20 @@ dependencies:
|
|
39
40
|
- - ">="
|
40
41
|
- !ruby/object:Gem::Version
|
41
42
|
version: '0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rack
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
42
57
|
- !ruby/object:Gem::Dependency
|
43
58
|
name: bundler
|
44
59
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,6 +114,7 @@ description:
|
|
99
114
|
email:
|
100
115
|
- mysti@instructure.com
|
101
116
|
- james.logan@instructure.com
|
117
|
+
- sarah.gerard@instructure.com
|
102
118
|
executables: []
|
103
119
|
extensions: []
|
104
120
|
extra_rdoc_files: []
|