github-to-canvas 0.1.3 → 0.1.9
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/bin/github-to-canvas +92 -12
- data/lib/github-to-canvas.rb +109 -4
- data/lib/github-to-canvas/canvas_interface.rb +53 -20
- data/lib/github-to-canvas/github_interface.rb +1 -1
- data/lib/github-to-canvas/repository_converter.rb +82 -30
- data/lib/github-to-canvas/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71e183a1ea3659fdc71af9af4c1ce0370be119f4241e8773ac82fdee9400cf48
|
4
|
+
data.tar.gz: ce08e0ec8f3f64471a4966a955e454d8a25cd95e9b9555dd61ca550ec77fe41b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b04300b61b6301f32512ca328f27affaa186082e0e35d8eeab7c748b77ba3c10a07a7309ba1d3e92563007910da3c9e70a7a1db37ce184b48763cc8d455ffb7
|
7
|
+
data.tar.gz: 2cbe19f6cd61338619072f9f07e215762ce45ffbd3b3aa0672d3f77a1c3bd3a8e7837b5e237bf6b01bd4058ac05afaf5c547b82c1b829a8787b344c88fc21276
|
data/bin/github-to-canvas
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require 'byebug'
|
2
1
|
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
3
4
|
require 'optparse'
|
4
5
|
require 'github-to-canvas'
|
5
6
|
|
@@ -76,7 +77,6 @@ OptionParser.new do |opts|
|
|
76
77
|
end
|
77
78
|
opts.on("-tTYPE", "--type TYPE",
|
78
79
|
"Sets the type Canvas lesson to be created (page or assignment). If no type, type decided based on repository structure") do |type|
|
79
|
-
# byebug
|
80
80
|
options[:type] = type.downcase
|
81
81
|
abort if type == 'quiz' || type == 'discussion'
|
82
82
|
# if type == 'page' || type == 'assignment' || type == 'discussion' || type == 'quiz' || type == 'Page' || type == 'Assignment' || type == 'Discussion' || type == 'Quiz'
|
@@ -106,10 +106,18 @@ OptionParser.new do |opts|
|
|
106
106
|
"Adds additional Flatiron School HTML after markdown conversion") do |f|
|
107
107
|
options[:fis] = true
|
108
108
|
end
|
109
|
+
opts.on("-g", "--git-links",
|
110
|
+
"Adds additional GitHub after markdown conversion") do |f|
|
111
|
+
options[:git_links] = true
|
112
|
+
end
|
109
113
|
opts.on("--aaq",
|
110
114
|
"Adds AAQ flag to HTML header appended with --fis-links") do |aaq|
|
111
115
|
options[:aaq] = aaq
|
112
116
|
end
|
117
|
+
opts.on("--prework",
|
118
|
+
"Adds prework flag to HTML header appended with --fis-links") do |prework|
|
119
|
+
options[:prework] = prework
|
120
|
+
end
|
113
121
|
opts.on("--forkable",
|
114
122
|
"Used with --fis-links, adds fork button to HTML header injected into Canvas lesson") do |remote|
|
115
123
|
options[:forkable] = true
|
@@ -138,10 +146,14 @@ OptionParser.new do |opts|
|
|
138
146
|
"REQUIRES -f or --file Associates canvas lessons with repositories. Use query to create required YAML file") do |file|
|
139
147
|
options[:map] = file
|
140
148
|
end
|
141
|
-
opts.on("--
|
142
|
-
"
|
143
|
-
options[:
|
149
|
+
opts.on("--urls-only",
|
150
|
+
"Use with --map. Outputs repo URLs instead of YAML") do |urls|
|
151
|
+
options[:urls_only] = urls
|
144
152
|
end
|
153
|
+
opts.on("--csv",
|
154
|
+
"Returns a course's lesson struction as CSV") do |csv|
|
155
|
+
options[:csv] = csv
|
156
|
+
end
|
145
157
|
opts.on("--read-from-canvas CANVAS_URL",
|
146
158
|
"Retrieves an existing Canvas lesson using the provided URL") do |url|
|
147
159
|
options[:read_from_canvas] = url
|
@@ -182,6 +194,19 @@ OptionParser.new do |opts|
|
|
182
194
|
"Escapes all HTML included in source markdown by replacing '<' and '>' with HTML charset values") do |html|
|
183
195
|
options[:contains_html] = html
|
184
196
|
end
|
197
|
+
opts.on("--canvas-to-canvas COURSE",
|
198
|
+
"Copies an existing Canvas lesson into another Canvas lesson") do |canvas_to_canvas|
|
199
|
+
options[:canvas_to_canvas] = canvas_to_canvas
|
200
|
+
end
|
201
|
+
opts.on("--build-from-csv CSV",
|
202
|
+
"Build a course using a CSV of lesson repos, names, modules, and types") do |csv_build|
|
203
|
+
options[:csv_build] = csv_build
|
204
|
+
end
|
205
|
+
opts.on("--update-from-csv CSV",
|
206
|
+
"Update a course using a CSV of lesson repos, names, modules, types, lesson IDs, and course IDs") do |csv_align|
|
207
|
+
options[:csv_align] = csv_align
|
208
|
+
end
|
209
|
+
|
185
210
|
|
186
211
|
end.parse!
|
187
212
|
|
@@ -196,6 +221,16 @@ if options[:read_from_canvas]
|
|
196
221
|
abort
|
197
222
|
end
|
198
223
|
|
224
|
+
if options[:canvas_to_canvas]
|
225
|
+
GithubToCanvas.new(mode: 'canvas_copy',
|
226
|
+
filepath: options[:canvas_to_canvas],
|
227
|
+
course_id: options[:course_id],
|
228
|
+
type: options[:type],
|
229
|
+
id: options[:id]
|
230
|
+
)
|
231
|
+
abort
|
232
|
+
end
|
233
|
+
|
199
234
|
if options[:read_from_github]
|
200
235
|
GithubToCanvas.new(mode: 'github_read',
|
201
236
|
filepath: options[:read_from_github],
|
@@ -203,6 +238,7 @@ if options[:read_from_github]
|
|
203
238
|
forkable: !!options[:forkable],
|
204
239
|
fis_links: !!options[:fis],
|
205
240
|
aaq: !!options[:aaq],
|
241
|
+
prework: !!options[:prework],
|
206
242
|
contains_html: options[:contains_html])
|
207
243
|
abort
|
208
244
|
end
|
@@ -218,6 +254,7 @@ if options[:create_from_github]
|
|
218
254
|
forkable: !!options[:forkable],
|
219
255
|
fis_links: !!options[:fis],
|
220
256
|
aaq: !!options[:aaq],
|
257
|
+
prework: !!options[:prework],
|
221
258
|
contains_html: options[:contains_html])
|
222
259
|
else
|
223
260
|
puts 'Canvas course ID and lesson type required. Example: github-to-canvas --create-from-github URL --course ID --type TYPE'
|
@@ -237,6 +274,7 @@ if options[:align_from_github]
|
|
237
274
|
forkable: !!options[:forkable],
|
238
275
|
fis_links: !!options[:fis],
|
239
276
|
aaq: !!options[:aaq],
|
277
|
+
prework: !!options[:prework],
|
240
278
|
contains_html: options[:contains_html])
|
241
279
|
else
|
242
280
|
puts 'Canvas course ID, lesson ID, and type required. Example: github-to-canvas --create-from-github URL --course COURSE_ID --id LESSON_ID --type TYPE'
|
@@ -250,12 +288,43 @@ if options[:query]
|
|
250
288
|
end
|
251
289
|
|
252
290
|
if options[:map]
|
253
|
-
GithubToCanvas.new(mode: 'map',
|
291
|
+
GithubToCanvas.new(mode: 'map',
|
292
|
+
file_to_convert: options[:map],
|
293
|
+
urls_only: !!options[:urls_only],
|
294
|
+
csv: !!options[:csv])
|
295
|
+
abort
|
296
|
+
end
|
297
|
+
|
298
|
+
# if options[:csv]
|
299
|
+
# GithubToCanvas.new(mode: 'csv', file_to_convert: options[:csv])
|
300
|
+
# abort
|
301
|
+
# end
|
302
|
+
|
303
|
+
if options[:csv_build]
|
304
|
+
GithubToCanvas.new(mode: 'csv_build',
|
305
|
+
file_to_convert: options[:csv_build],
|
306
|
+
course_id: options[:course_id],
|
307
|
+
fis_links: !!options[:fis],
|
308
|
+
remove_header_and_footer: !!options[:remove_header_and_footer],
|
309
|
+
aaq: !!options[:aaq],
|
310
|
+
forkable: !!options[:forkable],
|
311
|
+
branch: options[:branch],
|
312
|
+
contains_html: options[:contains_html],
|
313
|
+
git_links: !!options[:git_links])
|
254
314
|
abort
|
255
315
|
end
|
256
316
|
|
257
|
-
if options[:
|
258
|
-
GithubToCanvas.new(mode: '
|
317
|
+
if options[:csv_align]
|
318
|
+
GithubToCanvas.new(mode: 'csv_align',
|
319
|
+
file_to_convert: options[:csv_align],
|
320
|
+
course_id: options[:course_id],
|
321
|
+
fis_links: !!options[:fis],
|
322
|
+
remove_header_and_footer: !!options[:remove_header_and_footer],
|
323
|
+
aaq: !!options[:aaq],
|
324
|
+
forkable: !!options[:forkable],
|
325
|
+
branch: options[:branch],
|
326
|
+
contains_html: options[:contains_html],
|
327
|
+
git_links: !!options[:git_links])
|
259
328
|
abort
|
260
329
|
end
|
261
330
|
|
@@ -265,7 +334,10 @@ if options[:build_course]
|
|
265
334
|
fis_links: !!options[:fis],
|
266
335
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
267
336
|
aaq: !!options[:aaq],
|
268
|
-
|
337
|
+
prework: !!options[:prework],
|
338
|
+
forkable: !!options[:forkable],
|
339
|
+
contains_html: options[:contains_html],
|
340
|
+
git_links: !!options[:git_links])
|
269
341
|
abort
|
270
342
|
end
|
271
343
|
|
@@ -278,7 +350,9 @@ if options[:add_to_course]
|
|
278
350
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
279
351
|
forkable: !!options[:forkable],
|
280
352
|
aaq: !!options[:aaq],
|
281
|
-
|
353
|
+
prework: !!options[:prework],
|
354
|
+
contains_html: options[:contains_html],
|
355
|
+
git_links: !!options[:git_links])
|
282
356
|
else
|
283
357
|
puts '--course required'
|
284
358
|
end
|
@@ -292,7 +366,9 @@ if options[:update_course_lessons]
|
|
292
366
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
293
367
|
forkable: !!options[:forkable],
|
294
368
|
aaq: !!options[:aaq],
|
295
|
-
|
369
|
+
prework: !!options[:prework],
|
370
|
+
contains_html: options[:contains_html],
|
371
|
+
git_links: !!options[:git_links])
|
296
372
|
abort
|
297
373
|
end
|
298
374
|
|
@@ -352,10 +428,12 @@ if options[:create_lesson]
|
|
352
428
|
type: options[:type],
|
353
429
|
save_to_github: !!options[:save_to_github],
|
354
430
|
fis_links: !!options[:fis],
|
431
|
+
git_links: !!options[:git_links],
|
355
432
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
356
433
|
only_update_content: !!options[:only_content],
|
357
434
|
forkable: !!options[:forkable],
|
358
435
|
aaq: !!options[:aaq],
|
436
|
+
prework: !!options[:prework],
|
359
437
|
contains_html: options[:contains_html])
|
360
438
|
end
|
361
439
|
|
@@ -369,10 +447,12 @@ if options[:align]
|
|
369
447
|
name: options[:name],
|
370
448
|
type: options[:type],
|
371
449
|
save_to_github: !!options[:save_to_github],
|
372
|
-
fis_links: !!options[:fis],
|
450
|
+
fis_links: !!options[:fis],
|
451
|
+
git_links: !!options[:git_links],
|
373
452
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
374
453
|
only_update_content: !!options[:only_content],
|
375
454
|
forkable: !!options[:forkable],
|
376
455
|
aaq: !!options[:aaq],
|
456
|
+
prework: !!options[:prework],
|
377
457
|
contains_html: options[:contains_html])
|
378
458
|
end
|
data/lib/github-to-canvas.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'csv'
|
2
2
|
require_relative './github-to-canvas/create_canvas_lesson'
|
3
3
|
require_relative './github-to-canvas/update_canvas_lesson'
|
4
4
|
require_relative './github-to-canvas/canvas_dotfile'
|
@@ -21,11 +21,13 @@ class GithubToCanvas
|
|
21
21
|
when 'query'
|
22
22
|
CanvasInterface.get_course_info(options[:course_id], options[:id])
|
23
23
|
when 'map'
|
24
|
-
CanvasInterface.map_course_info(options
|
24
|
+
CanvasInterface.map_course_info(options)
|
25
25
|
when 'csv'
|
26
26
|
CanvasInterface.csv(options[:file_to_convert])
|
27
27
|
when 'canvas_read'
|
28
28
|
puts CanvasInterface.read_lesson(options[:filepath])
|
29
|
+
when 'canvas_copy'
|
30
|
+
CanvasInterface.copy_lesson(options)
|
29
31
|
when 'github_read'
|
30
32
|
html = RepositoryConverter.remote_file_conversion(options)
|
31
33
|
puts RepositoryConverter.adjust_converted_html(options, html)
|
@@ -43,16 +45,24 @@ class GithubToCanvas
|
|
43
45
|
CanvasInterface.update_all_related_lessons(options, name, html)
|
44
46
|
|
45
47
|
when 'github_create'
|
48
|
+
if (!options[:branch])
|
49
|
+
options[:branch] = 'master'
|
50
|
+
end
|
46
51
|
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
52
|
|
53
|
+
html = RepositoryConverter.adjust_converted_html(options, html)
|
54
|
+
name = options[:name] ? options[:name] : RepositoryInterface.get_name(options[:filepath], html)
|
55
|
+
puts name
|
50
56
|
response = CanvasInterface.create_lesson(options, name, html)
|
51
57
|
|
52
58
|
puts "Canvas lesson created. Lesson available at #{response['html_url']}"
|
53
59
|
when 'github_align'
|
60
|
+
if (!options[:branch])
|
61
|
+
options[:branch] = 'master'
|
62
|
+
end
|
54
63
|
html = RepositoryConverter.remote_file_conversion(options)
|
55
64
|
name = options[:name] ? options[:name] : RepositoryInterface.get_name(options[:filepath], html)
|
65
|
+
|
56
66
|
html = RepositoryConverter.adjust_converted_html(options, html)
|
57
67
|
response = CanvasInterface.update_existing_lesson(options, name, html)
|
58
68
|
puts "Canvas lesson updated. Lesson available at #{response['html_url']}"
|
@@ -152,6 +162,101 @@ class GithubToCanvas
|
|
152
162
|
end
|
153
163
|
}
|
154
164
|
}
|
165
|
+
when 'csv_build'
|
166
|
+
if !options[:course_id]
|
167
|
+
course_info = {
|
168
|
+
name: "CSV Build Test",
|
169
|
+
course_code: "CSV-TEST"
|
170
|
+
}
|
171
|
+
created_course_info = CanvasInterface.create_course(course_info)
|
172
|
+
puts "Course created - #{created_course_info["id"]}"
|
173
|
+
puts "Make sure to add yourself as a teacher to this course before continuing, then press Enter/Return"
|
174
|
+
input = gets
|
175
|
+
options[:course_id] = created_course_info["id"]
|
176
|
+
else
|
177
|
+
puts "Adding to course #{options[:course_id]}"
|
178
|
+
end
|
179
|
+
|
180
|
+
csv_data = CSV.read(options[:file_to_convert])
|
181
|
+
created_module_info = {
|
182
|
+
"id" => "",
|
183
|
+
"name" => ""
|
184
|
+
}
|
185
|
+
|
186
|
+
csv_data.each { |lesson|
|
187
|
+
# lesson[0] == repo
|
188
|
+
# lesson[1] == name
|
189
|
+
# lesson[2] == module
|
190
|
+
# lesson[3] == type
|
191
|
+
# lesson[4] == yes/no contains HTML
|
192
|
+
module_info = {
|
193
|
+
name: lesson[2]
|
194
|
+
}
|
195
|
+
if created_module_info["name"] != module_info[:name]
|
196
|
+
created_module_info = CanvasInterface.create_module(options[:course_id], module_info)
|
197
|
+
puts "New module created - #{created_module_info["id"]} - #{created_module_info["name"]}"
|
198
|
+
end
|
199
|
+
|
200
|
+
options[:filepath] = lesson[0]
|
201
|
+
options[:name] = lesson[1]
|
202
|
+
options[:type] = lesson[3]
|
203
|
+
options[:branch] = "master" if !options[:branch]
|
204
|
+
if !options[:contains_html]
|
205
|
+
options[:contains_html] = (lesson[4] == "yes" || lesson[4] == "Yes") ? true : false
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
html = RepositoryConverter.remote_file_conversion(options)
|
210
|
+
html = RepositoryConverter.adjust_converted_html(options, html)
|
211
|
+
created_lesson_info = CanvasInterface.create_lesson(options, lesson[1], html)
|
212
|
+
created_lesson_info["page_url"] = created_lesson_info["url"] if !created_lesson_info["page_url"]
|
213
|
+
created_lesson_info["id"] = created_lesson_info["page_url"] if !created_lesson_info["id"]
|
214
|
+
created_lesson_info["type"] = options[:type]
|
215
|
+
puts "Creating lesson - #{options[:name]}"
|
216
|
+
response = CanvasInterface.add_to_module(options[:course_id], created_module_info, created_lesson_info)
|
217
|
+
|
218
|
+
}
|
219
|
+
when 'csv_align'
|
220
|
+
|
221
|
+
csv_data = CSV.read(options[:file_to_convert])
|
222
|
+
created_module_info = {
|
223
|
+
"id" => "",
|
224
|
+
"name" => ""
|
225
|
+
}
|
226
|
+
|
227
|
+
csv_data.each { |lesson|
|
228
|
+
# lesson[0] == repo
|
229
|
+
# lesson[1] == name
|
230
|
+
# lesson[2] == module
|
231
|
+
# lesson[3] == type
|
232
|
+
# lesson[4] == yes/no contains HTML
|
233
|
+
# lesson[5] == lesson id
|
234
|
+
# lesson[6] == course id
|
235
|
+
|
236
|
+
module_info = {
|
237
|
+
name: lesson[2]
|
238
|
+
}
|
239
|
+
|
240
|
+
options[:filepath] = lesson[0]
|
241
|
+
options[:name] = lesson[1]
|
242
|
+
options[:type] = lesson[3]
|
243
|
+
options[:id] = lesson[5]
|
244
|
+
options[:course_id] = lesson[6]
|
245
|
+
options[:branch] = "master" if !options[:branch]
|
246
|
+
if !options[:contains_html]
|
247
|
+
options[:contains_html] = (lesson[4] == "yes" || lesson[4] == "Yes") ? true : false
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
html = RepositoryConverter.remote_file_conversion(options)
|
252
|
+
html = RepositoryConverter.adjust_converted_html(options, html)
|
253
|
+
updated_lesson_info = CanvasInterface.update_existing_lesson(options, lesson[1], html)
|
254
|
+
updated_lesson_info["page_url"] = updated_lesson_info["url"] if !updated_lesson_info["page_url"]
|
255
|
+
updated_lesson_info["id"] = updated_lesson_info["page_url"] if !updated_lesson_info["id"]
|
256
|
+
updated_lesson_info["type"] = options[:type]
|
257
|
+
puts "Updating lesson - #{options[:name]}"
|
258
|
+
|
259
|
+
}
|
155
260
|
else
|
156
261
|
puts VERSION
|
157
262
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'byebug'
|
2
1
|
require 'json'
|
3
2
|
require 'rest-client'
|
4
3
|
require 'yaml'
|
4
|
+
require 'byebug'
|
5
5
|
class CanvasInterface
|
6
6
|
|
7
7
|
def self.create_course(course_info)
|
@@ -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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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'
|
@@ -95,14 +95,15 @@ class CanvasInterface
|
|
95
95
|
if options[:type] == 'page' || options[:type] == 'Page'
|
96
96
|
response = RestClient.get(url, headers)
|
97
97
|
lesson_info = JSON.parse(response)
|
98
|
+
lesson_info = lesson_info[0] if lesson_info.kind_of?(Array)
|
98
99
|
url = url.sub(/[^\/]+$/, lesson_info["page_id"].to_s)
|
99
100
|
end
|
101
|
+
|
100
102
|
response = RestClient.put(url, payload, headers)
|
101
103
|
rescue
|
102
104
|
puts "Something went wrong while pushing lesson #{options[:id]} to course #{options[:course_id]}"
|
103
105
|
puts "Make sure you are working on lessons that are not locked"
|
104
106
|
abort
|
105
|
-
""
|
106
107
|
end
|
107
108
|
JSON.parse(response.body)
|
108
109
|
end
|
@@ -193,6 +194,7 @@ class CanvasInterface
|
|
193
194
|
while !!index
|
194
195
|
url = "#{ENV['CANVAS_API_PATH']}/courses/#{course}/modules?page=#{index}&per_page=20"
|
195
196
|
index += 1
|
197
|
+
|
196
198
|
response = RestClient.get(url, self.headers)
|
197
199
|
modules = JSON.parse(response.body)
|
198
200
|
|
@@ -200,7 +202,7 @@ class CanvasInterface
|
|
200
202
|
course_info[:modules] = course_info[:modules] + modules
|
201
203
|
else
|
202
204
|
index = nil
|
203
|
-
end
|
205
|
+
end
|
204
206
|
end
|
205
207
|
|
206
208
|
course_info[:modules] = course_info[:modules].map do |mod|
|
@@ -213,11 +215,12 @@ class CanvasInterface
|
|
213
215
|
while !!index
|
214
216
|
url = "#{ENV['CANVAS_API_PATH']}/courses/#{course}/modules/#{mod['id']}/items?page=#{index}&per_page=20"
|
215
217
|
index += 1
|
216
|
-
response = RestClient.get(url, headers
|
217
|
-
"Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
|
218
|
-
})
|
218
|
+
response = RestClient.get(url, self.headers)
|
219
219
|
lessons = JSON.parse(response.body)
|
220
220
|
lessons = lessons.map do |lesson|
|
221
|
+
if lesson["type"] == "ExternalUrl"
|
222
|
+
next
|
223
|
+
end
|
221
224
|
lesson = lesson.slice("id","title","name","indent","type","html_url","page_url","url","completion_requirement", "published")
|
222
225
|
lesson["repository"] = ""
|
223
226
|
lesson['id'] = lesson['url'].gsub(/^(.*[\\\/])/,'')
|
@@ -232,7 +235,7 @@ class CanvasInterface
|
|
232
235
|
end
|
233
236
|
new_mod
|
234
237
|
end
|
235
|
-
|
238
|
+
|
236
239
|
puts course_info.to_yaml
|
237
240
|
|
238
241
|
rescue
|
@@ -241,8 +244,8 @@ class CanvasInterface
|
|
241
244
|
end
|
242
245
|
end
|
243
246
|
|
244
|
-
def self.map_course_info(
|
245
|
-
course_info = YAML.load(File.read("#{Dir.pwd}/#{file_to_convert}"))
|
247
|
+
def self.map_course_info(options)
|
248
|
+
course_info = YAML.load(File.read("#{Dir.pwd}/#{options[:file_to_convert]}"))
|
246
249
|
course_info[:modules] = course_info[:modules].map do |mod|
|
247
250
|
mod[:lessons] = mod[:lessons].map do |lesson|
|
248
251
|
|
@@ -279,13 +282,15 @@ class CanvasInterface
|
|
279
282
|
else
|
280
283
|
lesson["repository"] = "https://github.com/learn-co-curriculum/" + repo
|
281
284
|
end
|
285
|
+
puts lesson["repository"] if options[:urls_only]
|
286
|
+
puts "#{lesson["repository"]}, #{lesson["title"]}, #{mod[:name]}, #{lesson["type"].downcase}, , #{lesson["id"]}, #{course_info[:id]}" if options[:csv]
|
282
287
|
end
|
283
288
|
sleep(1)
|
284
289
|
lesson
|
285
290
|
end
|
286
291
|
mod
|
287
292
|
end
|
288
|
-
puts course_info.to_yaml
|
293
|
+
puts course_info.to_yaml if !options[:urls_only]
|
289
294
|
end
|
290
295
|
|
291
296
|
def self.csv(file_to_convert)
|
@@ -332,12 +337,40 @@ class CanvasInterface
|
|
332
337
|
end
|
333
338
|
mod
|
334
339
|
end
|
335
|
-
byebug
|
336
340
|
puts course_info.to_yaml
|
337
341
|
end
|
338
342
|
|
339
|
-
|
343
|
+
def self.copy_lesson(options)
|
344
|
+
types = ["page", "assignment", "quiz", "discussion"]
|
345
|
+
url = options[:filepath]
|
346
|
+
type = types.find {|type| url.match(type)}
|
347
|
+
options[:type] = type
|
348
|
+
if !url.include?(ENV['CANVAS_API_PATH'])
|
349
|
+
url = url.sub(/^.*\/\/.*?\//,"#{ENV['CANVAS_API_PATH']}/")
|
350
|
+
end
|
340
351
|
|
352
|
+
response = RestClient.get(url, headers={
|
353
|
+
"Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
|
354
|
+
})
|
355
|
+
|
356
|
+
lesson_info = JSON.parse(response)
|
357
|
+
lesson_info = lesson_info.slice("title",
|
358
|
+
"name",
|
359
|
+
"description",
|
360
|
+
"body",
|
361
|
+
"message",
|
362
|
+
"shuffle_answers",
|
363
|
+
"allowed_attempts",
|
364
|
+
"question_count"
|
365
|
+
)
|
366
|
+
if options[:type] == "page"
|
367
|
+
self.update_existing_lesson(options, lesson_info["title"], lesson_info["body"])
|
368
|
+
else
|
369
|
+
self.update_existing_lesson(options, lesson_info["name"], lesson_info["description"])
|
370
|
+
end
|
371
|
+
|
372
|
+
|
373
|
+
end
|
341
374
|
|
342
375
|
def self.build_payload(options, name, html)
|
343
376
|
if options[:only_update_content]
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'redcarpet'
|
2
|
-
|
2
|
+
# require 'byebug'
|
3
3
|
class CustomRender < Redcarpet::Render::HTML
|
4
4
|
def block_code(code, lang)
|
5
5
|
"<pre>" \
|
@@ -14,7 +14,7 @@ end
|
|
14
14
|
|
15
15
|
class RepositoryConverter
|
16
16
|
def self.local_file_conversion(options)
|
17
|
-
GithubInterface.get_updated_repo(options[:filepath], options[:branch])
|
17
|
+
# GithubInterface.get_updated_repo(options[:filepath], options[:branch])
|
18
18
|
markdown = RepositoryInterface.read_local_file(options[:filepath], options[:file_to_convert])
|
19
19
|
raw_remote_url = self.set_raw_image_remote_url(options[:filepath])
|
20
20
|
markdown = self.escape_existing_html(markdown) if options[:contains_html]
|
@@ -26,15 +26,27 @@ class RepositoryConverter
|
|
26
26
|
def self.remote_file_conversion(options)
|
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
|
+
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'
|
39
|
+
end
|
30
40
|
markdown = self.fix_local_images(options, markdown, raw_remote_url)
|
31
41
|
html = self.convert_to_html(markdown)
|
32
42
|
# self.fix_local_html_links(options, html, options[:filepath])
|
33
43
|
end
|
34
44
|
|
35
45
|
def self.convert_to_html(markdown)
|
36
|
-
|
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})
|
37
48
|
html = redcarpet.render(markdown)
|
49
|
+
puts "Markdown converted to HTML"
|
38
50
|
self.remove_line_breaks(html)
|
39
51
|
end
|
40
52
|
|
@@ -44,25 +56,57 @@ class RepositoryConverter
|
|
44
56
|
html = self.remove_header_and_footer(html)
|
45
57
|
end
|
46
58
|
|
47
|
-
if options[:fis_links]
|
59
|
+
if options[:fis_links] || options[:git_links]
|
48
60
|
html = self.add_fis_links(options, html)
|
49
61
|
end
|
50
62
|
|
51
|
-
|
63
|
+
if options[:contains_html]
|
64
|
+
html = self.fix_escaped_inline_html_code(html)
|
65
|
+
end
|
52
66
|
|
53
67
|
html
|
54
68
|
end
|
55
69
|
|
56
70
|
def self.fix_escaped_inline_html_code(html)
|
57
|
-
|
58
|
-
|
71
|
+
|
72
|
+
# stops HTML/JSX code blocks from rendering as HTML in Canvas
|
73
|
+
# html = html.gsub("&gt;</code>", "></code>")
|
74
|
+
# html = html.gsub("&gt;</code>", "></code>")
|
75
|
+
|
76
|
+
# fixes < and > code snippets
|
77
|
+
|
78
|
+
# html = html.gsub(/<pre><code>(.*?)<\/code><\/pre>/) { |string|
|
79
|
+
# byebug
|
80
|
+
# }
|
81
|
+
# html = html.gsub("&gt;", ">")
|
82
|
+
|
83
|
+
# # fixes blockquotes
|
84
|
+
# html = html.gsub(/\n<p>>\;(.*)\n>\;/) { |bq|
|
85
|
+
# bq.delete_prefix!("\n<p>>")
|
86
|
+
# "\n<blockquote>" + bq
|
87
|
+
# }
|
88
|
+
# html = html.gsub(/\n>\;(.*)\n>\;/) { |bq|
|
89
|
+
# bq.delete_prefix!("\n>")
|
90
|
+
# " " + bq
|
91
|
+
# }
|
92
|
+
# html = html.gsub(/\n>\;(.*)<\/p>/) { |bq|
|
93
|
+
# bq.delete_prefix!("\n>\;")
|
94
|
+
# bq.delete_suffix!("</p>")
|
95
|
+
# " " + bq + "</blockquote>"
|
96
|
+
# }
|
97
|
+
|
98
|
+
html
|
59
99
|
end
|
60
100
|
|
61
101
|
|
62
102
|
def self.escape_existing_html(markdown)
|
63
|
-
markdown = markdown.gsub(/<\/(?!iframe)/, "</")
|
64
|
-
markdown = markdown.gsub(/<(?!iframe)/, "<")
|
65
|
-
markdown = markdown.gsub(/(?<!iframe)>/, ">")
|
103
|
+
# markdown = markdown.gsub(/<\/(?!iframe)/, "</")
|
104
|
+
# markdown = markdown.gsub(/<(?!iframe)/, "<")
|
105
|
+
# markdown = markdown.gsub(/(?<!iframe)>/, ">")
|
106
|
+
# byebug
|
107
|
+
# markdown = markdown.gsub(/```(.*?)```/) {|s|
|
108
|
+
# byebug
|
109
|
+
# }
|
66
110
|
end
|
67
111
|
|
68
112
|
def self.remove_header_and_footer(html)
|
@@ -78,6 +122,9 @@ class RepositoryConverter
|
|
78
122
|
|
79
123
|
def self.remove_footer(readme)
|
80
124
|
readme.gsub(/<p class='util--hide'(.+?)<\/p>/,"")
|
125
|
+
readme.gsub(/<p data-visibility='hidden'(.+?)<\/p>/,"")
|
126
|
+
readme.gsub(/<p><\;p data-visibility='\;hidden'(.+?)<\/p>/,"")
|
127
|
+
readme.gsub(/<p><\;p class='util--hide'\;(.+?)<\/p>/,"")
|
81
128
|
end
|
82
129
|
|
83
130
|
def self.remove_html_header(html)
|
@@ -115,7 +162,7 @@ class RepositoryConverter
|
|
115
162
|
remote = GithubInterface.git_remote(filepath)
|
116
163
|
end
|
117
164
|
raw_remote = remote.gsub("git@github.com:","https://raw.githubusercontent.com/")
|
118
|
-
raw_remote =
|
165
|
+
raw_remote = raw_remo te.gsub("https://github.com/","https://raw.githubusercontent.com/")
|
119
166
|
raw_remote = raw_remote.gsub(/\/blob\/master\/.*$/,"")
|
120
167
|
raw_remote = raw_remote.gsub(/\/blob\/main\/.*$/,"")
|
121
168
|
raw_remote = raw_remote.gsub(/.git$/,"")
|
@@ -130,7 +177,7 @@ class RepositoryConverter
|
|
130
177
|
end
|
131
178
|
|
132
179
|
def self.adjust_local_markdown_images(readme, raw_remote_url, branch)
|
133
|
-
readme.gsub
|
180
|
+
readme.gsub(/\!\[.+\]\(.+\)/) {|image_markdown|
|
134
181
|
if !image_markdown.match?('amazonaws.com') && !image_markdown.match?('https://') && !image_markdown.match?('http://') && !image_markdown.match?('youtube')
|
135
182
|
image_markdown.gsub!(/\(.+\)/) { |path|
|
136
183
|
path.delete_prefix!("(")
|
@@ -143,12 +190,18 @@ class RepositoryConverter
|
|
143
190
|
end
|
144
191
|
|
145
192
|
def self.adjust_local_html_images(readme, raw_remote_url, branch)
|
146
|
-
readme.gsub
|
147
|
-
|
148
|
-
|
149
|
-
image_source.gsub
|
150
|
-
image_source.
|
151
|
-
|
193
|
+
readme.gsub(/src=(\'|\")[\s\S]*?(\'|\")/) { |image_source|
|
194
|
+
|
195
|
+
if !image_source.match?('amazonaws.com') && !image_source.match?('https://') && !image_source.match?('http://') && !image_source.match?('youtube') && !image_source.match(/src=(\'|\")(?=<%)/)
|
196
|
+
image_source = image_source.gsub(/(\'|\")/, "")
|
197
|
+
image_source = image_source.gsub(/src=/, '')
|
198
|
+
image_source = image_source.strip
|
199
|
+
|
200
|
+
begin
|
201
|
+
'src="' + raw_remote_url + '/' + branch + '/' + image_source + '"'
|
202
|
+
rescue
|
203
|
+
puts "Error adjust HTML images - check images in Canvas"
|
204
|
+
end
|
152
205
|
else
|
153
206
|
image_source
|
154
207
|
end
|
@@ -178,12 +231,12 @@ class RepositoryConverter
|
|
178
231
|
def self.add_fis_links(options, html)
|
179
232
|
repo_info = self.get_repo_info(options[:filepath])
|
180
233
|
html = html.sub(/<div id="git-data-element.*<header class="fis-header.*<\/header>/,'') # remove existing fis header
|
181
|
-
header = self.create_github_link_header(repo_info[:repo_path], options
|
182
|
-
data_element = self.create_data_element(repo_info[:repo_org], repo_info[:repo_name], options[:aaq])
|
234
|
+
header = self.create_github_link_header(repo_info[:repo_path], options)
|
235
|
+
data_element = self.create_data_element(repo_info[:repo_org], repo_info[:repo_name], options[:aaq], options[:prework])
|
183
236
|
data_element + header + html
|
184
237
|
end
|
185
238
|
|
186
|
-
def self.create_github_link_header(repo_path,
|
239
|
+
def self.create_github_link_header(repo_path, options)
|
187
240
|
# add link to associated repository
|
188
241
|
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>"
|
189
242
|
|
@@ -191,20 +244,19 @@ class RepositoryConverter
|
|
191
244
|
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>"
|
192
245
|
|
193
246
|
# add link to fork (forking handled by separate Flatiron server, generation of link handled via custom Canvas JS theme file)
|
194
|
-
|
195
|
-
|
247
|
+
|
248
|
+
if (options[:forkable])
|
249
|
+
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>"
|
196
250
|
"<header class='fis-header' style='visibility: hidden;'>#{github_fork_link}#{github_repo_link}#{github_issue_link}</header>"
|
251
|
+
elsif options[:git_links]
|
252
|
+
"<header class='fis-header'>#{github_repo_link}#{github_issue_link}</header>"
|
197
253
|
else
|
198
254
|
"<header class='fis-header' style='visibility: hidden;'>#{github_repo_link}#{github_issue_link}</header>"
|
199
255
|
end
|
200
256
|
end
|
201
257
|
|
202
|
-
def self.create_data_element(repo_org, repo_name, aaq)
|
203
|
-
|
204
|
-
"<div id='git-data-element' data-aaq='enabled' data-org='#{repo_org}' data-repo='#{repo_name}'></div>"
|
205
|
-
else
|
206
|
-
"<div id='git-data-element' data-org='#{repo_org}' data-repo='#{repo_name}'></div>"
|
207
|
-
end
|
258
|
+
def self.create_data_element(repo_org, repo_name, aaq, prework)
|
259
|
+
"<div id='git-data-element' #{prework ? "data-prework='true'" : ""} #{aaq ? "data-aaq='enabled'" : ""} data-org='#{repo_org}' data-repo='#{repo_name}'></div>"
|
208
260
|
end
|
209
261
|
|
210
262
|
|
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.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- maxwellbenton
|
@@ -108,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
110
|
requirements: []
|
111
|
-
rubygems_version: 3.
|
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
|