github-to-canvas 0.1.5 → 0.1.7.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b18946099c8b4fd23e1c2230f71fac458f932079fd22ada5297732358fec4d0e
4
- data.tar.gz: '092e1b7854f2b4c4026f0713599d423d8eac6431ae16e4f9372c1a00ebb9775c'
3
+ metadata.gz: 53c9c96308fae1d78f27bc68e80fee55baf2ff23d381866edfd1d114b30601ec
4
+ data.tar.gz: bf7570a5be4657e102659454295beb72023864ceb20562b51858fa094997b5f7
5
5
  SHA512:
6
- metadata.gz: d11be9f366fc3a457a671669a57802d6a1a8cc8ff3b0a7e9fa3ee10b4b8b91334cbaa336d39c1e3057c41e787619716d76df3e8523d918393cbb1b6fa9737549
7
- data.tar.gz: 85d91f81000c82d55cb45e02f31c9aa3b2e241c785cb58366f5fbef99b72c7ce76e7e9d70f101cedb7f54c5082b2061926e0453cd8a162227cdba78f96c54e71
6
+ metadata.gz: adbf272b0121b81582d6520bc0c3881980276ede161cb97515d1792563cb29a603c93e7bf35790db1eacc89fb471b68127dccaf24fa43f3205cd758fa53739c2
7
+ data.tar.gz: 45182fbe2c428468ed967650a5e42ad496af4fa8dca236b61ec52ef9aa0ace3c209ece9a52eadd46849252a7dd6f9fa7c047a5017057bb96ca5143ee3155784a
@@ -108,6 +108,10 @@ OptionParser.new do |opts|
108
108
  "Adds additional Flatiron School HTML after markdown conversion") do |f|
109
109
  options[:fis] = true
110
110
  end
111
+ opts.on("-g", "--git-links",
112
+ "Adds additional GitHub after markdown conversion") do |f|
113
+ options[:git_links] = true
114
+ end
111
115
  opts.on("--aaq",
112
116
  "Adds AAQ flag to HTML header appended with --fis-links") do |aaq|
113
117
  options[:aaq] = aaq
@@ -188,6 +192,15 @@ OptionParser.new do |opts|
188
192
  "Escapes all HTML included in source markdown by replacing '<' and '>' with HTML charset values") do |html|
189
193
  options[:contains_html] = html
190
194
  end
195
+ opts.on("--canvas-to-canvas COURSE",
196
+ "Copies an existing Canvas lesson into another Canvas lesson") do |canvas_to_canvas|
197
+ options[:canvas_to_canvas] = canvas_to_canvas
198
+ end
199
+ opts.on("--build-from-csv CSV",
200
+ "Build a course usin a CSV of lesson repos, names, modules, and types") do |csv_build|
201
+ options[:csv_build] = csv_build
202
+ end
203
+
191
204
 
192
205
  end.parse!
193
206
 
@@ -202,6 +215,16 @@ if options[:read_from_canvas]
202
215
  abort
203
216
  end
204
217
 
218
+ if options[:canvas_to_canvas]
219
+ GithubToCanvas.new(mode: 'canvas_copy',
220
+ filepath: options[:canvas_to_canvas],
221
+ course_id: options[:course_id],
222
+ type: options[:type],
223
+ id: options[:id]
224
+ )
225
+ abort
226
+ end
227
+
205
228
  if options[:read_from_github]
206
229
  GithubToCanvas.new(mode: 'github_read',
207
230
  filepath: options[:read_from_github],
@@ -267,13 +290,29 @@ if options[:csv]
267
290
  abort
268
291
  end
269
292
 
293
+ if options[:csv_build]
294
+ GithubToCanvas.new(mode: 'csv_build',
295
+ file_to_convert: options[:csv_build],
296
+ course_id: options[:course_id],
297
+ fis_links: !!options[:fis],
298
+ remove_header_and_footer: !!options[:remove_header_and_footer],
299
+ aaq: !!options[:aaq],
300
+ forkable: !!options[:forkable],
301
+ branch: options[:branch],
302
+ contains_html: options[:contains_html],
303
+ git_links: !!options[:git_links])
304
+ abort
305
+ end
306
+
270
307
  if options[:build_course]
271
308
  GithubToCanvas.new(mode: 'build_course',
272
309
  file_to_convert: options[:build_course],
273
310
  fis_links: !!options[:fis],
274
311
  remove_header_and_footer: !!options[:remove_header_and_footer],
275
312
  aaq: !!options[:aaq],
276
- forkable: !!options[:forkable])
313
+ forkable: !!options[:forkable],
314
+ contains_html: options[:contains_html],
315
+ git_links: !!options[:git_links])
277
316
  abort
278
317
  end
279
318
 
@@ -286,7 +325,8 @@ if options[:add_to_course]
286
325
  remove_header_and_footer: !!options[:remove_header_and_footer],
287
326
  forkable: !!options[:forkable],
288
327
  aaq: !!options[:aaq],
289
- contains_html: options[:contains_html])
328
+ contains_html: options[:contains_html],
329
+ git_links: !!options[:git_links])
290
330
  else
291
331
  puts '--course required'
292
332
  end
@@ -300,7 +340,8 @@ if options[:update_course_lessons]
300
340
  remove_header_and_footer: !!options[:remove_header_and_footer],
301
341
  forkable: !!options[:forkable],
302
342
  aaq: !!options[:aaq],
303
- contains_html: options[:contains_html])
343
+ contains_html: options[:contains_html],
344
+ git_links: !!options[:git_links])
304
345
  abort
305
346
  end
306
347
 
@@ -360,6 +401,7 @@ if options[:create_lesson]
360
401
  type: options[:type],
361
402
  save_to_github: !!options[:save_to_github],
362
403
  fis_links: !!options[:fis],
404
+ git_links: !!options[:git_links],
363
405
  remove_header_and_footer: !!options[:remove_header_and_footer],
364
406
  only_update_content: !!options[:only_content],
365
407
  forkable: !!options[:forkable],
@@ -377,7 +419,8 @@ if options[:align]
377
419
  name: options[:name],
378
420
  type: options[:type],
379
421
  save_to_github: !!options[:save_to_github],
380
- fis_links: !!options[:fis],
422
+ fis_links: !!options[:fis],
423
+ git_links: !!options[:git_links],
381
424
  remove_header_and_footer: !!options[:remove_header_and_footer],
382
425
  only_update_content: !!options[:only_content],
383
426
  forkable: !!options[:forkable],
@@ -1,4 +1,5 @@
1
1
  require 'byebug'
2
+ require 'csv'
2
3
  require_relative './github-to-canvas/create_canvas_lesson'
3
4
  require_relative './github-to-canvas/update_canvas_lesson'
4
5
  require_relative './github-to-canvas/canvas_dotfile'
@@ -26,6 +27,8 @@ class GithubToCanvas
26
27
  CanvasInterface.csv(options[:file_to_convert])
27
28
  when 'canvas_read'
28
29
  puts CanvasInterface.read_lesson(options[:filepath])
30
+ when 'canvas_copy'
31
+ CanvasInterface.copy_lesson(options)
29
32
  when 'github_read'
30
33
  html = RepositoryConverter.remote_file_conversion(options)
31
34
  puts RepositoryConverter.adjust_converted_html(options, html)
@@ -43,16 +46,25 @@ class GithubToCanvas
43
46
  CanvasInterface.update_all_related_lessons(options, name, html)
44
47
 
45
48
  when 'github_create'
49
+ if (!options[:branch])
50
+ options[:branch] = 'master'
51
+ end
46
52
  html = RepositoryConverter.remote_file_conversion(options)
47
- name = options[:name] ? options[:name] : RepositoryInterface.get_name(options[:filepath], html)
48
- html = RepositoryConverter.adjust_converted_html(options, html)
49
53
 
54
+ html = RepositoryConverter.adjust_converted_html(options, html)
55
+ name = options[:name] ? options[:name] : RepositoryInterface.get_name(options[:filepath], html)
56
+ byebug
57
+ puts name
50
58
  response = CanvasInterface.create_lesson(options, name, html)
51
59
 
52
60
  puts "Canvas lesson created. Lesson available at #{response['html_url']}"
53
61
  when 'github_align'
62
+ if (!options[:branch])
63
+ options[:branch] = 'master'
64
+ end
54
65
  html = RepositoryConverter.remote_file_conversion(options)
55
66
  name = options[:name] ? options[:name] : RepositoryInterface.get_name(options[:filepath], html)
67
+
56
68
  html = RepositoryConverter.adjust_converted_html(options, html)
57
69
  response = CanvasInterface.update_existing_lesson(options, name, html)
58
70
  puts "Canvas lesson updated. Lesson available at #{response['html_url']}"
@@ -152,6 +164,60 @@ class GithubToCanvas
152
164
  end
153
165
  }
154
166
  }
167
+ when 'csv_build'
168
+ if !options[:course_id]
169
+ course_info = {
170
+ name: "CSV Build Test",
171
+ course_code: "CSV-TEST"
172
+ }
173
+ created_course_info = CanvasInterface.create_course(course_info)
174
+ puts "Course created - #{created_course_info["id"]}"
175
+ puts "Make sure to add yourself as a teacher to this course before continuing, then press Enter/Return"
176
+ input = gets
177
+ options[:course_id] = created_course_info["id"]
178
+ else
179
+ puts "Adding to course #{options[:course_id]}"
180
+ end
181
+
182
+ csv_data = CSV.read(options[:file_to_convert])
183
+ created_module_info = {
184
+ "id" => "",
185
+ "name" => ""
186
+ }
187
+
188
+ csv_data.each { |lesson|
189
+ # lesson[0] == repo
190
+ # lesson[1] == name
191
+ # lesson[2] == module
192
+ # lesson[3] == type
193
+ # lesson[4] == yes/no contains HTML
194
+ module_info = {
195
+ name: lesson[2]
196
+ }
197
+ if created_module_info["name"] != module_info[:name]
198
+ created_module_info = CanvasInterface.create_module(options[:course_id], module_info)
199
+ puts "New module created - #{created_module_info["id"]} - #{created_module_info["name"]}"
200
+ end
201
+
202
+ options[:filepath] = lesson[0]
203
+ options[:name] = lesson[1]
204
+ options[:type] = lesson[3]
205
+ options[:branch] = "master" if !options[:branch]
206
+ if !options[:contains_html]
207
+ options[:contains_html] = (lesson[4] == "yes" || lesson[4] == "Yes") ? true : false
208
+ end
209
+
210
+
211
+ html = RepositoryConverter.remote_file_conversion(options)
212
+ html = RepositoryConverter.adjust_converted_html(options, html)
213
+ created_lesson_info = CanvasInterface.create_lesson(options, lesson[1], html)
214
+ created_lesson_info["page_url"] = created_lesson_info["url"] if !created_lesson_info["page_url"]
215
+ created_lesson_info["id"] = created_lesson_info["page_url"] if !created_lesson_info["id"]
216
+ created_lesson_info["type"] = options[:type]
217
+ puts "Creating lesson - #{options[:name]}"
218
+ response = CanvasInterface.add_to_module(options[:course_id], created_module_info, created_lesson_info)
219
+
220
+ }
155
221
  else
156
222
  puts VERSION
157
223
  end
@@ -51,21 +51,21 @@ class CanvasInterface
51
51
  # POST /api/v1/courses/:course_id/modules/:module_id/items
52
52
  url = "#{ENV['CANVAS_API_PATH']}/courses/#{course_id}/modules/#{module_info["id"]}/items"
53
53
 
54
- if lesson_info["type"] == "Page"
54
+ if lesson_info["type"] == "Page" || lesson_info["type"] == "page"
55
55
  payload = {
56
- 'module_item[title]' => lesson_info["title"],
57
- 'module_item[type]' => lesson_info["type"],
58
- 'module_item[indent]' => 0,
59
- 'module_item[page_url]' => lesson_info["id"],
60
- 'module_item[completion_requirement][type]' => 'must_view'
61
- }
56
+ 'module_item[title]' => lesson_info["title"],
57
+ 'module_item[type]' => lesson_info["type"].capitalize,
58
+ 'module_item[indent]' => 0,
59
+ 'module_item[page_url]' => lesson_info["id"],
60
+ 'module_item[completion_requirement][type]' => 'must_view'
61
+ }
62
62
  elsif lesson_info["type"] == "Quiz"
63
63
  puts "Quiz needs to be added manually - #{lesson_info['title']} - lesson_info["
64
64
  else
65
65
 
66
66
  payload = {
67
67
  'module_item[title]' => lesson_info["title"],
68
- 'module_item[type]' => lesson_info["type"],
68
+ 'module_item[type]' => lesson_info["type"].capitalize,
69
69
  'module_item[indent]' => 1,
70
70
  'module_item[content_id]' => lesson_info["id"],
71
71
  'module_item[completion_requirement][type]' => 'must_submit'
@@ -74,6 +74,8 @@ class CanvasInterface
74
74
  begin
75
75
  response = RestClient.post(url, payload, self.headers)
76
76
  rescue
77
+ byebug
78
+
77
79
  puts "Something went wrong while adding lesson #{lesson_info["id"]} to module #{module_info["id"]} in course #{course_id}" if lesson_info["type"] == "Assignment"
78
80
  puts "Something went wrong while adding lesson #{lesson_info["page_url"]} to module #{module_info["id"]} in course #{course_id}" if lesson_info["type"] == "Page"
79
81
  abort
@@ -340,8 +342,37 @@ class CanvasInterface
340
342
  puts course_info.to_yaml
341
343
  end
342
344
 
343
-
345
+ def self.copy_lesson(options)
346
+ types = ["page", "assignment", "quiz", "discussion"]
347
+ url = options[:filepath]
348
+ type = types.find {|type| url.match(type)}
349
+ options[:type] = type
350
+ if !url.include?(ENV['CANVAS_API_PATH'])
351
+ url = url.sub(/^.*\/\/.*?\//,"#{ENV['CANVAS_API_PATH']}/")
352
+ end
353
+
354
+ response = RestClient.get(url, headers={
355
+ "Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
356
+ })
344
357
 
358
+ lesson_info = JSON.parse(response)
359
+ lesson_info = lesson_info.slice("title",
360
+ "name",
361
+ "description",
362
+ "body",
363
+ "message",
364
+ "shuffle_answers",
365
+ "allowed_attempts",
366
+ "question_count"
367
+ )
368
+ if options[:type] == "page"
369
+ self.update_existing_lesson(options, lesson_info["title"], lesson_info["body"])
370
+ else
371
+ self.update_existing_lesson(options, lesson_info["name"], lesson_info["description"])
372
+ end
373
+
374
+
375
+ end
345
376
 
346
377
  def self.build_payload(options, name, html)
347
378
  if options[:only_update_content]
@@ -66,8 +66,7 @@ class GithubInterface
66
66
  puts 'Error reading ' + url
67
67
  end
68
68
  end
69
-
70
-
69
+ response.body
71
70
  end
72
71
 
73
72
  def self.save_to_github(filepath, branch)
@@ -27,9 +27,15 @@ class RepositoryConverter
27
27
  markdown = GithubInterface.read_remote(options[:filepath])
28
28
  raw_remote_url = self.set_raw_image_remote_url(options[:filepath])
29
29
  if options[:contains_html]
30
- puts "Contains HTML"
31
- puts options[:contains_html]
32
- markdown = self.escape_existing_html(markdown)
30
+ begin
31
+ markdown = self.escape_existing_html(markdown)
32
+ rescue
33
+ puts "Error reading remote markdown"
34
+ abort
35
+ end
36
+ end
37
+ if (!options[:branch])
38
+ options[:branch] = 'master'
33
39
  end
34
40
  markdown = self.fix_local_images(options, markdown, raw_remote_url)
35
41
  html = self.convert_to_html(markdown)
@@ -37,9 +43,10 @@ class RepositoryConverter
37
43
  end
38
44
 
39
45
  def self.convert_to_html(markdown)
40
- redcarpet = Redcarpet::Markdown.new(CustomRender, options={tables: true, autolink: true, fenced_code_blocks: true})
46
+ renderer = CustomRender.new(escape_html: true, prettify: true, hard_wrap: true)
47
+ redcarpet = Redcarpet::Markdown.new(CustomRender, options={tables: true, autolink: true, fenced_code_blocks: true, disable_indented_code_blocks: true})
41
48
  html = redcarpet.render(markdown)
42
- self.remove_line_breaks(html)
49
+ # self.remove_line_breaks(html)
43
50
  end
44
51
 
45
52
  def self.adjust_converted_html(options, html)
@@ -48,7 +55,7 @@ class RepositoryConverter
48
55
  html = self.remove_header_and_footer(html)
49
56
  end
50
57
 
51
- if options[:fis_links]
58
+ if options[:fis_links] || options[:git_links]
52
59
  html = self.add_fis_links(options, html)
53
60
  end
54
61
 
@@ -60,8 +67,31 @@ class RepositoryConverter
60
67
  end
61
68
 
62
69
  def self.fix_escaped_inline_html_code(html)
63
- html = html.gsub("<code>&amp;lt;", "<code>&lt;")
70
+
71
+ # stops HTML/JSX code blocks from rendering as HTML in Canvas
64
72
  html = html.gsub("&amp;gt;</code>", "&gt;</code>")
73
+ html = html.gsub("&amp;gt;</code>", "&gt;</code>")
74
+
75
+ # fixes < and > code snippets
76
+ html = html.gsub("&amp;lt;", "&lt;")
77
+ html = html.gsub("&amp;gt;", "&gt;")
78
+
79
+ # # fixes blockquotes
80
+ # html = html.gsub(/\n<p>&gt\;(.*)\n&gt\;/) { |bq|
81
+ # bq.delete_prefix!("\n<p>&gt;")
82
+ # "\n<blockquote>" + bq
83
+ # }
84
+ # html = html.gsub(/\n&gt\;(.*)\n&gt\;/) { |bq|
85
+ # bq.delete_prefix!("\n&gt;")
86
+ # " " + bq
87
+ # }
88
+ # html = html.gsub(/\n&gt\;(.*)<\/p>/) { |bq|
89
+ # bq.delete_prefix!("\n&gt\;")
90
+ # bq.delete_suffix!("</p>")
91
+ # " " + bq + "</blockquote>"
92
+ # }
93
+
94
+ html
65
95
  end
66
96
 
67
97
 
@@ -84,6 +114,9 @@ class RepositoryConverter
84
114
 
85
115
  def self.remove_footer(readme)
86
116
  readme.gsub(/<p class='util--hide'(.+?)<\/p>/,"")
117
+ readme.gsub(/<p data-visibility='hidden'(.+?)<\/p>/,"")
118
+ readme.gsub(/<p>&lt\;p data-visibility=&#39\;hidden&#39(.+?)<\/p>/,"")
119
+ readme.gsub(/<p>&lt\;p class=&#39;util--hide&#39\;(.+?)<\/p>/,"")
87
120
  end
88
121
 
89
122
  def self.remove_html_header(html)
@@ -155,7 +188,12 @@ class RepositoryConverter
155
188
  image_source = image_source.gsub(/(\'|\")/, "")
156
189
  image_source = image_source.gsub(/src=/, '')
157
190
  image_source = image_source.strip
158
- 'src="' + raw_remote_url + '/' + branch + '/' + image_source + '"'
191
+
192
+ begin
193
+ 'src="' + raw_remote_url + '/' + branch + '/' + image_source + '"'
194
+ rescue
195
+ byebug
196
+ end
159
197
  else
160
198
  image_source
161
199
  end
@@ -185,12 +223,12 @@ class RepositoryConverter
185
223
  def self.add_fis_links(options, html)
186
224
  repo_info = self.get_repo_info(options[:filepath])
187
225
  html = html.sub(/<div id="git-data-element.*<header class="fis-header.*<\/header>/,'') # remove existing fis header
188
- header = self.create_github_link_header(repo_info[:repo_path], options[:forkable])
226
+ header = self.create_github_link_header(repo_info[:repo_path], options)
189
227
  data_element = self.create_data_element(repo_info[:repo_org], repo_info[:repo_name], options[:aaq])
190
228
  data_element + header + html
191
229
  end
192
230
 
193
- def self.create_github_link_header(repo_path, forkable)
231
+ def self.create_github_link_header(repo_path, options)
194
232
  # add link to associated repository
195
233
  github_repo_link = "<a class='fis-git-link' href='#{repo_path}' target='_blank' rel='noopener'><img id='repo-img' title='Open GitHub Repo' alt='GitHub Repo' /></a>"
196
234
 
@@ -198,9 +236,12 @@ class RepositoryConverter
198
236
  github_issue_link = "<a class='fis-git-link' href='#{repo_path}/issues/new' target='_blank' rel='noopener'><img id='issue-img' title='Create New Issue' alt='Create New Issue' /></a>"
199
237
 
200
238
  # add link to fork (forking handled by separate Flatiron server, generation of link handled via custom Canvas JS theme file)
201
- if (forkable)
202
- github_fork_link = "<a class='fis-fork-link' id='fork-link' href='#' target='_blank' rel='noopener'><img id='fork-img' title='Fork This Assignment' alt='Fork This Assignment' /></a>"
239
+
240
+ if (options[:forkable])
241
+ github_fork_link = "<a class='fis-fork-link' id='fork-link' href='#{repo_path}/fork' target='_blank' rel='noopener'><img id='fork-img' title='Fork This Assignment' alt='Fork This Assignment' /></a>"
203
242
  "<header class='fis-header' style='visibility: hidden;'>#{github_fork_link}#{github_repo_link}#{github_issue_link}</header>"
243
+ elsif options[:git_links]
244
+ "<header class='fis-header'>#{github_repo_link}#{github_issue_link}</header>"
204
245
  else
205
246
  "<header class='fis-header' style='visibility: hidden;'>#{github_repo_link}#{github_issue_link}</header>"
206
247
  end
@@ -1,3 +1,3 @@
1
1
  class GithubToCanvas
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.7"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: github-to-canvas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - maxwellbenton
@@ -104,11 +104,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
104
  version: '0'
105
105
  required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - ">="
107
+ - - ">"
108
108
  - !ruby/object:Gem::Version
109
- version: '0'
109
+ version: 1.3.1
110
110
  requirements: []
111
- rubygems_version: 3.0.8
111
+ rubygems_version: 3.2.3
112
112
  signing_key:
113
113
  specification_version: 4
114
114
  summary: github-to-canvas is a tool for migrating and aligning GitHub content with