quiz_api_client 4.8.0 → 4.14.0

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: 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