canvas_link_migrator 0.1.1 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e4d3a30191584ee3b4bc14c83f21edecbad0652562590eee989047f99e1d050
4
- data.tar.gz: fb9825fc75bb255068dfb1f5d2f285e332612657690f6bc08933c99ae4d948bb
3
+ metadata.gz: 989d0e7044ece5d052b909fa121de7f205906c733908a8dcf4a26d619cf67caf
4
+ data.tar.gz: a065d7f5ad6ad400cbd7cf448f5d42c5b69d400d9123837d2517950059d4a70e
5
5
  SHA512:
6
- metadata.gz: 5847f829a7938282cfd2399fe3067dc72a5d248b95c2c38d35716d58ea12a019fff94e5b6cc0b34d09ff0bb4efae0dcc4ebef98baf771f999d9a73c865e9fba5
7
- data.tar.gz: 25e4c872ded3277e7980bd99a7cbfc961d44a1a984840c8bfe8efb24052b0c36e0ac3c6c8e72f10a74072c14072ba89bd96f81305f2261abc0da0a5d67dbc389
6
+ metadata.gz: 50b673e7a91c0f345455c0ef0027b9e05a84c973f35d75f5659d336dfb70a3385d04d3360bead41b16a5101e3f8ee5e054f881cab88ac3f7c3ec0d5387cb7c6c
7
+ data.tar.gz: 8519365222facd8c05af020e7c6734db5c61e386cfd1fd0097f1a0815924c2c622929c217bfa4772d37fcd3acadd118019672cd9958ad76951512acd4bd8c4ba
@@ -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 context_path
39
- @migration_id_converter.context_path
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
@@ -150,13 +155,13 @@ module CanvasLinkMigrator
150
155
  # This is for backward-compatibility: canvas attachment filenames are escaped
151
156
  # with '+' for spaces and older exports have files with that instead of %20
152
157
  alt_rel_path = rel_path.tr("+", " ")
153
- if @migration_id_converter.attachment_path_id_lookup
154
- mig_id ||= @migration_id_converter.attachment_path_id_lookup[rel_path]
155
- mig_id ||= @migration_id_converter.attachment_path_id_lookup[alt_rel_path]
158
+ if attachment_path_id_lookup
159
+ mig_id ||= attachment_path_id_lookup[rel_path]
160
+ mig_id ||= attachment_path_id_lookup[alt_rel_path]
156
161
  end
157
- if !mig_id && @migration_id_converter.attachment_path_id_lookup_lower
158
- mig_id ||= @migration_id_converter.attachment_path_id_lookup_lower[rel_path.downcase]
159
- mig_id ||= @migration_id_converter.attachment_path_id_lookup_lower[alt_rel_path.downcase]
162
+ if !mig_id && attachment_path_id_lookup_lower
163
+ mig_id ||= attachment_path_id_lookup_lower[rel_path.downcase]
164
+ mig_id ||= attachment_path_id_lookup_lower[alt_rel_path.downcase]
160
165
  end
161
166
 
162
167
  # This md5 comparison is here to handle faulty cartridges with the migration_id equivalent of an empty string
@@ -182,7 +187,7 @@ module CanvasLinkMigrator
182
187
  while new_url.nil? && !rel_path_parts.empty?
183
188
  sub_path = File.join(rel_path_parts)
184
189
  if (file = find_file_in_context(sub_path))
185
- new_url = "#{context_path}/files/#{file.id}"
190
+ new_url = "#{context_path}/files/#{file["id"]}"
186
191
  # support other params in the query string, that were exported from the
187
192
  # original path components and query string. see
188
193
  # CCHelper::file_query_string
@@ -219,13 +224,13 @@ module CanvasLinkMigrator
219
224
 
220
225
  def resolve_media_comment_data(node, rel_path)
221
226
  if (file = find_file_in_context(rel_path[/^[^?]+/])) # strip query string for this search
222
- media_id = (file.media_object&.media_id || file.media_entry_id)
227
+ media_id = file.try(:media_object)&.media_id || file["media_entry_id"]
223
228
  if media_id && media_id != "maybe"
224
229
  if ["iframe", "source"].include?(node.name)
225
230
  node["data-media-id"] = media_id
226
231
  if node["data-is-media-attachment"]
227
232
  node.delete("data-is-media-attachment")
228
- return media_attachment_iframe_url(file.id, node["data-media-type"])
233
+ return media_attachment_iframe_url(file["id"], node["data-media-type"])
229
234
  else
230
235
  return media_iframe_url(media_id, node["data-media-type"])
231
236
  end
@@ -52,9 +52,9 @@ module CanvasLinkMigrator
52
52
  migration_data["destination_hosts"]
53
53
  end
54
54
 
55
- def attachment_path_id_lookup; end
56
-
57
- def attachment_path_id_lookup_lower; end
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"]
@@ -93,6 +93,7 @@ module CanvasLinkMigrator
93
93
  end
94
94
 
95
95
  def convert_migration_id(type, migration_id)
96
+ type = "modules" if type == "context_modules"
96
97
  id = if CanvasLinkMigrator::LinkParser::KNOWN_REFERENCE_TYPES.include? type
97
98
  resources.dig(type, migration_id, "destination", "id")
98
99
  end
@@ -101,5 +102,9 @@ module CanvasLinkMigrator
101
102
  # we'll check both here
102
103
  convert_announcement_migration_id(migration_id) if type == "discussion_topics"
103
104
  end
105
+
106
+ def lookup_attachment_by_migration_id(migration_id)
107
+ resources.dig("files", migration_id, "destination")
108
+ end
104
109
  end
105
110
  end
@@ -56,62 +56,55 @@ describe CanvasLinkMigrator::ImportedHtmlConverter do
56
56
  end
57
57
  end
58
58
 
59
- # it "finds an attachment by migration id" do
60
- # test_string = %{<p>This is an image: <br /><img src="%24CANVAS_OBJECT_REFERENCE%24/attachments/F" alt=":(" /></p>}
61
- # expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/6/preview" alt=":("></p>}, nil])
62
- # end
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
59
+ it "finds an attachment by migration id" do
60
+ test_string = %{<p>This is an image: <br /><img src="%24CANVAS_OBJECT_REFERENCE%24/attachments/F" alt=":(" /></p>}
61
+ expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/6/preview" alt=":("></p>}, nil])
62
+ end
73
63
 
74
- # it "finds an attachment by a path with a space" do
75
- # att = make_test_att
76
- # @migration.attachment_path_id_lookup = { "subfolder/with a space/test.png" => att.migration_id }
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>}
77
66
 
78
- # test_string = %(<img src="subfolder/with%20a%20space/test.png" alt="nope" />)
79
- # expect(@converter.convert_exported_html(test_string)).to eq %(<img src="#{@path}files/#{att.id}/preview" alt="nope">)
67
+ # if there isn't a path->migration id map it'll be a relative course file path
68
+ expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).exactly(4).times.and_return({})
69
+ html, bad_links = @converter.convert_exported_html(test_string)
70
+ expect(html).to eq %{<p>This is an image: <br><img src="#{@path}file_contents/course%20files/test.png" alt=":("></p>}
71
+ expect(bad_links[0]).to include({ link_type: :file, missing_url: "/courses/2/file_contents/course%20files/test.png" })
80
72
 
81
- # test_string = %(<img src="subfolder/with+a+space/test.png" alt="nope" />)
82
- # expect(@converter.convert_exported_html(test_string)).to eq %(<img src="#{@path}files/#{att.id}/preview" alt="nope">)
83
- # end
73
+ expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_call_original
74
+ expect(@converter.convert_exported_html(test_string)).to eq([%{<p>This is an image: <br><img src="#{@path}files/5/preview" alt=":("></p>}, nil])
75
+ end
84
76
 
85
- # it "finds an attachment even if the link has an extraneous folder" do
86
- # att = make_test_att
87
- # @migration.attachment_path_id_lookup = { "subfolder/test.png" => att.migration_id }
77
+ it "finds an attachment by a path with a space" do
78
+ test_string = %(<img src="subfolder/with%20a%20space/test.png" alt="nope" />)
79
+ expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
88
80
 
89
- # test_string = %(<img src="anotherfolder/subfolder/test.png" alt="nope" />)
90
- # expect(@converter.convert_exported_html(test_string)).to eq %(<img src="#{@path}files/#{att.id}/preview" alt="nope">)
91
- # end
81
+ test_string = %(<img src="subfolder/with+a+space/test.png" alt="nope" />)
82
+ expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
83
+ end
92
84
 
93
- # it "finds an attachment by path if capitalization is different" do
94
- # att = make_test_att
95
- # @migration.attachment_path_id_lookup = { "subfolder/withCapital/test.png" => "wrong!" }
96
- # @migration.attachment_path_id_lookup_lower = { "subfolder/withcapital/test.png" => att.migration_id }
85
+ it "finds an attachment even if the link has an extraneous folder" do
86
+ test_string = %(<img src="anotherfolder/subfolder/test.png" alt="nope" />)
87
+ expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/7/preview" alt="nope">), nil])
88
+ end
97
89
 
98
- # test_string = %(<img src="subfolder/WithCapital/TEST.png" alt="nope" />)
99
- # expect(@converter.convert_exported_html(test_string)).to eq %(<img src="#{@path}files/#{att.id}/preview" alt="nope">)
100
- # end
90
+ it "finds an attachment by path if capitalization is different" do
91
+ expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_return({ "subfolder/withCapital/test.png" => "wrong!" })
92
+ expect(@converter.link_resolver).to receive(:attachment_path_id_lookup).twice.and_return({ "subfolder/withcapital/test.png" => "F" })
101
93
 
102
- # it "finds an attachment with query params" do
103
- # att = make_test_att
104
- # @migration.attachment_path_id_lookup = { "test.png" => att.migration_id }
94
+ test_string = %(<img src="subfolder/WithCapital/TEST.png" alt="nope" />)
95
+ expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/6/preview" alt="nope">), nil])
96
+ end
105
97
 
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/#{att.id}/customaction?customparam=1" alt="nope">)
98
+ it "finds an attachment with query params" do
99
+ test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?canvas_customaction=1&canvas_qs_customparam=1" alt="nope" />)
100
+ expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/customaction?customparam=1" alt="nope">), nil])
108
101
 
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/#{att.id}/preview?customparam2=3" alt="nope">)
102
+ test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?canvas_qs_customparam2=3" alt="nope" />)
103
+ expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview?customparam2=3" alt="nope">), nil])
111
104
 
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/#{att.id}/preview" alt="nope">)
114
- # end
105
+ test_string = %(<img src="%24IMS_CC_FILEBASE%24/test.png?notarelevantparam" alt="nope" />)
106
+ expect(@converter.convert_exported_html(test_string)).to eq([%(<img src="#{@path}files/5/preview" alt="nope">), nil])
107
+ end
115
108
  end
116
109
 
117
110
  it "converts picture source srcsets" do
@@ -69,10 +69,22 @@ describe CanvasLinkMigrator::LinkResolver do
69
69
  expect(link[:new_value]).to eq("/courses/2/discussion_topics/10?foo=bar")
70
70
  end
71
71
 
72
+ it "converts module links" do
73
+ link = { link_type: :object, type: "modules", migration_id: "J", query: "?foo=bar" }
74
+ resolver.resolve_link!(link)
75
+ expect(link[:new_value]).to eq("/courses/2/modules/36?foo=bar")
76
+ end
77
+
72
78
  it "converters other links" do
73
79
  link = { link_type: :object, type: "assignments", migration_id: "I", query: "#fie" }
74
80
  resolver.resolve_link!(link)
75
81
  expect(link[:new_value]).to eq("/courses/2/assignments/12#fie")
76
82
  end
77
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
78
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": {
@@ -69,6 +85,16 @@
69
85
  }
70
86
  }
71
87
  },
88
+ "modules": {
89
+ "J": {
90
+ "destination": {
91
+ "id": "36"
92
+ },
93
+ "source": {
94
+ "id": "22"
95
+ }
96
+ }
97
+ },
72
98
  "wiki_pages": {
73
99
  "A": {
74
100
  "destination": {
@@ -82,12 +108,6 @@
82
108
  }
83
109
  }
84
110
  },
85
- "file_tree": {
86
- "folder 1": {
87
- "id": "1",
88
- "sub_folders": {}
89
- }
90
- },
91
111
  "source_course": "1",
92
112
  "source_host": "pineapple.edu"
93
- }
113
+ }
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: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mysti Lilla
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-07-25 00:00:00.000000000 Z
12
+ date: 2023-08-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rack
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: bundler
44
58
  requirement: !ruby/object:Gem::Requirement