github-to-canvas 0.1.2 → 0.1.8
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/README.md +34 -18
- data/bin/github-to-canvas +107 -16
- data/lib/github-to-canvas.rb +71 -7
- data/lib/github-to-canvas/canvas_interface.rb +49 -26
- data/lib/github-to-canvas/github_interface.rb +1 -1
- data/lib/github-to-canvas/repository_converter.rb +83 -19
- 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: 18f61edcbd53e1e26f59fe6767ae09b3bb227dee2f6529797a1f0fc6ace94b00
|
4
|
+
data.tar.gz: 0757bd6b39a7fd9e4bb996156db33309cd96afbe2f8274c1261e95b4aad210e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 593e15eb02ee30c7d45b3ffb479efcd69ab3b80436a23b81f6f731e3ad7a2a3a81d05601baf15cd893a86a54029a919ac45617a20cdb4a2c5ad4e441b8529c4e
|
7
|
+
data.tar.gz: 8306e5d652b5e61c3aba33e09a70e0f8aa3a1455dea60269c685983793c443f7065944cf157aa365c693cec9ae12d49a579aec66efc73e390e2643c3fa07b198
|
data/README.md
CHANGED
@@ -294,29 +294,45 @@ includes HTML that is not meant to be rendered, the content will be rendered as
|
|
294
294
|
part of the page's HTML, resulting in unusual display errors in Canvas. Examples of
|
295
295
|
this would be lessons on HTML or JavaScript that include HTML code snippets.
|
296
296
|
|
297
|
-
To
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
297
|
+
To prevent HTML from being rendered, include the `--contains-html` option when
|
298
|
+
running the GitHub to Canvas gem. This replaces `<` and `>` characters with HTML
|
299
|
+
charset values wrapped in `span` elements. This will stop Canvas from rendering
|
300
|
+
the HTML.
|
301
|
+
|
302
|
+
If your markdown contains a mix of HTML that should and should not be rendered,
|
303
|
+
you will need to either replace HTML that you want to be rendered with markdown
|
304
|
+
syntax equivalents. For example, HTML you want to display as code and an `<img>`
|
305
|
+
element you want to render as the image itself, replace the `<img>` tag with
|
306
|
+
markdown syntax (``).
|
307
|
+
|
308
|
+
The one exception is the `<iframe>` element. There is no way to easily embed
|
309
|
+
videos in GitHub markdown without HTML, so this tag will always be allowed to
|
310
|
+
render in Canvas, whether or not you use `--contains-html`.
|
311
|
+
|
312
|
+
If you have HTML related rendering issues in Canvas that can't be fixed with
|
313
|
+
`--contains-html`:
|
314
|
+
|
315
|
+
- Go to the Canvas WYSIWYG editor for the afflicted lesson.
|
316
|
+
- Click the HTML editor option (`</>` button in the lower right) to switch to
|
317
|
+
HTML.
|
318
|
+
- Read the GitHub repo as HTML:
|
319
|
+
|
320
|
+
```sh
|
321
|
+
github-to-canvas --read-from-github URL
|
322
|
+
```
|
323
|
+
|
324
|
+
- Copy the output HTML and paste it in to the Canvas editor. This should clear up
|
325
|
+
some larger page rendering issues, but may not fix all code snippets issues.
|
326
|
+
- Switch back to the regular Canvas WYSIWYG editor
|
327
|
+
- Open a second tab to the GitHub repo you're converting from.
|
328
|
+
- Copy any HTML code snippets from GitHub and paste them into the Canvas editor
|
329
|
+
where they should be displayed.
|
312
330
|
|
313
331
|
The Canvas editor will treat the pasted HTML content as code and will
|
314
332
|
automatically replace some characters, escaping the code from the
|
315
333
|
normal rendering process.
|
316
334
|
|
317
|
-
Note that realigning after fixing this content
|
318
|
-
rendering for these lessons again. A fix is planned for this issue, but has not
|
319
|
-
been implemented.
|
335
|
+
Note that realigning after fixing this content may overwrite fixes.
|
320
336
|
|
321
337
|
### Multi-Line Code Snippets Render as a Single Line
|
322
338
|
|
data/bin/github-to-canvas
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
require 'byebug'
|
2
1
|
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'byebug'
|
4
|
+
|
3
5
|
require 'optparse'
|
4
6
|
require 'github-to-canvas'
|
5
7
|
|
@@ -77,7 +79,6 @@ OptionParser.new do |opts|
|
|
77
79
|
opts.on("-tTYPE", "--type TYPE",
|
78
80
|
"Sets the type Canvas lesson to be created (page or assignment). If no type, type decided based on repository structure") do |type|
|
79
81
|
# byebug
|
80
|
-
puts type.downcase
|
81
82
|
options[:type] = type.downcase
|
82
83
|
abort if type == 'quiz' || type == 'discussion'
|
83
84
|
# if type == 'page' || type == 'assignment' || type == 'discussion' || type == 'quiz' || type == 'Page' || type == 'Assignment' || type == 'Discussion' || type == 'Quiz'
|
@@ -107,6 +108,18 @@ OptionParser.new do |opts|
|
|
107
108
|
"Adds additional Flatiron School HTML after markdown conversion") do |f|
|
108
109
|
options[:fis] = true
|
109
110
|
end
|
111
|
+
opts.on("-g", "--git-links",
|
112
|
+
"Adds additional GitHub after markdown conversion") do |f|
|
113
|
+
options[:git_links] = true
|
114
|
+
end
|
115
|
+
opts.on("--aaq",
|
116
|
+
"Adds AAQ flag to HTML header appended with --fis-links") do |aaq|
|
117
|
+
options[:aaq] = aaq
|
118
|
+
end
|
119
|
+
opts.on("--prework",
|
120
|
+
"Adds prework flag to HTML header appended with --fis-links") do |prework|
|
121
|
+
options[:prework] = prework
|
122
|
+
end
|
110
123
|
opts.on("--forkable",
|
111
124
|
"Used with --fis-links, adds fork button to HTML header injected into Canvas lesson") do |remote|
|
112
125
|
options[:forkable] = true
|
@@ -135,10 +148,14 @@ OptionParser.new do |opts|
|
|
135
148
|
"REQUIRES -f or --file Associates canvas lessons with repositories. Use query to create required YAML file") do |file|
|
136
149
|
options[:map] = file
|
137
150
|
end
|
138
|
-
opts.on("--
|
139
|
-
"
|
140
|
-
options[:
|
151
|
+
opts.on("--urls-only",
|
152
|
+
"Use with --map. Outputs repo URLs instead of YAML") do |urls|
|
153
|
+
options[:urls_only] = urls
|
141
154
|
end
|
155
|
+
# opts.on("--csv COURSE",
|
156
|
+
# "Returns a course's lesson struction as CSV") do |course|
|
157
|
+
# options[:csv] = course
|
158
|
+
# end
|
142
159
|
opts.on("--read-from-canvas CANVAS_URL",
|
143
160
|
"Retrieves an existing Canvas lesson using the provided URL") do |url|
|
144
161
|
options[:read_from_canvas] = url
|
@@ -175,6 +192,19 @@ OptionParser.new do |opts|
|
|
175
192
|
"Iterates over provided course YAML file and clones repos locally") do |file|
|
176
193
|
options[:clone_from_yaml] = file
|
177
194
|
end
|
195
|
+
opts.on("--contains-html",
|
196
|
+
"Escapes all HTML included in source markdown by replacing '<' and '>' with HTML charset values") do |html|
|
197
|
+
options[:contains_html] = html
|
198
|
+
end
|
199
|
+
opts.on("--canvas-to-canvas COURSE",
|
200
|
+
"Copies an existing Canvas lesson into another Canvas lesson") do |canvas_to_canvas|
|
201
|
+
options[:canvas_to_canvas] = canvas_to_canvas
|
202
|
+
end
|
203
|
+
opts.on("--build-from-csv CSV",
|
204
|
+
"Build a course usin a CSV of lesson repos, names, modules, and types") do |csv_build|
|
205
|
+
options[:csv_build] = csv_build
|
206
|
+
end
|
207
|
+
|
178
208
|
|
179
209
|
end.parse!
|
180
210
|
|
@@ -184,12 +214,30 @@ if options[:version]
|
|
184
214
|
end
|
185
215
|
|
186
216
|
if options[:read_from_canvas]
|
187
|
-
GithubToCanvas.new(mode: 'canvas_read',
|
217
|
+
GithubToCanvas.new(mode: 'canvas_read',
|
218
|
+
filepath: options[:read_from_canvas])
|
219
|
+
abort
|
220
|
+
end
|
221
|
+
|
222
|
+
if options[:canvas_to_canvas]
|
223
|
+
GithubToCanvas.new(mode: 'canvas_copy',
|
224
|
+
filepath: options[:canvas_to_canvas],
|
225
|
+
course_id: options[:course_id],
|
226
|
+
type: options[:type],
|
227
|
+
id: options[:id]
|
228
|
+
)
|
188
229
|
abort
|
189
230
|
end
|
190
231
|
|
191
232
|
if options[:read_from_github]
|
192
|
-
GithubToCanvas.new(mode: 'github_read',
|
233
|
+
GithubToCanvas.new(mode: 'github_read',
|
234
|
+
filepath: options[:read_from_github],
|
235
|
+
remove_header_and_footer: !!options[:remove_header_and_footer],
|
236
|
+
forkable: !!options[:forkable],
|
237
|
+
fis_links: !!options[:fis],
|
238
|
+
aaq: !!options[:aaq],
|
239
|
+
prework: !!options[:prework],
|
240
|
+
contains_html: options[:contains_html])
|
193
241
|
abort
|
194
242
|
end
|
195
243
|
|
@@ -199,9 +247,13 @@ if options[:create_from_github]
|
|
199
247
|
filepath: options[:create_from_github],
|
200
248
|
course_id: options[:course_id],
|
201
249
|
type: options[:type],
|
250
|
+
name: options[:name],
|
202
251
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
203
252
|
forkable: !!options[:forkable],
|
204
|
-
fis_links: !!options[:fis]
|
253
|
+
fis_links: !!options[:fis],
|
254
|
+
aaq: !!options[:aaq],
|
255
|
+
prework: !!options[:prework],
|
256
|
+
contains_html: options[:contains_html])
|
205
257
|
else
|
206
258
|
puts 'Canvas course ID and lesson type required. Example: github-to-canvas --create-from-github URL --course ID --type TYPE'
|
207
259
|
end
|
@@ -218,7 +270,10 @@ if options[:align_from_github]
|
|
218
270
|
name: options[:name],
|
219
271
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
220
272
|
forkable: !!options[:forkable],
|
221
|
-
fis_links: !!options[:fis]
|
273
|
+
fis_links: !!options[:fis],
|
274
|
+
aaq: !!options[:aaq],
|
275
|
+
prework: !!options[:prework],
|
276
|
+
contains_html: options[:contains_html])
|
222
277
|
else
|
223
278
|
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'
|
224
279
|
end
|
@@ -231,7 +286,9 @@ if options[:query]
|
|
231
286
|
end
|
232
287
|
|
233
288
|
if options[:map]
|
234
|
-
GithubToCanvas.new(mode: 'map',
|
289
|
+
GithubToCanvas.new(mode: 'map',
|
290
|
+
file_to_convert: options[:map],
|
291
|
+
urls_only: !!options[:urls_only])
|
235
292
|
abort
|
236
293
|
end
|
237
294
|
|
@@ -240,12 +297,30 @@ if options[:csv]
|
|
240
297
|
abort
|
241
298
|
end
|
242
299
|
|
300
|
+
if options[:csv_build]
|
301
|
+
GithubToCanvas.new(mode: 'csv_build',
|
302
|
+
file_to_convert: options[:csv_build],
|
303
|
+
course_id: options[:course_id],
|
304
|
+
fis_links: !!options[:fis],
|
305
|
+
remove_header_and_footer: !!options[:remove_header_and_footer],
|
306
|
+
aaq: !!options[:aaq],
|
307
|
+
forkable: !!options[:forkable],
|
308
|
+
branch: options[:branch],
|
309
|
+
contains_html: options[:contains_html],
|
310
|
+
git_links: !!options[:git_links])
|
311
|
+
abort
|
312
|
+
end
|
313
|
+
|
243
314
|
if options[:build_course]
|
244
315
|
GithubToCanvas.new(mode: 'build_course',
|
245
316
|
file_to_convert: options[:build_course],
|
246
317
|
fis_links: !!options[:fis],
|
247
318
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
248
|
-
|
319
|
+
aaq: !!options[:aaq],
|
320
|
+
prework: !!options[:prework],
|
321
|
+
forkable: !!options[:forkable],
|
322
|
+
contains_html: options[:contains_html],
|
323
|
+
git_links: !!options[:git_links])
|
249
324
|
abort
|
250
325
|
end
|
251
326
|
|
@@ -256,7 +331,11 @@ if options[:add_to_course]
|
|
256
331
|
file_to_convert: options[:add_to_course],
|
257
332
|
fis_links: !!options[:fis],
|
258
333
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
259
|
-
forkable: !!options[:forkable]
|
334
|
+
forkable: !!options[:forkable],
|
335
|
+
aaq: !!options[:aaq],
|
336
|
+
prework: !!options[:prework],
|
337
|
+
contains_html: options[:contains_html],
|
338
|
+
git_links: !!options[:git_links])
|
260
339
|
else
|
261
340
|
puts '--course required'
|
262
341
|
end
|
@@ -268,7 +347,11 @@ if options[:update_course_lessons]
|
|
268
347
|
file_to_convert: options[:update_course_lessons],
|
269
348
|
fis_links: !!options[:fis],
|
270
349
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
271
|
-
forkable: !!options[:forkable]
|
350
|
+
forkable: !!options[:forkable],
|
351
|
+
aaq: !!options[:aaq],
|
352
|
+
prework: !!options[:prework],
|
353
|
+
contains_html: options[:contains_html],
|
354
|
+
git_links: !!options[:git_links])
|
272
355
|
abort
|
273
356
|
end
|
274
357
|
|
@@ -328,9 +411,13 @@ if options[:create_lesson]
|
|
328
411
|
type: options[:type],
|
329
412
|
save_to_github: !!options[:save_to_github],
|
330
413
|
fis_links: !!options[:fis],
|
414
|
+
git_links: !!options[:git_links],
|
331
415
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
332
416
|
only_update_content: !!options[:only_content],
|
333
|
-
forkable: !!options[:forkable]
|
417
|
+
forkable: !!options[:forkable],
|
418
|
+
aaq: !!options[:aaq],
|
419
|
+
prework: !!options[:prework],
|
420
|
+
contains_html: options[:contains_html])
|
334
421
|
end
|
335
422
|
|
336
423
|
if options[:align]
|
@@ -343,8 +430,12 @@ if options[:align]
|
|
343
430
|
name: options[:name],
|
344
431
|
type: options[:type],
|
345
432
|
save_to_github: !!options[:save_to_github],
|
346
|
-
fis_links: !!options[:fis],
|
433
|
+
fis_links: !!options[:fis],
|
434
|
+
git_links: !!options[:git_links],
|
347
435
|
remove_header_and_footer: !!options[:remove_header_and_footer],
|
348
436
|
only_update_content: !!options[:only_content],
|
349
|
-
forkable: !!options[:forkable]
|
437
|
+
forkable: !!options[:forkable],
|
438
|
+
aaq: !!options[:aaq],
|
439
|
+
prework: !!options[:prework],
|
440
|
+
contains_html: options[:contains_html])
|
350
441
|
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,14 +21,16 @@ 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
|
-
|
31
|
-
puts RepositoryConverter.
|
32
|
+
html = RepositoryConverter.remote_file_conversion(options)
|
33
|
+
puts RepositoryConverter.adjust_converted_html(options, html)
|
32
34
|
when 'create' # used with a local repo
|
33
35
|
html = RepositoryConverter.local_file_conversion(options)
|
34
36
|
name = RepositoryInterface.get_name(options[:filepath], html)
|
@@ -38,21 +40,29 @@ class GithubToCanvas
|
|
38
40
|
puts "Canvas lesson created. Lesson available at #{response['html_url']}"
|
39
41
|
when 'align' # used with a local repo
|
40
42
|
html = RepositoryConverter.local_file_conversion(options)
|
41
|
-
name = RepositoryInterface.get_name(options[:filepath], html)
|
43
|
+
name = options[:name] ? options[:name] : RepositoryInterface.get_name(options[:filepath], html)
|
42
44
|
html = RepositoryConverter.adjust_converted_html(options, html)
|
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 = 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,60 @@ 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
|
+
}
|
155
219
|
else
|
156
220
|
puts VERSION
|
157
221
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'byebug'
|
2
1
|
require 'json'
|
3
2
|
require 'rest-client'
|
4
3
|
require 'yaml'
|
@@ -47,44 +46,37 @@ class CanvasInterface
|
|
47
46
|
JSON.parse(response.body)
|
48
47
|
end
|
49
48
|
|
50
|
-
def self.create_quiz(options, quiz_data)
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
49
|
def self.add_to_module(course_id, module_info, lesson_info)
|
55
50
|
# POST /api/v1/courses/:course_id/modules/:module_id/items
|
56
51
|
url = "#{ENV['CANVAS_API_PATH']}/courses/#{course_id}/modules/#{module_info["id"]}/items"
|
57
52
|
|
58
|
-
if lesson_info["type"] == "Page"
|
53
|
+
if lesson_info["type"] == "Page" || lesson_info["type"] == "page"
|
59
54
|
payload = {
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
55
|
+
'module_item[title]' => lesson_info["title"],
|
56
|
+
'module_item[type]' => lesson_info["type"].capitalize,
|
57
|
+
'module_item[indent]' => 0,
|
58
|
+
'module_item[page_url]' => lesson_info["id"],
|
59
|
+
'module_item[completion_requirement][type]' => 'must_view'
|
60
|
+
}
|
66
61
|
elsif lesson_info["type"] == "Quiz"
|
67
62
|
puts "Quiz needs to be added manually - #{lesson_info['title']} - lesson_info["
|
68
63
|
else
|
69
64
|
|
70
65
|
payload = {
|
71
66
|
'module_item[title]' => lesson_info["title"],
|
72
|
-
'module_item[type]' => lesson_info["type"],
|
67
|
+
'module_item[type]' => lesson_info["type"].capitalize,
|
73
68
|
'module_item[indent]' => 1,
|
74
69
|
'module_item[content_id]' => lesson_info["id"],
|
75
70
|
'module_item[completion_requirement][type]' => 'must_submit'
|
76
71
|
}
|
77
72
|
end
|
78
73
|
begin
|
79
|
-
byebug
|
80
74
|
response = RestClient.post(url, payload, self.headers)
|
81
75
|
rescue
|
82
76
|
puts "Something went wrong while adding lesson #{lesson_info["id"]} to module #{module_info["id"]} in course #{course_id}" if lesson_info["type"] == "Assignment"
|
83
77
|
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"
|
84
78
|
abort
|
85
79
|
end
|
86
|
-
|
87
|
-
|
88
80
|
response
|
89
81
|
|
90
82
|
end
|
@@ -200,6 +192,7 @@ class CanvasInterface
|
|
200
192
|
while !!index
|
201
193
|
url = "#{ENV['CANVAS_API_PATH']}/courses/#{course}/modules?page=#{index}&per_page=20"
|
202
194
|
index += 1
|
195
|
+
|
203
196
|
response = RestClient.get(url, self.headers)
|
204
197
|
modules = JSON.parse(response.body)
|
205
198
|
|
@@ -207,7 +200,7 @@ class CanvasInterface
|
|
207
200
|
course_info[:modules] = course_info[:modules] + modules
|
208
201
|
else
|
209
202
|
index = nil
|
210
|
-
end
|
203
|
+
end
|
211
204
|
end
|
212
205
|
|
213
206
|
course_info[:modules] = course_info[:modules].map do |mod|
|
@@ -220,11 +213,12 @@ class CanvasInterface
|
|
220
213
|
while !!index
|
221
214
|
url = "#{ENV['CANVAS_API_PATH']}/courses/#{course}/modules/#{mod['id']}/items?page=#{index}&per_page=20"
|
222
215
|
index += 1
|
223
|
-
response = RestClient.get(url, headers
|
224
|
-
"Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
|
225
|
-
})
|
216
|
+
response = RestClient.get(url, self.headers)
|
226
217
|
lessons = JSON.parse(response.body)
|
227
218
|
lessons = lessons.map do |lesson|
|
219
|
+
if lesson["type"] == "ExternalUrl"
|
220
|
+
next
|
221
|
+
end
|
228
222
|
lesson = lesson.slice("id","title","name","indent","type","html_url","page_url","url","completion_requirement", "published")
|
229
223
|
lesson["repository"] = ""
|
230
224
|
lesson['id'] = lesson['url'].gsub(/^(.*[\\\/])/,'')
|
@@ -239,7 +233,7 @@ class CanvasInterface
|
|
239
233
|
end
|
240
234
|
new_mod
|
241
235
|
end
|
242
|
-
|
236
|
+
|
243
237
|
puts course_info.to_yaml
|
244
238
|
|
245
239
|
rescue
|
@@ -248,8 +242,8 @@ class CanvasInterface
|
|
248
242
|
end
|
249
243
|
end
|
250
244
|
|
251
|
-
def self.map_course_info(
|
252
|
-
course_info = YAML.load(File.read("#{Dir.pwd}/#{file_to_convert}"))
|
245
|
+
def self.map_course_info(options)
|
246
|
+
course_info = YAML.load(File.read("#{Dir.pwd}/#{options[:file_to_convert]}"))
|
253
247
|
course_info[:modules] = course_info[:modules].map do |mod|
|
254
248
|
mod[:lessons] = mod[:lessons].map do |lesson|
|
255
249
|
|
@@ -285,6 +279,7 @@ class CanvasInterface
|
|
285
279
|
lesson["repository"] = repo
|
286
280
|
else
|
287
281
|
lesson["repository"] = "https://github.com/learn-co-curriculum/" + repo
|
282
|
+
puts lesson["repository"] if options[:urls_only]
|
288
283
|
end
|
289
284
|
end
|
290
285
|
sleep(1)
|
@@ -292,7 +287,7 @@ class CanvasInterface
|
|
292
287
|
end
|
293
288
|
mod
|
294
289
|
end
|
295
|
-
puts course_info.to_yaml
|
290
|
+
puts course_info.to_yaml if !options[:urls_only]
|
296
291
|
end
|
297
292
|
|
298
293
|
def self.csv(file_to_convert)
|
@@ -339,12 +334,40 @@ class CanvasInterface
|
|
339
334
|
end
|
340
335
|
mod
|
341
336
|
end
|
342
|
-
byebug
|
343
337
|
puts course_info.to_yaml
|
344
338
|
end
|
345
339
|
|
346
|
-
|
340
|
+
def self.copy_lesson(options)
|
341
|
+
types = ["page", "assignment", "quiz", "discussion"]
|
342
|
+
url = options[:filepath]
|
343
|
+
type = types.find {|type| url.match(type)}
|
344
|
+
options[:type] = type
|
345
|
+
if !url.include?(ENV['CANVAS_API_PATH'])
|
346
|
+
url = url.sub(/^.*\/\/.*?\//,"#{ENV['CANVAS_API_PATH']}/")
|
347
|
+
end
|
347
348
|
|
349
|
+
response = RestClient.get(url, headers={
|
350
|
+
"Authorization" => "Bearer #{ENV['CANVAS_API_KEY']}"
|
351
|
+
})
|
352
|
+
|
353
|
+
lesson_info = JSON.parse(response)
|
354
|
+
lesson_info = lesson_info.slice("title",
|
355
|
+
"name",
|
356
|
+
"description",
|
357
|
+
"body",
|
358
|
+
"message",
|
359
|
+
"shuffle_answers",
|
360
|
+
"allowed_attempts",
|
361
|
+
"question_count"
|
362
|
+
)
|
363
|
+
if options[:type] == "page"
|
364
|
+
self.update_existing_lesson(options, lesson_info["title"], lesson_info["body"])
|
365
|
+
else
|
366
|
+
self.update_existing_lesson(options, lesson_info["name"], lesson_info["description"])
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
end
|
348
371
|
|
349
372
|
def self.build_payload(options, name, html)
|
350
373
|
if options[:only_update_content]
|
@@ -17,7 +17,7 @@ class RepositoryConverter
|
|
17
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]
|
21
21
|
markdown = self.fix_local_images(options, markdown, raw_remote_url)
|
22
22
|
html = self.convert_to_html(markdown)
|
23
23
|
# self.fix_local_html_links(options, html, options[:filepath])
|
@@ -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
|
+
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
|
29
40
|
markdown = self.fix_local_images(options, markdown, raw_remote_url)
|
30
41
|
html = self.convert_to_html(markdown)
|
31
42
|
# self.fix_local_html_links(options, html, options[:filepath])
|
32
43
|
end
|
33
44
|
|
34
45
|
def self.convert_to_html(markdown)
|
35
|
-
|
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})
|
36
48
|
html = redcarpet.render(markdown)
|
37
|
-
self.remove_line_breaks(html)
|
49
|
+
# self.remove_line_breaks(html)
|
38
50
|
end
|
39
51
|
|
40
52
|
def self.adjust_converted_html(options, html)
|
@@ -43,12 +55,52 @@ class RepositoryConverter
|
|
43
55
|
html = self.remove_header_and_footer(html)
|
44
56
|
end
|
45
57
|
|
46
|
-
if options[:fis_links]
|
58
|
+
if options[:fis_links] || options[:git_links]
|
47
59
|
html = self.add_fis_links(options, html)
|
48
60
|
end
|
61
|
+
|
62
|
+
if options[:contains_html]
|
63
|
+
html = self.fix_escaped_inline_html_code(html)
|
64
|
+
end
|
65
|
+
|
66
|
+
html
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.fix_escaped_inline_html_code(html)
|
70
|
+
|
71
|
+
# stops HTML/JSX code blocks from rendering as HTML in Canvas
|
72
|
+
html = html.gsub("&gt;</code>", "></code>")
|
73
|
+
html = html.gsub("&gt;</code>", "></code>")
|
74
|
+
|
75
|
+
# fixes < and > code snippets
|
76
|
+
html = html.gsub("&lt;", "<")
|
77
|
+
html = html.gsub("&gt;", ">")
|
78
|
+
|
79
|
+
# # fixes blockquotes
|
80
|
+
# html = html.gsub(/\n<p>>\;(.*)\n>\;/) { |bq|
|
81
|
+
# bq.delete_prefix!("\n<p>>")
|
82
|
+
# "\n<blockquote>" + bq
|
83
|
+
# }
|
84
|
+
# html = html.gsub(/\n>\;(.*)\n>\;/) { |bq|
|
85
|
+
# bq.delete_prefix!("\n>")
|
86
|
+
# " " + bq
|
87
|
+
# }
|
88
|
+
# html = html.gsub(/\n>\;(.*)<\/p>/) { |bq|
|
89
|
+
# bq.delete_prefix!("\n>\;")
|
90
|
+
# bq.delete_suffix!("</p>")
|
91
|
+
# " " + bq + "</blockquote>"
|
92
|
+
# }
|
93
|
+
|
49
94
|
html
|
50
95
|
end
|
51
96
|
|
97
|
+
|
98
|
+
def self.escape_existing_html(markdown)
|
99
|
+
markdown = markdown.gsub(/<\/(?!iframe)/, "</")
|
100
|
+
markdown = markdown.gsub(/<(?!iframe)/, "<")
|
101
|
+
markdown = markdown.gsub(/(?<!iframe)>/, ">")
|
102
|
+
end
|
103
|
+
|
52
104
|
def self.remove_header_and_footer(html)
|
53
105
|
new_html = self.remove_html_header(html)
|
54
106
|
new_html = self.remove_footer(new_html)
|
@@ -56,12 +108,15 @@ class RepositoryConverter
|
|
56
108
|
end
|
57
109
|
|
58
110
|
def self.remove_header(readme)
|
59
|
-
readme.gsub
|
111
|
+
readme = readme.gsub(/^# .+?\n\n/,"")
|
60
112
|
readme.gsub(/^# .+?\n/,"")
|
61
113
|
end
|
62
114
|
|
63
115
|
def self.remove_footer(readme)
|
64
116
|
readme.gsub(/<p class='util--hide'(.+?)<\/p>/,"")
|
117
|
+
readme.gsub(/<p data-visibility='hidden'(.+?)<\/p>/,"")
|
118
|
+
readme.gsub(/<p><\;p data-visibility='\;hidden'(.+?)<\/p>/,"")
|
119
|
+
readme.gsub(/<p><\;p class='util--hide'\;(.+?)<\/p>/,"")
|
65
120
|
end
|
66
121
|
|
67
122
|
def self.remove_html_header(html)
|
@@ -114,7 +169,7 @@ class RepositoryConverter
|
|
114
169
|
end
|
115
170
|
|
116
171
|
def self.adjust_local_markdown_images(readme, raw_remote_url, branch)
|
117
|
-
readme.gsub
|
172
|
+
readme.gsub(/\!\[.+\]\(.+\)/) {|image_markdown|
|
118
173
|
if !image_markdown.match?('amazonaws.com') && !image_markdown.match?('https://') && !image_markdown.match?('http://') && !image_markdown.match?('youtube')
|
119
174
|
image_markdown.gsub!(/\(.+\)/) { |path|
|
120
175
|
path.delete_prefix!("(")
|
@@ -127,12 +182,18 @@ class RepositoryConverter
|
|
127
182
|
end
|
128
183
|
|
129
184
|
def self.adjust_local_html_images(readme, raw_remote_url, branch)
|
130
|
-
readme.gsub
|
131
|
-
|
132
|
-
|
133
|
-
image_source.gsub
|
134
|
-
image_source.
|
135
|
-
|
185
|
+
readme.gsub(/src=(\'|\")[\s\S]*?(\'|\")/) { |image_source|
|
186
|
+
|
187
|
+
if !image_source.match?('amazonaws.com') && !image_source.match?('https://') && !image_source.match?('http://') && !image_source.match?('youtube') && !image_source.match(/src=(\'|\")(?=<%)/)
|
188
|
+
image_source = image_source.gsub(/(\'|\")/, "")
|
189
|
+
image_source = image_source.gsub(/src=/, '')
|
190
|
+
image_source = image_source.strip
|
191
|
+
|
192
|
+
begin
|
193
|
+
'src="' + raw_remote_url + '/' + branch + '/' + image_source + '"'
|
194
|
+
rescue
|
195
|
+
puts "Error adjust HTML images - check images in Canvas"
|
196
|
+
end
|
136
197
|
else
|
137
198
|
image_source
|
138
199
|
end
|
@@ -162,12 +223,12 @@ class RepositoryConverter
|
|
162
223
|
def self.add_fis_links(options, html)
|
163
224
|
repo_info = self.get_repo_info(options[:filepath])
|
164
225
|
html = html.sub(/<div id="git-data-element.*<header class="fis-header.*<\/header>/,'') # remove existing fis header
|
165
|
-
header = self.create_github_link_header(repo_info[:repo_path], options
|
166
|
-
data_element = self.create_data_element(repo_info[:repo_org], repo_info[:repo_name])
|
226
|
+
header = self.create_github_link_header(repo_info[:repo_path], options)
|
227
|
+
data_element = self.create_data_element(repo_info[:repo_org], repo_info[:repo_name], options[:aaq], options[:prework])
|
167
228
|
data_element + header + html
|
168
229
|
end
|
169
230
|
|
170
|
-
def self.create_github_link_header(repo_path,
|
231
|
+
def self.create_github_link_header(repo_path, options)
|
171
232
|
# add link to associated repository
|
172
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>"
|
173
234
|
|
@@ -175,16 +236,19 @@ class RepositoryConverter
|
|
175
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>"
|
176
237
|
|
177
238
|
# add link to fork (forking handled by separate Flatiron server, generation of link handled via custom Canvas JS theme file)
|
178
|
-
|
179
|
-
|
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>"
|
180
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>"
|
181
245
|
else
|
182
246
|
"<header class='fis-header' style='visibility: hidden;'>#{github_repo_link}#{github_issue_link}</header>"
|
183
247
|
end
|
184
248
|
end
|
185
249
|
|
186
|
-
def self.create_data_element(repo_org, repo_name)
|
187
|
-
"<div id='git-data-element' data-org='#{repo_org}' data-repo='#{repo_name}'></div>"
|
250
|
+
def self.create_data_element(repo_org, repo_name, aaq, prework)
|
251
|
+
"<div id='git-data-element' #{prework ? "data-prework='true'" : ""} #{aaq ? "data-aaq='enabled'" : ""} data-org='#{repo_org}' data-repo='#{repo_name}'></div>"
|
188
252
|
end
|
189
253
|
|
190
254
|
|
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.8
|
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
|