senkyoshi 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +92 -0
- data/bin/console +14 -0
- data/bin/import_blackboard +6 -0
- data/lib/senkyoshi/canvas_course.rb +179 -0
- data/lib/senkyoshi/collection.rb +26 -0
- data/lib/senkyoshi/config.rb +35 -0
- data/lib/senkyoshi/exceptions.rb +13 -0
- data/lib/senkyoshi/models/announcement.rb +36 -0
- data/lib/senkyoshi/models/answer.rb +32 -0
- data/lib/senkyoshi/models/assessment.rb +95 -0
- data/lib/senkyoshi/models/assignment.rb +26 -0
- data/lib/senkyoshi/models/assignment_group.rb +23 -0
- data/lib/senkyoshi/models/blog.rb +22 -0
- data/lib/senkyoshi/models/content.rb +92 -0
- data/lib/senkyoshi/models/content_file.rb +26 -0
- data/lib/senkyoshi/models/course.rb +39 -0
- data/lib/senkyoshi/models/file.rb +99 -0
- data/lib/senkyoshi/models/forum.rb +28 -0
- data/lib/senkyoshi/models/gradebook.rb +30 -0
- data/lib/senkyoshi/models/group.rb +22 -0
- data/lib/senkyoshi/models/module.rb +22 -0
- data/lib/senkyoshi/models/module_item.rb +23 -0
- data/lib/senkyoshi/models/question.rb +188 -0
- data/lib/senkyoshi/models/questions/calculated.rb +72 -0
- data/lib/senkyoshi/models/questions/either_or.rb +31 -0
- data/lib/senkyoshi/models/questions/essay.rb +11 -0
- data/lib/senkyoshi/models/questions/file_upload.rb +4 -0
- data/lib/senkyoshi/models/questions/fill_in_blank.rb +15 -0
- data/lib/senkyoshi/models/questions/fill_in_blank_plus.rb +20 -0
- data/lib/senkyoshi/models/questions/hot_spot.rb +11 -0
- data/lib/senkyoshi/models/questions/jumbled_sentence.rb +37 -0
- data/lib/senkyoshi/models/questions/matching.rb +57 -0
- data/lib/senkyoshi/models/questions/multiple_answer.rb +56 -0
- data/lib/senkyoshi/models/questions/multiple_choice.rb +18 -0
- data/lib/senkyoshi/models/questions/numerical.rb +31 -0
- data/lib/senkyoshi/models/questions/opinion_scale.rb +18 -0
- data/lib/senkyoshi/models/questions/ordering.rb +40 -0
- data/lib/senkyoshi/models/questions/quiz_bowl.rb +11 -0
- data/lib/senkyoshi/models/questions/short_response.rb +4 -0
- data/lib/senkyoshi/models/questions/true_false.rb +15 -0
- data/lib/senkyoshi/models/quiz.rb +7 -0
- data/lib/senkyoshi/models/resource.rb +33 -0
- data/lib/senkyoshi/models/scorm_package.rb +109 -0
- data/lib/senkyoshi/models/staff_info.rb +72 -0
- data/lib/senkyoshi/models/wikipage.rb +34 -0
- data/lib/senkyoshi/tasks.rb +90 -0
- data/lib/senkyoshi/version.rb +3 -0
- data/lib/senkyoshi/xml_parser.rb +154 -0
- data/lib/senkyoshi.rb +69 -0
- metadata +250 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cb37815e8613f1dc566a20f201f9613fd0caa850
|
4
|
+
data.tar.gz: e7c7eb79f471a87f0e2f3f103074294649128659
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 437ab1a18a0f0fa3038317efaf884341ad25b03f0fcf3c9b3d0bbd44cefec3e407ee3f7a6c302ea1eb8e1455330f33ca09e0d2d17d0c6c042ece072715eaedb3
|
7
|
+
data.tar.gz: 2fe6f2ab0dba999722a2b93d4d2f7667a1833d00c2b0a62e6b6600fb1439e882d2981bbfbf3a31e3a64619f0711b8f4d45f89743b5c76f5539918e4498f74dc6
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 AtomicJolt
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Senkyoshi Converter [![Build Status](https://travis-ci.org/atomicjolt/senkyoshi.svg?branch=master)](https://travis-ci.org/atomicjolt/senkyoshi)
|
2
|
+
|
3
|
+
TODO: Describe the gem
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem "senkyoshi"
|
11
|
+
gem "canvas_cc", git: "https://github.com/atomicjolt/canvas_cc.git"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```sh
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```sh
|
21
|
+
$ gem install senkyoshi
|
22
|
+
```
|
23
|
+
|
24
|
+
Create a `Rakefile` and add
|
25
|
+
```ruby
|
26
|
+
require "senkyoshi/tasks"
|
27
|
+
Senkyoshi::Tasks.install_tasks
|
28
|
+
```
|
29
|
+
|
30
|
+
Create a `senkyoshi.yml` and add credentials
|
31
|
+
```yaml
|
32
|
+
# Generally looks like https://< mycanvas_instance >/api
|
33
|
+
:canvas_url: <canvas instance api url>
|
34
|
+
|
35
|
+
# Canvas tokens can be generated at <my_canvas_url>/profile/setting provided
|
36
|
+
# that the user has the required priviledges
|
37
|
+
:canvas_token: <canvas token>
|
38
|
+
|
39
|
+
# Url of scorm manager. This could the the adhesion app
|
40
|
+
# [https://github.com/atomicjolt/adhesion]
|
41
|
+
:scorm_url: <scorm manager url>
|
42
|
+
|
43
|
+
# This should be the endpoint to launch a given scorm course, in the case of
|
44
|
+
# adhesion this will look like https://<adhesion url>/scorm_course
|
45
|
+
:scorm_launch_url: <scorm launch url>
|
46
|
+
|
47
|
+
# This is the secret to authenticate requests to the scorm manager. In the case
|
48
|
+
# of adhesion you can generate a shared secret by logging into the server and
|
49
|
+
# running rake shared_auth, which will generate and save a token
|
50
|
+
:scorm_shared_auth: <scorm manager token>
|
51
|
+
|
52
|
+
# The account or sub-account id. This can be :self, :default, or an id
|
53
|
+
:account_id: <id>
|
54
|
+
```
|
55
|
+
|
56
|
+
## Usage
|
57
|
+
|
58
|
+
Run the rake task to convert from .zip to .imscc
|
59
|
+
```sh
|
60
|
+
rake imscc
|
61
|
+
```
|
62
|
+
This will take all your files in your source folder and convert them to your outputs folder
|
63
|
+
|
64
|
+
Run converting files in parallel
|
65
|
+
```sh
|
66
|
+
time rake imscc -m
|
67
|
+
```
|
68
|
+
|
69
|
+
Delete entire outputs folder
|
70
|
+
```sh
|
71
|
+
rake clean
|
72
|
+
```
|
73
|
+
|
74
|
+
## Development
|
75
|
+
|
76
|
+
After checking out the repo, run `bundle install` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
77
|
+
|
78
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
79
|
+
|
80
|
+
## Contributing
|
81
|
+
|
82
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/senkyoshi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
83
|
+
|
84
|
+
|
85
|
+
## License
|
86
|
+
|
87
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
88
|
+
|
89
|
+
|
90
|
+
### Things not quite implemented
|
91
|
+
People Group Sets
|
92
|
+
Blogs
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "senkyoshi"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
12
|
+
|
13
|
+
# require "irb"
|
14
|
+
# IRB.start
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require "pandarus"
|
2
|
+
require "senkyoshi/config"
|
3
|
+
require "senkyoshi/models/scorm_package"
|
4
|
+
require "rest-client"
|
5
|
+
|
6
|
+
module Senkyoshi
|
7
|
+
##
|
8
|
+
# This class represents a canvas course for which we are uploading data to
|
9
|
+
##
|
10
|
+
class CanvasCourse
|
11
|
+
##
|
12
|
+
# A new canvas course accepts the metadata for a course
|
13
|
+
# and the pandarus course resourse
|
14
|
+
##
|
15
|
+
def initialize(metadata, course_resource, blackboard_export)
|
16
|
+
@metadata = metadata
|
17
|
+
@course_resource = course_resource
|
18
|
+
@scorm_packages = ScormPackage.get_scorm_packages(blackboard_export)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Given a filename to a zip file, extract the necessary metadata
|
23
|
+
# for the course
|
24
|
+
##
|
25
|
+
def self.metadata_from_file(filename)
|
26
|
+
Zip::File.open(filename) do |file|
|
27
|
+
settings = "course_settings/course_settings.xml"
|
28
|
+
config = file.find_entry(settings).get_input_stream.read
|
29
|
+
doc = Nokogiri::XML(config)
|
30
|
+
{
|
31
|
+
name: doc.at("title").text,
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Create a new pandarus instance to communicate with the canvas server
|
38
|
+
##
|
39
|
+
def self.client
|
40
|
+
@client ||= Pandarus::Client.new(
|
41
|
+
prefix: Senkyoshi.canvas_url,
|
42
|
+
token: Senkyoshi.canvas_token,
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Find or Create a new CanvasCourse instance from the given metadata
|
48
|
+
##
|
49
|
+
def self.from_metadata(metadata, blackboard_export = nil)
|
50
|
+
course_name = metadata[:name] || metadata[:title]
|
51
|
+
courses = client.list_active_courses_in_account(Senkyoshi.account_id)
|
52
|
+
canvas_course = courses.detect { |course| course.name == course_name } ||
|
53
|
+
client.create_new_course(
|
54
|
+
Senkyoshi.account_id,
|
55
|
+
course: {
|
56
|
+
name: course_name,
|
57
|
+
},
|
58
|
+
)
|
59
|
+
CanvasCourse.new(metadata, canvas_course, blackboard_export)
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Creates a canvas assignment from a scorm package that has already been
|
64
|
+
# uploaded to a scorm manager
|
65
|
+
##
|
66
|
+
def create_scorm_assignment(scorm_package, course_id)
|
67
|
+
url = Senkyoshi.scorm_launch_url +
|
68
|
+
"?course_id=#{scorm_package['package_id']}"
|
69
|
+
|
70
|
+
payload = {
|
71
|
+
assignment__submission_types__: ["external_tool"],
|
72
|
+
assignment__integration_id__: scorm_package["package_id"],
|
73
|
+
assignment__integration_data__: {
|
74
|
+
provider: "atomic-scorm",
|
75
|
+
},
|
76
|
+
assignment__external_tool_tag_attributes__: {
|
77
|
+
url: url,
|
78
|
+
},
|
79
|
+
}
|
80
|
+
|
81
|
+
CanvasCourse.client.create_assignment(
|
82
|
+
course_id,
|
83
|
+
scorm_package["title"],
|
84
|
+
payload,
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Uploads a scorm package to scorm manager specified in senkyoshi.yml
|
90
|
+
# config file
|
91
|
+
##
|
92
|
+
def upload_scorm_package(scorm_package, course_id, tmp_name)
|
93
|
+
zip = scorm_package.write_zip tmp_name
|
94
|
+
File.open(zip, "rb") do |file|
|
95
|
+
RestClient.post(
|
96
|
+
"#{Senkyoshi.scorm_url}/api/scorm_courses",
|
97
|
+
{
|
98
|
+
oauth_consumer_key: "scorm-player",
|
99
|
+
lms_course_id: course_id,
|
100
|
+
file: file,
|
101
|
+
},
|
102
|
+
SharedAuthorization: Senkyoshi.scorm_shared_auth,
|
103
|
+
) do |resp|
|
104
|
+
JSON.parse(resp.body)["response"]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Creates assignments from all previously uploaded scorm packages
|
111
|
+
##
|
112
|
+
def create_scorm_assignments(scorm_packages, course_id)
|
113
|
+
scorm_packages.each { |pack| create_scorm_assignment(pack, course_id) }
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Uploads all scorm packages to scorm manager specified in senkyoshi.yml
|
118
|
+
# config file
|
119
|
+
##
|
120
|
+
def upload_scorm_packages(scorm_packages)
|
121
|
+
package_index = 0
|
122
|
+
scorm_packages.map do |pack|
|
123
|
+
package_index += 1
|
124
|
+
tmp_name = "#{@metadata[:name]}_#{package_index}.zip"
|
125
|
+
upload_scorm_package(pack, @course_resource.id, tmp_name)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Create a migration for the course
|
131
|
+
# and upload the imscc file to be imported into the course
|
132
|
+
##
|
133
|
+
def upload_content(filename)
|
134
|
+
client = CanvasCourse.client
|
135
|
+
name = File.basename(filename)
|
136
|
+
# Create a migration for the course and get S3 upload authorization
|
137
|
+
migration = client.
|
138
|
+
create_content_migration_courses(
|
139
|
+
@course_resource.id,
|
140
|
+
:canvas_cartridge_importer,
|
141
|
+
pre_attachment: { name: name },
|
142
|
+
)
|
143
|
+
|
144
|
+
puts "Uploading: #{name}"
|
145
|
+
upload_to_s3(migration, filename)
|
146
|
+
puts "Done uploading: #{name}"
|
147
|
+
|
148
|
+
puts "Creating Scorm: #{name}"
|
149
|
+
create_scorm_assignments(
|
150
|
+
upload_scorm_packages(@scorm_packages),
|
151
|
+
@course_resource.id,
|
152
|
+
)
|
153
|
+
puts "Done creating scorm: #{name}"
|
154
|
+
end
|
155
|
+
|
156
|
+
def upload_to_s3(migration, filename)
|
157
|
+
File.open(filename, "rb") do |file|
|
158
|
+
# Attach the file to the S3 auth
|
159
|
+
pre_attachment = migration.pre_attachment
|
160
|
+
upload_url = pre_attachment["upload_url"]
|
161
|
+
upload_params = pre_attachment["upload_params"]
|
162
|
+
upload_params[:file] = file
|
163
|
+
|
164
|
+
# Post to S3
|
165
|
+
RestClient.post(
|
166
|
+
upload_url,
|
167
|
+
upload_params,
|
168
|
+
) do |response|
|
169
|
+
# Post to Canvas
|
170
|
+
RestClient.post(
|
171
|
+
response.headers[:location],
|
172
|
+
nil,
|
173
|
+
Authorization: "Bearer #{Senkyoshi.canvas_token}",
|
174
|
+
)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Senkyoshi
|
2
|
+
class Collection
|
3
|
+
attr_reader :resources
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@resources = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(resources)
|
10
|
+
@resources.concat(resources)
|
11
|
+
end
|
12
|
+
|
13
|
+
def detect_xid(xid)
|
14
|
+
@resources.detect do |resource|
|
15
|
+
resource.matches_xid? xid
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def each
|
20
|
+
@resources.each do |resource|
|
21
|
+
yield resource
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module Senkyoshi
|
4
|
+
def self.canvas_url
|
5
|
+
Senkyoshi._config[:canvas_url]
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.canvas_token
|
9
|
+
Senkyoshi._config[:canvas_token]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.scorm_launch_url
|
13
|
+
Senkyoshi._config[:scorm_launch_url]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.scorm_url
|
17
|
+
Senkyoshi._config[:scorm_url]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.scorm_shared_auth
|
21
|
+
Senkyoshi._config[:scorm_shared_auth]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.account_id
|
25
|
+
Senkyoshi._config[:account_id] || :self
|
26
|
+
end
|
27
|
+
|
28
|
+
def self._config
|
29
|
+
@config ||= if File.exists? "senkyoshi.yml"
|
30
|
+
YAML::load(File.read("senkyoshi.yml"))
|
31
|
+
else
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "senkyoshi/models/resource"
|
2
|
+
|
3
|
+
module Senkyoshi
|
4
|
+
class Announcement < Resource
|
5
|
+
def initialize
|
6
|
+
@title = ""
|
7
|
+
@text = ""
|
8
|
+
@delayed_post = ""
|
9
|
+
@posted_at = ""
|
10
|
+
@identifier = Senkyoshi.create_random_hex
|
11
|
+
@dependency = Senkyoshi.create_random_hex
|
12
|
+
@type = "announcement"
|
13
|
+
end
|
14
|
+
|
15
|
+
def iterate_xml(data, _)
|
16
|
+
dates = data.children.at("DATES")
|
17
|
+
@title = Senkyoshi.get_attribute_value(data, "TITLE")
|
18
|
+
@text = Senkyoshi.get_text(data, "TEXT")
|
19
|
+
@delayed_post = Senkyoshi.get_attribute_value(dates, "RESTRICTSTART")
|
20
|
+
@posted_at = Senkyoshi.get_attribute_value(dates, "CREATED")
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def canvas_conversion(course, _resources = nil)
|
25
|
+
announcement = CanvasCc::CanvasCC::Models::Announcement.new
|
26
|
+
announcement.title = @title
|
27
|
+
announcement.text = @text
|
28
|
+
announcement.delayed_post = @delayed_post
|
29
|
+
announcement.posted_at = @posted_at
|
30
|
+
announcement.identifier = @identifier
|
31
|
+
announcement.dependency = @dependency
|
32
|
+
course.announcements << announcement
|
33
|
+
course
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "senkyoshi/models/resource"
|
2
|
+
|
3
|
+
module Senkyoshi
|
4
|
+
class Answer < Resource
|
5
|
+
attr_reader :id, :answer_text
|
6
|
+
attr_accessor :fraction, :resp_ident, :feedback
|
7
|
+
|
8
|
+
def initialize(text, id = Senkyoshi.create_random_hex)
|
9
|
+
@answer_text = text
|
10
|
+
@resp_ident = ""
|
11
|
+
@fraction = ""
|
12
|
+
@feedback = ""
|
13
|
+
@points = 0
|
14
|
+
@id = id
|
15
|
+
end
|
16
|
+
|
17
|
+
def iterate_xml
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def canvas_conversion(question, resources)
|
22
|
+
answer = CanvasCc::CanvasCC::Models::Answer.new(@answer_text)
|
23
|
+
answer.answer_text = fix_html(@answer_text, resources)
|
24
|
+
answer.id = @id
|
25
|
+
answer.fraction = @fraction
|
26
|
+
answer.feedback = @feedback
|
27
|
+
answer.resp_ident = @resp_ident
|
28
|
+
question.answers << answer
|
29
|
+
question
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "senkyoshi/models/assignment_group"
|
2
|
+
require "senkyoshi/models/assignment"
|
3
|
+
require "senkyoshi/models/question"
|
4
|
+
require "senkyoshi/models/resource"
|
5
|
+
|
6
|
+
module Senkyoshi
|
7
|
+
class Assessment < Resource
|
8
|
+
def initialize
|
9
|
+
@title = ""
|
10
|
+
@description = ""
|
11
|
+
@quiz_type = "assignment"
|
12
|
+
@points_possible = 0
|
13
|
+
@items = []
|
14
|
+
@group_name = ""
|
15
|
+
@workflow_state = "published"
|
16
|
+
@available = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def iterate_xml(data, pre_data)
|
20
|
+
pre_data ||= {}
|
21
|
+
@id = pre_data[:assignment_id] || Senkyoshi.create_random_hex
|
22
|
+
@title = data.at("assessment").attributes["title"].value
|
23
|
+
@points_possible = data.at("qmd_absolutescore_max").text
|
24
|
+
@description = data.at("presentation_material").
|
25
|
+
at("mat_formattedtext").text
|
26
|
+
@group_name = data.at("bbmd_assessmenttype").text
|
27
|
+
data.at("section").children.map do |item|
|
28
|
+
@items.push(item) if item.name == "item"
|
29
|
+
end
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def canvas_conversion(course, resources)
|
34
|
+
if @items.count > 0
|
35
|
+
assessment = CanvasCc::CanvasCC::Models::Assessment.new
|
36
|
+
assessment.identifier = @id
|
37
|
+
course = create_assignment_group(course, resources)
|
38
|
+
assignment = create_assignment
|
39
|
+
assignment.quiz_identifier_ref = assessment.identifier
|
40
|
+
course.assignments << assignment
|
41
|
+
assessment = setup_assessment(assessment, assignment, resources)
|
42
|
+
course.assessments << assessment
|
43
|
+
end
|
44
|
+
course
|
45
|
+
end
|
46
|
+
|
47
|
+
def setup_assessment(assessment, assignment, resources)
|
48
|
+
assessment.title = @title
|
49
|
+
assessment.description = fix_html(@description, resources)
|
50
|
+
assessment.available = @available
|
51
|
+
assessment.quiz_type = @quiz_type
|
52
|
+
assessment.points_possible = @points_possible
|
53
|
+
assessment = create_items(assessment, resources)
|
54
|
+
assessment.assignment = assignment
|
55
|
+
assessment
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_items(assessment, resources)
|
59
|
+
@items = @items - ["", nil]
|
60
|
+
questions = @items.map do |item|
|
61
|
+
Question.from(item)
|
62
|
+
end
|
63
|
+
assessment.items = []
|
64
|
+
questions.each do |item|
|
65
|
+
assessment = item.canvas_conversion(assessment, resources)
|
66
|
+
end
|
67
|
+
assessment
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_assignment_group(course, resources)
|
71
|
+
group = course.assignment_groups.detect { |a| a.title == @group_name }
|
72
|
+
if group
|
73
|
+
@group_id = group.identifier
|
74
|
+
else
|
75
|
+
@group_id = Senkyoshi.create_random_hex
|
76
|
+
assignment_group = AssignmentGroup.new(@group_name, @group_id)
|
77
|
+
course = assignment_group.canvas_conversion(course, resources)
|
78
|
+
end
|
79
|
+
course
|
80
|
+
end
|
81
|
+
|
82
|
+
def create_assignment
|
83
|
+
assignment = CanvasCc::CanvasCC::Models::Assignment.new
|
84
|
+
assignment.identifier = Senkyoshi.create_random_hex
|
85
|
+
assignment.assignment_group_identifier_ref = @group_id
|
86
|
+
assignment.title = @title
|
87
|
+
assignment.position = 1
|
88
|
+
assignment.submission_types << "online_quiz"
|
89
|
+
assignment.grading_type = "points"
|
90
|
+
assignment.workflow_state = @workflow_state
|
91
|
+
assignment.points_possible = @points_possible
|
92
|
+
assignment
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "senkyoshi/models/resource"
|
2
|
+
|
3
|
+
module Senkyoshi
|
4
|
+
class Assignment < Content
|
5
|
+
def canvas_conversion(course, resources)
|
6
|
+
unless @title == "--TOP--"
|
7
|
+
assignment = CanvasCc::CanvasCC::Models::Assignment.new
|
8
|
+
assignment.identifier = @id
|
9
|
+
assignment.title = @title
|
10
|
+
assignment.body = fix_html(@body, resources)
|
11
|
+
assignment.points_possible = @points
|
12
|
+
assignment.assignment_group_identifier_ref = @group_id
|
13
|
+
assignment.position = 1
|
14
|
+
assignment.workflow_state = "published"
|
15
|
+
assignment.submission_types << "online_text_entry"
|
16
|
+
assignment.submission_types << "online_upload"
|
17
|
+
assignment.grading_type = "points"
|
18
|
+
|
19
|
+
@files.each { |f| assignment.body << f.canvas_conversion }
|
20
|
+
course = create_module(course)
|
21
|
+
course.assignments << assignment
|
22
|
+
end
|
23
|
+
course
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "senkyoshi/models/resource"
|
2
|
+
|
3
|
+
module Senkyoshi
|
4
|
+
class AssignmentGroup < Resource
|
5
|
+
attr_reader :id
|
6
|
+
def initialize(name, group_id)
|
7
|
+
@title = name
|
8
|
+
@group_weight = ""
|
9
|
+
@rules = {}
|
10
|
+
@id = group_id
|
11
|
+
end
|
12
|
+
|
13
|
+
def canvas_conversion(course, _resources = nil)
|
14
|
+
assignment_group = CanvasCc::CanvasCC::Models::AssignmentGroup.new
|
15
|
+
assignment_group.identifier = @id
|
16
|
+
assignment_group.title = @title
|
17
|
+
assignment_group.group_weight = @group_weight
|
18
|
+
assignment_group.rules = @rules
|
19
|
+
course.assignment_groups << assignment_group
|
20
|
+
course
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "senkyoshi/models/resource"
|
2
|
+
|
3
|
+
module Senkyoshi
|
4
|
+
class Blog < Resource
|
5
|
+
def initialize
|
6
|
+
@title = ""
|
7
|
+
@description = ""
|
8
|
+
@is_public = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def iterate_xml(data, _)
|
12
|
+
@name = Senkyoshi.get_attribute_value(data, "TITLE")
|
13
|
+
@description = data.at("TEXT").text
|
14
|
+
@is_public = Senkyoshi.get_attribute_value(data, "ISAVAILABLE")
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def canvas_conversion(course, _resources = nil)
|
19
|
+
course
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|