quiz_api_client 4.8.0 → 4.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 057d0dea94cbf0a0781d3c8144906a8ea7b29790f278f4d4a55891aaf6c3a12b
4
- data.tar.gz: c5241135784c367e250fe0fb0a1e6012fc391c2a9d09c1225173f1acfbb3a595
3
+ metadata.gz: 450aa47af30bde7b962ac76248bde2fa992b4168875f1e8847c48539813576e5
4
+ data.tar.gz: 73da155fb2da7763ec9a07f557250842e62bd38ddfe570418df8a7eeee7608aa
5
5
  SHA512:
6
- metadata.gz: 89212f479d1081e38ad2005e5f7b84a4c3c5088b1620c6673cc2538fa719ed73f9eba1df31c5bca786c0efa4c3755d9e5bcd37e2508e7aaec73ee8ad41b1bdc4
7
- data.tar.gz: b2be42851612a9fae066ff5dcfdd322e6d66d821ddd03fa53083e8713e90c8d4ad780de177c4f13752919897ffc0e720e8b8aa2db98f27e159c73e3f64e9cd2f
6
+ metadata.gz: bd2bf29f5d1a2b3d512e8cb75b40479789138551d7fce2438e3a215158b423f174bb19bb5f854f48373f6ea685815ca73dfa0431cbde2e0839c8ae191aeff1f0
7
+ data.tar.gz: 3a95461f774db17ccb8ed636d6a552c3ea4c50291d648989d44d2f621434c196ef21468de4c8e81d0f3ccf215e6dff132dcd8cfd5c404bceba484316319062a7
@@ -31,7 +31,7 @@ module QuizApiClient
31
31
  def get(path, all: false, query: {})
32
32
  return make_request :get, url_for(path), query: query unless all
33
33
 
34
- make_paginated_request :get, url_for(path), query: query
34
+ make_paginated_request :get, url_for(path), query: sanitized_query(query, all)
35
35
  end
36
36
 
37
37
  def post(path, body = {})
@@ -52,6 +52,14 @@ module QuizApiClient
52
52
 
53
53
  private
54
54
 
55
+ def sanitized_query(query, all)
56
+ query.delete(:page) if query.key?(:page) && query[:page].nil? || all
57
+
58
+ query.delete(:per_page) if query.key?(:per_page) && query[:per_page].nil?
59
+
60
+ query
61
+ end
62
+
55
63
  def initialize_logger(log_level)
56
64
  HTTParty::Logger.add_formatter('quiz_api_client_json_formatter', QuizApiClient::JSONFormatter)
57
65
  @logger = ::Logger.new(
@@ -130,7 +138,8 @@ module QuizApiClient
130
138
  end
131
139
 
132
140
  def next_page_link(response, options)
133
- return if response.headers['link'].blank?
141
+ return if response.headers['link'].nil?
142
+ return if response.headers['link'].empty?
134
143
 
135
144
  links = LinkHeader.parse(response.headers['link']).links
136
145
  next_link = links.find { |link| link['rel'] == 'next' }
@@ -140,7 +149,9 @@ module QuizApiClient
140
149
  def next_page_dynamo(response, url, options)
141
150
  hash_key = response.headers['x-last-evaluated-hash-key']
142
151
  range_key = response.headers['x-last-evaluated-range-key']
143
- return unless hash_key.present? && range_key.present?
152
+
153
+ return if hash_key.nil? || hash_key.empty?
154
+ return if range_key.nil? || range_key.empty?
144
155
 
145
156
  query = (options[:query] || {}).merge(
146
157
  last_evaluated_hash_key: hash_key,
@@ -0,0 +1,17 @@
1
+ module QuizApiClient::Services
2
+ class AnalysesService < BaseApiService
3
+ def create(params:, token: nil)
4
+ post_to_quiz_api(params: params, token: token)
5
+ end
6
+
7
+ private
8
+
9
+ def post_to_quiz_api(params:, token:)
10
+ client(token: token).post(
11
+ "/api/quizzes/#{params[:quiz_id]}/analyses",
12
+ quiz_session_ids: params[:quiz_session_ids],
13
+ filter: params[:filter]
14
+ )
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module QuizApiClient::Services
2
+ class BankEntriesService < BaseApiService
3
+ def list(params:, token: nil, all: false)
4
+ raise 'Bank Id Required' unless params && params[:id]
5
+
6
+ pagination_params = { page: params.delete(:page), per_page: params.delete(:per_page) }.compact
7
+ get_from_quiz_api(params: params, token: token, pagination_params: pagination_params, all: all)
8
+ end
9
+
10
+ private
11
+
12
+ def get_from_quiz_api(params:, token:, pagination_params:, all:)
13
+ client(token: token).get(
14
+ "/api/internal_services/banks/#{params[:id]}/bank_entries",
15
+ query: pagination_params,
16
+ all: all
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module QuizApiClient::Services
2
+ class BankService < BaseApiService
3
+ def show(params:, token: nil)
4
+ get_from_quiz_api(params: params, token: token)
5
+ end
6
+
7
+ private
8
+
9
+ def get_from_quiz_api(params:, token:)
10
+ client(token: token).get(
11
+ "/api/internal_services/banks/#{params[:id]}"
12
+ )
13
+ end
14
+ end
15
+ end
@@ -4,6 +4,12 @@ module QuizApiClient::Services
4
4
  post_to_quiz_api(params: params, token: token)
5
5
  end
6
6
 
7
+ def show(params:, token: nil)
8
+ raise 'Content Export Id Required' unless params && params[:id]
9
+
10
+ get_from_quiz_api(params: params, token: token)
11
+ end
12
+
7
13
  private
8
14
 
9
15
  def post_to_quiz_api(params:, token:)
@@ -12,5 +18,11 @@ module QuizApiClient::Services
12
18
  content_export: params
13
19
  )
14
20
  end
21
+
22
+ def get_from_quiz_api(params:, token:)
23
+ client(token: token).get(
24
+ "/api/content_exports/#{params[:id]}"
25
+ )
26
+ end
15
27
  end
16
28
  end
@@ -26,6 +26,13 @@ module QuizApiClient::Services
26
26
  )
27
27
  end
28
28
 
29
+ def associate_courses(params:, token: nil)
30
+ client(token: token).patch(
31
+ "/api/courses/#{params[:canvas_id]}/associate_courses",
32
+ course_canvas_ids: params[:course_canvas_ids]
33
+ )
34
+ end
35
+
29
36
  private
30
37
 
31
38
  def post_to_quiz_api(params:, token:)
@@ -19,6 +19,12 @@ module QuizApiClient::Services
19
19
  put_to_quiz_api(params: params, token: token)
20
20
  end
21
21
 
22
+ def media_upload_url(params:, token: nil)
23
+ raise 'Quiz Id Required' unless params && params[:quiz_id]
24
+
25
+ get_media_upload_url_from_quiz_api(params: params, token: token)
26
+ end
27
+
22
28
  private
23
29
 
24
30
  def list_from_quiz_api(params:, token:)
@@ -44,5 +50,10 @@ module QuizApiClient::Services
44
50
  item: params
45
51
  )
46
52
  end
53
+
54
+ def get_media_upload_url_from_quiz_api(params:, token:)
55
+ quiz_id = params.delete(:quiz_id)
56
+ client(token: token).get("/api/quizzes/#{quiz_id}/items/media_upload_url")
57
+ end
47
58
  end
48
59
  end
@@ -4,6 +4,10 @@ module QuizApiClient::Services
4
4
  post_to_quiz_api(body: body, params: params, token: token)
5
5
  end
6
6
 
7
+ def update(body: {}, params:, token: nil)
8
+ put_to_quiz_api(body: body, params: params, token: token)
9
+ end
10
+
7
11
  def create_batch(body:, token: nil)
8
12
  batch_post_to_quiz_api(body: body, token: token)
9
13
  end
@@ -17,6 +21,13 @@ module QuizApiClient::Services
17
21
  )
18
22
  end
19
23
 
24
+ def put_to_quiz_api(body:, params:, token:)
25
+ client(token: token).put(
26
+ "/api/quiz_clone_jobs/#{params.fetch(:id)}",
27
+ body
28
+ )
29
+ end
30
+
20
31
  def batch_post_to_quiz_api(body:, token:)
21
32
  client(token: token).post(
22
33
  '/api/quiz_clone_jobs/create_batch',
@@ -15,7 +15,7 @@ module QuizApiClient::Services
15
15
 
16
16
  def update(params:, token: nil)
17
17
  raise 'Quiz Id Required' unless params && params[:quiz_id]
18
- raise 'Entry Id Required' unless params[:entry_id]
18
+ raise 'Entry Id Required' unless params[:id]
19
19
 
20
20
  put_to_quiz_api(params: params, token: token)
21
21
  end
@@ -23,7 +23,8 @@ module QuizApiClient::Services
23
23
  def list(params:, token: nil, all: false)
24
24
  raise 'Quiz Id Required' unless params && params[:id]
25
25
 
26
- get_from_quiz_api(params: params, token: token, all: all)
26
+ pagination_params = { page: params.delete(:page), per_page: params.delete(:per_page) }.compact
27
+ get_from_quiz_api(params: params, token: token, pagination_params: pagination_params, all: all)
27
28
  end
28
29
 
29
30
  def destroy(params:, token: nil)
@@ -50,14 +51,15 @@ module QuizApiClient::Services
50
51
 
51
52
  def put_to_quiz_api(params:, token:)
52
53
  client(token: token).put(
53
- "/api/quizzes/#{params[:quiz_id]}/quiz_entries/#{params[:entry_id]}",
54
+ "/api/quizzes/#{params[:quiz_id]}/quiz_entries/#{params[:id]}",
54
55
  quiz_entry: params
55
56
  )
56
57
  end
57
58
 
58
- def get_from_quiz_api(params:, token:, all:)
59
+ def get_from_quiz_api(params:, token:, pagination_params:, all:)
59
60
  client(token: token).get(
60
61
  "/api/quizzes/#{params[:id]}/quiz_entries",
62
+ query: pagination_params,
61
63
  all: all
62
64
  )
63
65
  end
@@ -7,7 +7,10 @@ module QuizApiClient::Services
7
7
  def show(params:, token: nil)
8
8
  raise 'Quiz Session Id Required' unless params && params[:id]
9
9
 
10
- get_from_quiz_api(params: params, token: token)
10
+ access_code_params = {
11
+ disable_ac_invalidation: params.delete(:disable_ac_invalidation)
12
+ }.compact
13
+ get_from_quiz_api(params: params, token: token, access_code_params: access_code_params)
11
14
  end
12
15
 
13
16
  private
@@ -19,9 +22,10 @@ module QuizApiClient::Services
19
22
  )
20
23
  end
21
24
 
22
- def get_from_quiz_api(params:, token:)
25
+ def get_from_quiz_api(params:, token:, access_code_params:)
23
26
  client(token: token).get(
24
- "/api/quiz_sessions/#{params[:id]}"
27
+ "/api/quiz_sessions/#{params[:id]}",
28
+ query: access_code_params
25
29
  )
26
30
  end
27
31
  end
@@ -1,3 +1,3 @@
1
1
  module QuizApiClient
2
- VERSION = '4.8.0'.freeze
2
+ VERSION = '4.14.0'.freeze
3
3
  end
@@ -18,6 +18,14 @@ module QuizApiClient
18
18
  yield(config) if block_given?
19
19
  end
20
20
 
21
+ def bank_service
22
+ @_bank_service ||= Services::BankService.new(config)
23
+ end
24
+
25
+ def bank_entries_service
26
+ @_bank_entries_service ||= Services::BankEntriesService.new(config)
27
+ end
28
+
21
29
  def config
22
30
  @_config ||= QuizApiClient::Config.new
23
31
  end
@@ -70,6 +78,10 @@ module QuizApiClient
70
78
  @_qti_imports_service ||= Services::QtiImportsService.new(config)
71
79
  end
72
80
 
81
+ def analyses_service
82
+ @_analyses_service ||= Services::AnalysesService.new(config)
83
+ end
84
+
73
85
  def item_analyses_service
74
86
  @_item_analyses_service ||= Services::ItemAnalysesService.new(config)
75
87
  end
@@ -122,9 +134,12 @@ require 'quiz_api_client/http_request/metrics'
122
134
  require 'quiz_api_client/services/jwt_service'
123
135
  require 'quiz_api_client/services/base_api_service'
124
136
 
137
+ require 'quiz_api_client/services/bank_service'
138
+ require 'quiz_api_client/services/bank_entries_service'
125
139
  require 'quiz_api_client/services/content_exports_service'
126
140
  require 'quiz_api_client/services/courses_service'
127
141
  require 'quiz_api_client/services/interaction_types_service'
142
+ require 'quiz_api_client/services/analyses_service'
128
143
  require 'quiz_api_client/services/item_analyses_service'
129
144
  require 'quiz_api_client/services/items_service'
130
145
  require 'quiz_api_client/services/qti_imports_service'
@@ -81,7 +81,17 @@ describe QuizApiClient::HttpClient do
81
81
  path = '/api/quizzes'
82
82
  stub_quiz_api path, headers: { link: link_header(path, 1, 2) }
83
83
  stub_quiz_api path, item: 2, query: { page: 2 }, headers: { link: link_header(path, 2, 2) }
84
- expect(client.get('/api/quizzes', all: true)).to eq [1, 2]
84
+ expect(client.get('/api/quizzes', query: { page: 2 }, all: true)).to eq [1, 2]
85
+ end
86
+
87
+ it 'sanitizies the query param if page is nil' do
88
+ stub_quiz_api '/api/quizzes'
89
+ expect(client.get('/api/quizzes', query: { page: nil }, all: true)).to eq [1]
90
+ end
91
+
92
+ it 'sanitizies the query param if per_page is nil' do
93
+ stub_quiz_api '/api/quizzes'
94
+ expect(client.get('/api/quizzes', query: { per_page: nil }, all: true)).to eq [1]
85
95
  end
86
96
  end
87
97
 
@@ -102,6 +112,20 @@ describe QuizApiClient::HttpClient do
102
112
  stub_quiz_api path, item: 2, query: { my_id: 12, **dynamo_params }
103
113
  expect(client.get('/api/quizzes', query: { my_id: 12 }, all: true)).to eq [1, 2]
104
114
  end
115
+
116
+ it 'retrieves subsequent pages when all is true and sanitizes query if page is nil' do
117
+ path = '/api/quizzes'
118
+ stub_quiz_api path, query: { my_id: 12 }, headers: dynamo_headers
119
+ stub_quiz_api path, item: 2, query: { my_id: 12, **dynamo_params }
120
+ expect(client.get('/api/quizzes', query: { my_id: 12, page: nil }, all: true)).to eq [1, 2]
121
+ end
122
+
123
+ it 'retrieves subsequent pages when all is true and sanitizes query if per_page is nil' do
124
+ path = '/api/quizzes'
125
+ stub_quiz_api path, query: { my_id: 12 }, headers: dynamo_headers
126
+ stub_quiz_api path, item: 2, query: { my_id: 12, **dynamo_params }
127
+ expect(client.get('/api/quizzes', query: { my_id: 12, per_page: nil }, all: true)).to eq [1, 2]
128
+ end
105
129
  end
106
130
  end
107
131
  end
@@ -93,6 +93,13 @@ describe QuizApiClient do
93
93
  end
94
94
  end
95
95
 
96
+ describe '#analyses_service' do
97
+ it 'should create the service' do
98
+ expect(QuizApiClient::Services::AnalysesService).to receive(:new).with(subject.config)
99
+ subject.analyses_service
100
+ end
101
+ end
102
+
96
103
  describe '#item_analyses_service' do
97
104
  it 'should create the service' do
98
105
  expect(QuizApiClient::Services::ItemAnalysesService).to receive(:new).with(subject.config)
@@ -121,6 +128,34 @@ describe QuizApiClient do
121
128
  end
122
129
  end
123
130
 
131
+ describe '#quiz_service' do
132
+ it 'should create the service' do
133
+ expect(QuizApiClient::Services::QuizService).to receive(:new).with(subject.config)
134
+ subject.quiz_service
135
+ end
136
+ end
137
+
138
+ describe '#quiz_entries_service' do
139
+ it 'should create the service' do
140
+ expect(QuizApiClient::Services::QuizEntriesService).to receive(:new).with(subject.config)
141
+ subject.quiz_entries_service
142
+ end
143
+ end
144
+
145
+ describe '#bank_service' do
146
+ it 'should create the service' do
147
+ expect(QuizApiClient::Services::BankService).to receive(:new).with(subject.config)
148
+ subject.bank_service
149
+ end
150
+ end
151
+
152
+ describe '#bank_entries_service' do
153
+ it 'should create the service' do
154
+ expect(QuizApiClient::Services::BankEntriesService).to receive(:new).with(subject.config)
155
+ subject.bank_entries_service
156
+ end
157
+ end
158
+
124
159
  describe '#interaction_types_service' do
125
160
  it 'should create the service' do
126
161
  expect(QuizApiClient::Services::InteractionTypesService).to receive(:new).with(subject.config)
@@ -0,0 +1,28 @@
1
+ describe QuizApiClient::Services::AnalysesService do
2
+ let(:host) { 'api.host' }
3
+ let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
4
+ let(:subject) { described_class.new(config) }
5
+
6
+ describe '#create' do
7
+ let(:params) do
8
+ { quiz_id: 1, quiz_session_ids: [1, 5, 10], filter: :last_attempt }
9
+ end
10
+ let(:stubbed_response) { { 'job_id' => 1 } }
11
+ let(:expected_url) { "https://#{host}/api/quizzes/#{params[:quiz_id]}/analyses" }
12
+ let(:status_code) { 200 }
13
+
14
+ before do
15
+ stub_request(:post, expected_url)
16
+ .to_return(
17
+ status: status_code,
18
+ body: stubbed_response.to_json,
19
+ headers: { 'Content-Type' => 'application/json' }
20
+ )
21
+ end
22
+
23
+ it 'posts to quiz_api/api/quizzes/{id}/analyses and returns the response' do
24
+ result = subject.create(params: params, token: 'token')
25
+ expect(result.parsed_response).to eql(stubbed_response)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,55 @@
1
+ describe QuizApiClient::Services::BankEntriesService do
2
+ let(:host) { 'api.host' }
3
+ let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
4
+ let(:subject) { described_class.new(config) }
5
+
6
+ def link_header(host, path, page, last_page)
7
+ link_header = "<https://#{host}#{path}?page=#{last_page}>; rel=\"last\""
8
+ link_header += ", <https://#{host}#{path}?page=#{page + 1}>; rel=\"next\"" if page < last_page
9
+ link_header += ", <https://#{host}#{path}?page=#{page - 1}>; rel=\"prev\"" if page > 1
10
+ link_header += ", <https://#{host}#{path}?page=1>; rel=\"first\"" if page > 1
11
+ { link: link_header }
12
+ end
13
+
14
+ def stub_quiz_api(url, body, query: {}, headers: {}, status: 200)
15
+ stub_request(:get, url)
16
+ .with(query: query)
17
+ .to_return(
18
+ body: body.to_json,
19
+ status: status,
20
+ headers: headers.merge(
21
+ 'Content-Type' => 'application/json'
22
+ )
23
+ )
24
+ end
25
+
26
+ describe '#list' do
27
+ let(:params) { { id: 1 } }
28
+ let(:path) { "/api/internal_services/banks/#{params[:id]}/bank_entries" }
29
+ let(:expected_url) { "https://#{host}#{path}" }
30
+
31
+ def page(page_num)
32
+ [{ 'id' => page_num, 'entry' => { 'id' => page_num } }]
33
+ end
34
+
35
+ it 'single page' do
36
+ stub_quiz_api(expected_url, page(1), headers: link_header(host, path, 1, 1))
37
+ result = subject.list(params: params, token: 'token', all: true)
38
+ expect(result).to eql([{ 'id' => 1, 'entry' => { 'id' => 1 } }])
39
+ end
40
+
41
+ it 'paginated response' do
42
+ expected_result = [
43
+ { 'id' => 1, 'entry' => { 'id' => 1 } },
44
+ { 'id' => 2, 'entry' => { 'id' => 2 } },
45
+ { 'id' => 3, 'entry' => { 'id' => 3 } }
46
+ ]
47
+
48
+ stub_quiz_api(expected_url, page(1), headers: link_header(host, path, 1, 3))
49
+ stub_quiz_api(expected_url, page(2), query: { page: 2 }, headers: link_header(host, path, 2, 3))
50
+ stub_quiz_api(expected_url, page(3), query: { page: 3 }, headers: link_header(host, path, 3, 3))
51
+ result = subject.list(params: params, token: 'token', all: true)
52
+ expect(result).to eql(expected_result)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,26 @@
1
+ describe QuizApiClient::Services::BankService do
2
+ let(:host) { 'api.host' }
3
+ let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
4
+ let(:subject) { described_class.new(config) }
5
+
6
+ describe '#show' do
7
+ let(:params) { { id: 1 } }
8
+ let(:stubbed_response) { { 'id' => 1, 'title' => 'some title' } }
9
+ let(:expected_url) { "https://#{host}/api/internal_services/banks/#{params[:id]}" }
10
+ let(:status_code) { 200 }
11
+
12
+ before do
13
+ stub_request(:get, expected_url)
14
+ .to_return(
15
+ status: status_code,
16
+ body: stubbed_response.to_json,
17
+ headers: { 'Content-Type' => 'application/json' }
18
+ )
19
+ end
20
+
21
+ it 'gets from quiz_api/api/banks and returns the response' do
22
+ result = subject.show(params: params, token: 'token')
23
+ expect(result.parsed_response).to eql(stubbed_response)
24
+ end
25
+ end
26
+ end
@@ -3,6 +3,20 @@ describe QuizApiClient::Services::ContentExportsService do
3
3
  let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
4
4
  let(:subject) { described_class.new(config) }
5
5
 
6
+ let(:stubbed_response) do
7
+ {
8
+ 'id' => '1',
9
+ 'canvas_content_export_id' => '1234',
10
+ 'export_settings' => {
11
+ 'quizzes' => [10, 11],
12
+ 'everything' => false,
13
+ 'content_export_type' => 'qti'
14
+ },
15
+ 'created_at' => '2023-02-17T01:00:00.000Z',
16
+ 'updated_at' => '2023-02-17T01:00:00.000Z'
17
+ }
18
+ end
19
+
6
20
  describe '#create' do
7
21
  let(:params) do
8
22
  {
@@ -15,20 +29,6 @@ describe QuizApiClient::Services::ContentExportsService do
15
29
  }
16
30
  end
17
31
 
18
- let(:response) do
19
- {
20
- 'id' => '1',
21
- 'canvas_content_export_id' => '1234',
22
- 'export_settings' => {
23
- 'quizzes' => [10, 11],
24
- 'everything' => false,
25
- 'content_export_type' => 'qti'
26
- },
27
- 'created_at' => '2023-02-17T01:00:00.000Z',
28
- 'updated_at' => '2023-02-17T01:00:00.000Z'
29
- }
30
- end
31
-
32
32
  let(:expected_url) { "https://#{host}/api/content_exports" }
33
33
 
34
34
  before do
@@ -36,7 +36,7 @@ describe QuizApiClient::Services::ContentExportsService do
36
36
  .with(body: { content_export: params }.to_json)
37
37
  .to_return(
38
38
  status: 201,
39
- body: response.to_json,
39
+ body: stubbed_response.to_json,
40
40
  headers: { 'Content-Type' => 'application/json' }
41
41
  )
42
42
  end
@@ -44,7 +44,27 @@ describe QuizApiClient::Services::ContentExportsService do
44
44
  it 'posts to the correct endpoint and returns the response' do
45
45
  expect(
46
46
  subject.create(params: params, token: 'token').parsed_response
47
- ).to eq(response)
47
+ ).to eq(stubbed_response)
48
+ end
49
+ end
50
+
51
+ describe '#show' do
52
+ let(:params) { { id: 1 } }
53
+ let(:expected_url) { "https://#{host}/api/content_exports/#{params[:id]}" }
54
+ let(:status_code) { 200 }
55
+
56
+ before do
57
+ stub_request(:get, expected_url)
58
+ .to_return(
59
+ status: status_code,
60
+ body: stubbed_response.to_json,
61
+ headers: { 'Content-Type' => 'application/json' }
62
+ )
63
+ end
64
+
65
+ it 'gets from quiz_api/api/content_exports and returns the response' do
66
+ response = subject.show(params: params, token: 'token')
67
+ expect(response.parsed_response).to eql(stubbed_response)
48
68
  end
49
69
  end
50
70
  end
@@ -174,4 +174,39 @@ describe QuizApiClient::Services::CoursesService do
174
174
  ).to eq(response)
175
175
  end
176
176
  end
177
+
178
+ describe '#associate_courses' do
179
+ let(:params) { { canvas_id: 1, course_canvas_ids: [2, 3, 4] } }
180
+ let(:response) do
181
+ {
182
+ 'course' => {
183
+ 'id' => '4',
184
+ 'title' => 'foo',
185
+ 'canvas_id' => '2',
186
+ 'is_blueprint' => true,
187
+ 'created_at' => '2022-06-22T18:59:27.577Z',
188
+ 'updated_at' => '2022-06-22T18:59:27.577Z'
189
+ },
190
+ 'courses_synced' => params[:course_canvas_ids]
191
+ }
192
+ end
193
+
194
+ let(:expected_url) { "https://#{host}/api/courses/1/associate_courses" }
195
+
196
+ before do
197
+ stub_request(:patch, expected_url)
198
+ .with(body: { course_canvas_ids: params[:course_canvas_ids] }.to_json)
199
+ .to_return(
200
+ status: 200,
201
+ body: response.to_json,
202
+ headers: { 'Content-Type' => 'application/json' }
203
+ )
204
+ end
205
+
206
+ it 'patches to the correct endpoint and returns the response' do
207
+ expect(
208
+ subject.associate_courses(params: params, token: 'token').parsed_response
209
+ ).to eq(response)
210
+ end
211
+ end
177
212
  end
@@ -79,4 +79,25 @@ describe QuizApiClient::Services::ItemsService do
79
79
  expect { subject.update(params: { quiz_id: 1 }, token: 'token') }.to raise_error('Item Id Required')
80
80
  end
81
81
  end
82
+
83
+ describe '#media_upload_url' do
84
+ let(:params) { { quiz_id: 1 } }
85
+ let(:stubbed_response) { { 'url' => 'awsuploadurl' } }
86
+ let(:expected_url) { "https://#{host}/api/quizzes/#{params[:quiz_id]}/items/media_upload_url" }
87
+ let(:status_code) { 200 }
88
+
89
+ before do
90
+ stub_request(:get, expected_url)
91
+ .to_return(
92
+ status: status_code,
93
+ body: stubbed_response.to_json,
94
+ headers: { 'Content-Type' => 'application/json' }
95
+ )
96
+ end
97
+
98
+ it 'gets from quiz_api/api/quizzes/{id}/items/media_upload_url and returns the response' do
99
+ result = subject.media_upload_url(params: params, token: 'token')
100
+ expect(result.parsed_response).to eql(stubbed_response)
101
+ end
102
+ end
82
103
  end
@@ -40,6 +40,43 @@ describe QuizApiClient::Services::QuizCloneJobsService do
40
40
  end
41
41
  end
42
42
 
43
+ describe '#update' do
44
+ let(:body) { { resource_map_url: 'http://foo.bar/123' } }
45
+ let(:params) { { id: 1 } }
46
+ let(:expected_url) { "https://#{host}/api/quiz_clone_jobs/#{params.fetch(:id)}" }
47
+ let(:stubbed_response) { { 'id' => '1' } }
48
+
49
+ context 'on success' do
50
+ before do
51
+ stub_request(:put, expected_url)
52
+ .to_return(
53
+ status: 200,
54
+ body: stubbed_response.to_json,
55
+ headers: { 'Content-Type' => 'application/json' }
56
+ )
57
+ end
58
+
59
+ it 'puts to /api/quiz_clone_jobs/:id' do
60
+ result = subject.update(body: body, params: params, token: 'token')
61
+ expect(result.parsed_response).to eql(stubbed_response)
62
+ end
63
+ end
64
+
65
+ context 'on failure' do
66
+ let(:status_code) { 401 }
67
+
68
+ before do
69
+ stub_request(:put, expected_url)
70
+ .to_return(status: status_code)
71
+ end
72
+
73
+ it 'returns a response with the correct code' do
74
+ response = subject.update(body: body, params: params, token: 'token')
75
+ expect(response.code).to eq(status_code)
76
+ end
77
+ end
78
+ end
79
+
43
80
  describe '#create_batch' do
44
81
  let(:expected_url) { "https://#{host}/api/quiz_clone_jobs/create_batch" }
45
82
  let(:body) { { quiz_ids: [1, 2] } }
@@ -3,24 +3,53 @@ describe QuizApiClient::Services::QuizEntriesService do
3
3
  let(:config) { QuizApiClient::Config.new { |c| c.host = host } }
4
4
  let(:subject) { described_class.new(config) }
5
5
 
6
+ def link_header(host, path, page, last_page)
7
+ link_header = "<https://#{host}#{path}?page=#{last_page}>; rel=\"last\""
8
+ link_header += ", <https://#{host}#{path}?page=#{page + 1}>; rel=\"next\"" if page < last_page
9
+ link_header += ", <https://#{host}#{path}?page=#{page - 1}>; rel=\"prev\"" if page > 1
10
+ link_header += ", <https://#{host}#{path}?page=1>; rel=\"first\"" if page > 1
11
+ { link: link_header }
12
+ end
13
+
14
+ def stub_quiz_api(url, body, query: {}, headers: {}, status: 200)
15
+ stub_request(:get, url)
16
+ .with(query: query)
17
+ .to_return(
18
+ body: body.to_json,
19
+ status: status,
20
+ headers: headers.merge(
21
+ 'Content-Type' => 'application/json'
22
+ )
23
+ )
24
+ end
25
+
6
26
  describe '#list' do
7
27
  let(:params) { { id: 1 } }
8
- let(:stubbed_response) { { 'id' => 1, 'entry' => { 'id' => 1 } } }
9
- let(:expected_url) { "https://#{host}/api/quizzes/#{params[:id]}/quiz_entries" }
10
- let(:status_code) { 200 }
28
+ let(:path) { "/api/quizzes/#{params[:id]}/quiz_entries" }
29
+ let(:expected_url) { "https://#{host}#{path}" }
11
30
 
12
- before do
13
- stub_request(:get, expected_url)
14
- .to_return(
15
- status: status_code,
16
- body: stubbed_response.to_json,
17
- headers: { 'Content-Type' => 'application/json' }
18
- )
31
+ def page(page_num)
32
+ [{ 'id' => page_num, 'entry' => { 'id' => page_num } }]
19
33
  end
20
34
 
21
- it 'gets from quiz_api/api/quizzes/{id}/quiz_entries and returns the response' do
22
- result = subject.list(params: params, token: 'token')
23
- expect(result.parsed_response).to eql(stubbed_response)
35
+ it 'single page' do
36
+ stub_quiz_api(expected_url, page(1), headers: link_header(host, path, 1, 1))
37
+ result = subject.list(params: params, token: 'token', all: true)
38
+ expect(result).to eql([{ 'id' => 1, 'entry' => { 'id' => 1 } }])
39
+ end
40
+
41
+ it 'paginated response' do
42
+ expected_result = [
43
+ { 'id' => 1, 'entry' => { 'id' => 1 } },
44
+ { 'id' => 2, 'entry' => { 'id' => 2 } },
45
+ { 'id' => 3, 'entry' => { 'id' => 3 } }
46
+ ]
47
+
48
+ stub_quiz_api(expected_url, page(1), headers: link_header(host, path, 1, 3))
49
+ stub_quiz_api(expected_url, page(2), query: { page: 2 }, headers: link_header(host, path, 2, 3))
50
+ stub_quiz_api(expected_url, page(3), query: { page: 3 }, headers: link_header(host, path, 3, 3))
51
+ result = subject.list(params: params, token: 'token', all: true)
52
+ expect(result).to eql(expected_result)
24
53
  end
25
54
  end
26
55
 
@@ -74,9 +103,9 @@ describe QuizApiClient::Services::QuizEntriesService do
74
103
  end
75
104
 
76
105
  describe '#update' do
77
- let(:params) { { quiz_id: 1, entry_id: 1, points_possible: 1 } }
106
+ let(:params) { { quiz_id: 1, id: 1, points_possible: 1 } }
78
107
  let(:stubbed_response) { { 'id' => 1, 'entry' => { 'id' => 1 } } }
79
- let(:expected_url) { "https://#{host}/api/quizzes/#{params[:quiz_id]}/quiz_entries/#{params[:entry_id]}" }
108
+ let(:expected_url) { "https://#{host}/api/quizzes/#{params[:quiz_id]}/quiz_entries/#{params[:id]}" }
80
109
  let(:status_code) { 200 }
81
110
  before do
82
111
  stub_request(:put, expected_url)
@@ -87,7 +116,7 @@ describe QuizApiClient::Services::QuizEntriesService do
87
116
  )
88
117
  end
89
118
 
90
- it 'puts to quiz_api/api/quizzes/{quiz_id}/quiz_entries/{entry_id} and returns the response' do
119
+ it 'puts to quiz_api/api/quizzes/{quiz_id}/quiz_entries/{id} and returns the response' do
91
120
  result = subject.update(params: params, token: 'token')
92
121
  expect(result.parsed_response).to eql(stubbed_response)
93
122
  end
@@ -45,5 +45,26 @@ describe QuizApiClient::Services::QuizSessionService do
45
45
  response = subject.show(params: params, token: 'token')
46
46
  expect(response.parsed_response).to eql(stubbed_response)
47
47
  end
48
+
49
+ context 'when the query param "disable_ac_invalidation" is given' do
50
+ let(:params) { { id: 1, disable_ac_invalidation: true } }
51
+ let(:stubbed_response) { { 'id' => 1, 'time_limit_seconds' => 10 } }
52
+ let(:expected_url) { "https://#{host}/api/quiz_sessions/#{params[:id]}?disable_ac_invalidation=true" }
53
+ let(:status_code) { 200 }
54
+
55
+ before do
56
+ stub_request(:get, expected_url)
57
+ .to_return(
58
+ status: status_code,
59
+ body: stubbed_response.to_json,
60
+ headers: { 'Content-Type' => 'application/json' }
61
+ )
62
+ end
63
+
64
+ it 'gets from quiz_api/api/quiz_sessions and returns the response' do
65
+ response = subject.show(params: params, token: 'token')
66
+ expect(response.parsed_response).to eql(stubbed_response)
67
+ end
68
+ end
48
69
  end
49
70
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quiz_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.8.0
4
+ version: 4.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Slaughter
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: exe
17
17
  cert_chain: []
18
- date: 2023-02-24 00:00:00.000000000 Z
18
+ date: 2023-10-23 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: httparty
@@ -179,6 +179,9 @@ files:
179
179
  - lib/quiz_api_client/http_request/failure.rb
180
180
  - lib/quiz_api_client/http_request/metrics.rb
181
181
  - lib/quiz_api_client/json_formatter.rb
182
+ - lib/quiz_api_client/services/analyses_service.rb
183
+ - lib/quiz_api_client/services/bank_entries_service.rb
184
+ - lib/quiz_api_client/services/bank_service.rb
182
185
  - lib/quiz_api_client/services/base_api_service.rb
183
186
  - lib/quiz_api_client/services/content_exports_service.rb
184
187
  - lib/quiz_api_client/services/courses_service.rb
@@ -209,6 +212,9 @@ files:
209
212
  - spec/quiz_api_client/http_request/failure_spec.rb
210
213
  - spec/quiz_api_client/http_request/metrics_spec.rb
211
214
  - spec/quiz_api_client_spec.rb
215
+ - spec/services/analyses_service_spec.rb
216
+ - spec/services/bank_entries_service_spec.rb
217
+ - spec/services/bank_service_spec.rb
212
218
  - spec/services/base_api_service_spec.rb
213
219
  - spec/services/content_exports_service_spec.rb
214
220
  - spec/services/courses_service_spec.rb
@@ -243,14 +249,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
243
249
  requirements:
244
250
  - - ">="
245
251
  - !ruby/object:Gem::Version
246
- version: '2.6'
252
+ version: '2.7'
247
253
  required_rubygems_version: !ruby/object:Gem::Requirement
248
254
  requirements:
249
255
  - - ">="
250
256
  - !ruby/object:Gem::Version
251
257
  version: '0'
252
258
  requirements: []
253
- rubygems_version: 3.3.7
259
+ rubygems_version: 3.4.10
254
260
  signing_key:
255
261
  specification_version: 4
256
262
  summary: Ruby client for quiz_api
@@ -261,6 +267,9 @@ test_files:
261
267
  - spec/quiz_api_client/http_request/failure_spec.rb
262
268
  - spec/quiz_api_client/http_request/metrics_spec.rb
263
269
  - spec/quiz_api_client_spec.rb
270
+ - spec/services/analyses_service_spec.rb
271
+ - spec/services/bank_entries_service_spec.rb
272
+ - spec/services/bank_service_spec.rb
264
273
  - spec/services/base_api_service_spec.rb
265
274
  - spec/services/content_exports_service_spec.rb
266
275
  - spec/services/courses_service_spec.rb