ruql-canvas 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3418ecd8bce903e51bfeab3af00cc5d5ac0cbcc1c1043d35e730cdc9cf2df924
4
- data.tar.gz: 2445969de592cba48c164fae63ebcdf3cbfd0670840fe518274f31a3b305e48d
3
+ metadata.gz: fdc05b1cc995933e8a0b76fa2b29c0f351ce002605e25c21ae1f1f411d1841bd
4
+ data.tar.gz: bf751328a381352dc45a221f87ffaffe086c65087f2c65b826c68415781648a7
5
5
  SHA512:
6
- metadata.gz: cf0f232a4ce1981fc8636b3f8840a66efe8a8bf152085f6129780177344f655d44f36159308ca91f9b25406de96e284efb6a034ad5c8f11010e05a1ca49db4ef
7
- data.tar.gz: c01c3ff0a897fd33530577231d80eba5a64a7d9aa8b7cdf599a06886cd33b2836bd421b1b71427bc26828ed357bee9efd59be05961dacc8ceea0dcfd4a6a9343
6
+ metadata.gz: 1a68292bf05596303e9cd7ab6d377e06ae92999fb119ff095882115b84c53f69de9deeb6db1f7f9f454f97a8f8c22cec1e1ed7e9da93a0506b6bd5ef824b425d
7
+ data.tar.gz: 16da6cf1a5e248652b26e35fca2ea008c33c2c94b7d48302f5e89386d82eaf7f03f94cd9287bf9bd4320fe7ac0454df67255ed92d40fac07c19a4a7b6af2746c
@@ -24,9 +24,11 @@ module Ruql
24
24
  yaml = YAML.load_file(yaml_options)
25
25
  logger.warn "Doing dry run without making any changes" if
26
26
  (@dry_run = yaml['dry_run'] || options['--canvas-dry-run'])
27
- set_canvas_options(yaml['canvas'])
27
+ @canvas_options = yaml['canvas']
28
+ set_canvas_options(@canvas_options)
28
29
 
29
30
  @quiz_options = YAML.load_file(@default_quiz_options_file)['quiz'].merge(yaml['quiz'] || {})
31
+ @quiz_id = @quiz_options['quiz_id'] # may be nil if new quiz is to be created.
30
32
  logger.info "Using quiz options:\n#{@quiz_options.inspect}"
31
33
 
32
34
  verify_valid_quiz!
@@ -48,16 +50,20 @@ module Ruql
48
50
  help = <<eos
49
51
  The Canvas renderer adds the given file as a quiz in Canvas, with these options:
50
52
  --canvas-dry-run - don't actually change anything, but do all non-state-changing API calls.
51
- You can also set dry_run: true in the YAML file instead.
53
+ You can also set dry_run: true in the YAML file instead. The presence of either
54
+ mechanism will turn this into a dry run.
52
55
  --canvas-config=file.yml - A Yaml file that must contain at least the following:
53
56
  dry_run: true # don't actually change anything, but check API connection and parsability
54
57
  canvas:
55
58
  api_base: https://bcourses.berkeley.edu/api/v1 # base URL for Canvas LMS API
56
59
  auth_token: 012345 # Bearer auth token for Canvas API
57
60
  course_id: 99999 # Course ID in Canvas to which a NEW quiz should be added
58
- # If a quiz_id is given and exists within that course, that quiz's contents
59
- # will be completely replaced, otherwise a new quiz will be created:
60
- quiz_id: 99999
61
+ # If quiz_id given, replace that quiz's questions and time limit; if not, create new
62
+ quiz_id: 99999
63
+ # How quiz time limit is set, eg 20-point quiz = 40 minutes. Default is 1
64
+ minutes_per_point: 2
65
+ # Fixed extra time in addition to minutes/point. Default 5. Total time rounded up to multiple of 5.
66
+ extra_minutes: 5
61
67
  quiz:
62
68
  # various options that control quiz; defaults are in #{@default_quiz_options_file}
63
69
  eos
@@ -86,10 +92,32 @@ eos
86
92
  create_quiz!
87
93
  @output = "New quiz #{@quiz_id}"
88
94
  end
89
- quiz.ungrouped_questions.each do |q|
90
- canvas_question = render_multiple_choice(q)
91
- add_question_to_current_group(canvas_question)
95
+ emit_ungrouped_questions
96
+ emit_grouped_questions
97
+ @output << " now has #{@qcount} questions in #{@group_count} pool(s)"
98
+ end
99
+ #####
100
+
101
+
102
+ private
103
+
104
+ # all "ungrouped" questions go into a single big group that can be shuffled.
105
+ # Caveat 1: where groups are typically "pick 1 of the following N", this big group has to be "pick N of the
106
+ # following N" so that all questions are presented, just in a shuffled order.
107
+ # Caveat 2: all questions in a group must be worth same # points, so we actually have to subdivide
108
+ # ungrouped questions into subgroups by point value.
109
+ def emit_ungrouped_questions
110
+ ungrouped_question_sets = quiz.ungrouped_questions.group_by(&:points)
111
+ ungrouped_question_sets.each_pair do |points,questions|
112
+ start_new_group(:name => "Group:unpooled:#{points}", :pick_count => questions.length, :question_points => points)
113
+ questions.each do |q|
114
+ canvas_question = render_multiple_choice(q)
115
+ add_question_to_current_group(canvas_question)
116
+ end
92
117
  end
118
+ end
119
+
120
+ def emit_grouped_questions
93
121
  current_group = nil
94
122
  quiz.grouped_questions.each do |q|
95
123
  if q.question_group != current_group
@@ -99,12 +127,8 @@ eos
99
127
  canvas_question = render_multiple_choice(q)
100
128
  add_question_to_current_group(canvas_question)
101
129
  end
102
- @output << " now has #{@qcount} questions in #{@group_count} pool(s)"
103
130
  end
104
- #####
105
-
106
- private
107
-
131
+
108
132
  def set_canvas_options(canvas)
109
133
  @course_id = canvas['course_id'] || raise(Ruql::OptionsError.new("course_id missing from config file"))
110
134
  @quiz_id = canvas['quiz_id'] # may be nil => create new quiz
@@ -137,8 +161,12 @@ eos
137
161
  def time_limit_for_quiz
138
162
  # intent is 1 point per minute, add 5 minutes for slop, round total up to nearest 5 minutes
139
163
  # but # questions is really # unique groups.
140
- limit = 5 * (quiz.points.to_i / 5 + 1)
141
- logger.info "Time limit #{limit} based on #{quiz.points} grouped points"
164
+ minutes_per_point = (@canvas_options['minutes_per_point'] || 1).to_i
165
+ slop = (@canvas_options['extra_minutes'] || 5).to_i
166
+ limit = quiz.points.to_i * minutes_per_point + slop
167
+ # round up to 5 minutes
168
+ limit += 5 - (limit % 5)
169
+ logger.info "Time limit #{limit} based on #{quiz.points} points"
142
170
  limit
143
171
  end
144
172
 
@@ -157,14 +185,19 @@ eos
157
185
  group_ids.each do |gid|
158
186
  canvas("Delete group #{gid}", :delete, path + "/groups/#{gid}")
159
187
  end
188
+ # modify time limit to reflect the questions we're about to replace them with
189
+ # and update quiz title
190
+ update_quiz = {'quiz' => {
191
+ 'title' => quiz.title,
192
+ 'time_limit' => time_limit_for_quiz
193
+ }}.to_json
194
+ canvas("Update quiz title and time limit", :put, path, data: update_quiz)
160
195
  end
161
196
 
162
197
  def create_quiz!
163
198
  quiz_opts = @quiz_options.merge({
164
199
  'title' => quiz.title,
165
200
  'time_limit' => time_limit_for_quiz,
166
- 'due_at' => "2020-08-01T23:00Z",
167
- 'unlock_at' => "2020-05-21T00:00Z"
168
201
  })
169
202
  quiz_object = {:quiz => quiz_opts}.to_json
170
203
  path = "courses/#{@course_id}/quizzes"
@@ -1,5 +1,5 @@
1
1
  module Ruql
2
2
  class Canvas
3
- VERSION = "1.0.0"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  end
@@ -1,10 +1,16 @@
1
+ # See canvas.instructure.com/doc/api/quizzes.html for valid values
1
2
  quiz:
2
3
  title: "Will be overridden by argument of 'quiz' in RuQL file"
3
4
  description: "Short description seen when quiz is started"
4
5
  quiz_type: assignment
5
6
  show_correct_answers: false
6
7
  shuffle_answers: true
7
- time_limit: 60
8
- due_at: "2020-08-01T23:00Z"
9
- unlock_at: "2020-05-21T00:00Z"
8
+ due_at: "2030-01-01T00:00Z"
9
+ unlock_at: "2030-01-01T00:00Z"
10
+ lock_at: "2030-01-01T00:00Z"
10
11
  published: false
12
+ # when can student see correct answer and results? (see Canvas docs)
13
+ hide_results: always
14
+ one_question_at_a_time: false
15
+ # to put it into an assignment group:
16
+ # assignment_group_id: 9999
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruql-canvas
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Armando Fox
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-03 00:00:00.000000000 Z
11
+ date: 2020-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday