strongmind-platform-sdk 3.19.30 → 3.19.32

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: 99cb6793a19a83ca3efad9083a259ccf17b15fe1d64f3ac4a824964ac5e0bcc1
4
- data.tar.gz: 9765e4699c62939e57e328bebd72316a0eb26102cd3a994f92af7d1ebef253bc
3
+ metadata.gz: 220721704b3493784c6916cd60d381e82c6c581c0882de3afdce1bfeed4daa09
4
+ data.tar.gz: 6af5b9ec2711a28f202bcdde4f7b997633cfef6f3a0c500f272bec13d2ceb8a1
5
5
  SHA512:
6
- metadata.gz: a6490fd12ee607dcad600c9e5098da6561c757a50b9d0ab83be81d112c6d8865d638d8ea32faea512a5bd924b192efa1cdd87a66702acce4e3d8d86275dc9c9f
7
- data.tar.gz: 969ac7c437f12e2d91a8e4c5bdbae2a9dc01f2e15f40177d69110c8214cb574edf6dd1992750e955d44affc8aba0f37dee73907d1091720ca9ce14586e42b4d2
6
+ metadata.gz: eef3bdb74b5b1d66a8db6032017c379cf125b47b3f1e9cbc1ff5398fef3c2548fb87c7cafae85d0f295f96debc8c09351b29827ea4bb3e12b01fe0ab9bb868da
7
+ data.tar.gz: 6dc5553e6b644e25a0b19e598e08d260e61648a91d5dc3873fcb4d64daa26dd322875808330d76d39d62b076b2948add4204aeb9feb39678adb3ae6ea93ec1d8
data/Gemfile CHANGED
@@ -10,6 +10,7 @@ gemspec
10
10
 
11
11
  gem "faraday"
12
12
  gem "faraday-retry"
13
+ gem "faraday-multipart"
13
14
  gem "jwt", "~> 1.5", ">= 1.5.4"
14
15
  gem "learnosity-sdk", "~> 0.2.2"
15
16
  gem "multi_json"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- strongmind-platform-sdk (3.19.30)
4
+ strongmind-platform-sdk (3.19.32)
5
5
  activesupport (~> 7.1)
6
6
  asset_sync
7
7
  aws-sdk-secretsmanager (~> 1.66)
@@ -96,21 +96,21 @@ GEM
96
96
  tzinfo (~> 2.0)
97
97
  addressable (2.8.7)
98
98
  public_suffix (>= 2.0.2, < 7.0)
99
- asset_sync (2.19.1)
99
+ asset_sync (2.19.2)
100
100
  activemodel (>= 4.1.0)
101
101
  fog-core
102
102
  mime-types (>= 2.99)
103
103
  unf
104
104
  ast (2.4.2)
105
105
  aws-eventstream (1.3.0)
106
- aws-partitions (1.962.0)
106
+ aws-partitions (1.970.0)
107
107
  aws-sdk-cloudwatch (1.97.0)
108
108
  aws-sdk-core (~> 3, >= 3.201.0)
109
109
  aws-sigv4 (~> 1.5)
110
- aws-sdk-core (3.201.3)
110
+ aws-sdk-core (3.202.2)
111
111
  aws-eventstream (~> 1, >= 1.3.0)
112
112
  aws-partitions (~> 1, >= 1.651.0)
113
- aws-sigv4 (~> 1.8)
113
+ aws-sigv4 (~> 1.9)
114
114
  jmespath (~> 1, >= 1.6.1)
115
115
  aws-sdk-secretsmanager (1.102.0)
116
116
  aws-sdk-core (~> 3, >= 3.201.0)
@@ -141,6 +141,8 @@ GEM
141
141
  faraday (2.10.0)
142
142
  faraday-net_http (>= 2.0, < 3.2)
143
143
  logger
144
+ faraday-multipart (1.0.4)
145
+ multipart-post (~> 2)
144
146
  faraday-net_http (3.1.1)
145
147
  net-http
146
148
  faraday-retry (2.2.1)
@@ -148,7 +150,8 @@ GEM
148
150
  ffi (1.17.0)
149
151
  ffi (1.17.0-x86_64-darwin)
150
152
  ffi (1.17.0-x86_64-linux-gnu)
151
- fog-aws (3.24.0)
153
+ fog-aws (3.25.0)
154
+ base64 (~> 0.2.0)
152
155
  fog-core (~> 2.1)
153
156
  fog-json (~> 1.1)
154
157
  fog-xml (~> 0.1)
@@ -192,15 +195,16 @@ GEM
192
195
  method_source (1.1.0)
193
196
  mime-types (3.5.2)
194
197
  mime-types-data (~> 3.2015)
195
- mime-types-data (3.2024.0806)
198
+ mime-types-data (3.2024.0820)
196
199
  mini_mime (1.1.5)
197
200
  mini_portile2 (2.8.7)
198
201
  minitest (5.24.1)
199
202
  multi_json (1.15.0)
203
+ multipart-post (2.4.1)
200
204
  mutex_m (0.2.0)
201
205
  net-http (0.4.1)
202
206
  uri
203
- net-imap (0.4.14)
207
+ net-imap (0.4.15)
204
208
  date
205
209
  net-protocol
206
210
  net-pop (0.1.2)
@@ -314,7 +318,7 @@ GEM
314
318
  sentry-ruby (5.18.2)
315
319
  bigdecimal
316
320
  concurrent-ruby (~> 1.0, >= 1.0.2)
317
- sidekiq (7.3.0)
321
+ sidekiq (7.3.1)
318
322
  concurrent-ruby (< 2)
319
323
  connection_pool (>= 2.3.0)
320
324
  logger
@@ -341,9 +345,7 @@ GEM
341
345
  ethon (>= 0.9.0)
342
346
  tzinfo (2.0.6)
343
347
  concurrent-ruby (~> 1.0)
344
- unf (0.1.4)
345
- unf_ext
346
- unf_ext (0.0.9.1)
348
+ unf (0.2.0)
347
349
  unicode-display_width (2.5.0)
348
350
  uri (0.13.0)
349
351
  webmock (3.23.1)
@@ -366,6 +368,7 @@ DEPENDENCIES
366
368
  factory_bot
367
369
  faker
368
370
  faraday
371
+ faraday-multipart
369
372
  faraday-retry
370
373
  jwt (~> 1.5, >= 1.5.4)
371
374
  learnosity-sdk (~> 0.2.2)
@@ -9,7 +9,7 @@ module PlatformSdk
9
9
  included do
10
10
  after_create :send_pipeline_create
11
11
  before_destroy :send_pipeline_destroy
12
- after_update :send_pipeline_update
12
+ after_update :send_pipeline_update, if: -> { saved_changes? }
13
13
  end
14
14
 
15
15
  def send_pipeline_create
@@ -55,9 +55,9 @@ module PlatformSdk
55
55
 
56
56
  def pipeline_data(action)
57
57
  attributes.symbolize_keys
58
- .merge(pipeline_additional_attributes)
59
- .except(*pipeline_excluded_attributes)
60
- .merge(action:)
58
+ .merge(pipeline_additional_attributes)
59
+ .except(*pipeline_excluded_attributes)
60
+ .merge(action:)
61
61
  end
62
62
 
63
63
  def pipeline_additional_attributes
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "faraday"
4
+ require "faraday/multipart"
5
+
4
6
 
5
7
  module PlatformSdk
6
8
  module CanvasApiWrapper
7
9
  # DataPipeline::Client
8
10
  class Client
9
- attr_reader :host, :token, :connection
11
+ attr_reader :host, :token, :connection, :multipart_connection
10
12
 
11
13
  PAGE_SIZE = 10
12
14
 
@@ -16,6 +18,10 @@ module PlatformSdk
16
18
  @host = "https://#{domain}"
17
19
  @token = token
18
20
  @connection = Faraday.new(url: host, headers: { 'Authorization' => "Bearer #{token}" })
21
+ @multipart_connection = Faraday.new(url: host, headers: { 'Authorization' => "Bearer #{token}" }) do |f|
22
+ f.request :multipart
23
+ f.adapter :net_http
24
+ end
19
25
  end
20
26
 
21
27
  # @param course_id [Integer]
@@ -348,6 +354,44 @@ module PlatformSdk
348
354
  end
349
355
  end
350
356
 
357
+ # @param course_id [Integer]
358
+ # @param module_id [Integer]
359
+ def put_relock_module(course_id:, module_id:)
360
+ uri = "api/v1/courses/#{course_id}/modules/#{module_id}/relock"
361
+ response = @connection.put(uri)
362
+ result = MultiJson.load response.body, symbolize_keys: true
363
+ handle_rate_limiting response
364
+ if success?(response.status)
365
+ result
366
+ else
367
+ error_message = parse_response_errors(result:, message: 'Error re-locking module')
368
+ raise CanvasClientError, error_message
369
+ end
370
+ end
371
+
372
+ # @param course_id [Integer]
373
+ # @param module_id [Integer]
374
+ # @param prerequisite_ids [Array<Integer>]
375
+ # @note prerequisite_ids should be a valid module_id, sending and empty array removes all prerequisites.
376
+ def put_module_prerequesites(course_id:, module_id:, prerequisite_ids:)
377
+ uri = "/api/v1/courses/#{course_id}/modules/#{module_id}"
378
+ response = @multipart_connection.put(uri) do |req|
379
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
380
+ req.body = { 'module[prerequisite_module_ids]' => prerequisite_ids }
381
+ end
382
+ handle_rate_limiting response
383
+ result = MultiJson.load response.body, symbolize_keys: true
384
+ if success?(response.status)
385
+ result
386
+ else
387
+ error_messages = String.new
388
+ result[:errors]&.each do |error|
389
+ error_messages << "#{error[:message]} "
390
+ end
391
+ raise "Error updating module prerequisite: #{error_messages}"
392
+ end
393
+ end
394
+
351
395
  private
352
396
 
353
397
  # @param headers [Faraday::Utils::Headers]
@@ -408,14 +452,14 @@ module PlatformSdk
408
452
  # @param message [String]
409
453
  def handle_post_response_errors(response, message)
410
454
  result = MultiJson.load response.body, symbolize_keys: true
411
- raise PlatformSdk::CanvasApiWrapper::Client::LockedModuleItemError, "#{message}: #{result[:message]}" if response.status == 403
412
- raise PlatformSdk::CanvasApiWrapper::Client::MissingModuleItemError, "#{message}: #{result[:message]}" if response.status == 404
413
- raise PlatformSdk::CanvasApiWrapper::Client::CanvasClientError, parse_response_errors(message:, result:)
455
+ raise LockedModuleItemError, "#{message}: #{result[:message]}" if response.status == 403
456
+ raise MissingModuleItemError, "#{message}: #{result[:message]}" if response.status == 404
457
+ raise CanvasClientError, parse_response_errors(message:, result:)
414
458
  end
415
459
  end
416
460
 
417
- class Client::CanvasClientError < StandardError; end
418
- class Client::LockedModuleItemError < Client::CanvasClientError; end
419
- class Client::MissingModuleItemError < Client::CanvasClientError; end
461
+ class CanvasClientError < StandardError; end
462
+ class LockedModuleItemError < CanvasClientError; end
463
+ class MissingModuleItemError < CanvasClientError; end
420
464
  end
421
465
  end
@@ -1,6 +1,7 @@
1
1
  module PlatformSdk
2
2
  module SpecSupport
3
- RSpec.shared_examples "DataPipelineable" do
3
+ RSpec.shared_examples 'DataPipelineable' do |params = {}|
4
+ let(:shared_params) { params }
4
5
  let(:record) { build(described_class.to_s.underscore.to_sym) }
5
6
  let(:data_pipeline_client) { double(PlatformSdk::DataPipeline::Client) }
6
7
 
@@ -12,41 +13,76 @@ module PlatformSdk
12
13
 
13
14
  after { Timecop.return }
14
15
 
15
- context 'after_create callbacks' do
16
- before { allow(record).to receive(:send_pipeline_create) }
16
+ context 'create' do
17
17
 
18
- it "defines an after_create callback" do
18
+ it 'posts a copy of our data to the data pipeline' do
19
19
  record.save!
20
- expect(record).to have_received(:send_pipeline_create)
20
+ expect(data_pipeline_client).to have_received(:post).once.with(hash_including(
21
+ noun: described_class.pipeline_noun,
22
+ data: record.pipeline_data('created'),
23
+ meta: described_class.pipeline_meta,
24
+ envelope_version: '1.0.0',
25
+ message_timestamp: Time.current.utc.iso8601,
26
+ identifiers: { id: record.id },
27
+ ))
21
28
  end
22
29
  end
23
30
 
24
- context 'before_destroy callbacks' do
25
- before do
26
- allow(record).to receive(:send_pipeline_create)
27
- allow(record).to receive(:send_pipeline_destroy)
28
- end
31
+ context 'destroy' do
29
32
 
30
- it "defines an after_destroy callback" do
33
+ it 'posts a copy of our data to the data pipeline' do
31
34
  record.save!
32
35
  record.destroy
33
36
 
34
- expect(record).to have_received(:send_pipeline_create)
35
- expect(record).to have_received(:send_pipeline_destroy)
37
+ expect(data_pipeline_client).to have_received(:post).once.with(hash_including(
38
+ noun: described_class.pipeline_noun,
39
+ data: record.pipeline_data('destroyed'),
40
+ meta: described_class.pipeline_meta,
41
+ envelope_version: '1.0.0',
42
+ message_timestamp: Time.current.utc.iso8601,
43
+ identifiers: { id: record.id }
44
+ ))
36
45
  end
37
46
  end
38
47
 
39
- context 'after_update callbacks' do
48
+ context 'update' do
40
49
  before do
41
- allow(record).to receive(:send_pipeline_update)
42
50
  record.save!
43
51
  end
44
52
 
45
- it "defines an after_update callback" do
46
- column = column_to_update(record)
47
- unless column.nil?
53
+ context 'after an update' do
54
+ it 'posts a copy of our data to the data pipeline' do
55
+ column = column_to_update(record)
56
+ unless column.nil?
57
+ update_record(record, column)
58
+ expect(data_pipeline_client).to have_received(:post).once.with(hash_including(
59
+ noun: described_class.pipeline_noun,
60
+ data: record.pipeline_data('modified'),
61
+ meta: described_class.pipeline_meta,
62
+ envelope_version: '1.0.0',
63
+ message_timestamp: Time.current.utc.iso8601,
64
+ identifiers: { id: record.id },
65
+ ))
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'after an update that does not change data' do
71
+ let(:action) { 'modified' }
72
+
73
+ it 'does not post to the data pipeline' do
74
+ record.save!
75
+ column = column_to_update(record)
48
76
  update_record(record, column)
49
- expect(record).to have_received(:send_pipeline_update)
77
+ record.save!
78
+ expect(data_pipeline_client).to have_received(:post).once.with(hash_including(
79
+ noun: described_class.pipeline_noun,
80
+ data: record.pipeline_data('modified'),
81
+ meta: described_class.pipeline_meta,
82
+ envelope_version: '1.0.0',
83
+ message_timestamp: Time.current.utc.iso8601,
84
+ identifiers: { id: record.id }
85
+ ))
50
86
  end
51
87
  end
52
88
  end
@@ -60,13 +96,18 @@ module PlatformSdk
60
96
  end
61
97
 
62
98
  def update_record(record, column)
99
+ if shared_params[:update_method]
100
+ send(shared_params[:update_method], record)
101
+ return
102
+ end
63
103
  new_record = build(described_class.to_s.underscore.to_sym)
64
104
 
65
- column_class = record[column]
66
- case column_class
67
- when Integer
105
+ column_value = record[column]
106
+ column_class = column_value.class
107
+ case column_class.to_s
108
+ when 'Integer'
68
109
  record.update!(column => 69)
69
- when [true, false].include?(column_class)
110
+ when 'TrueClass', 'FalseClass'
70
111
  record.update!(column => !record[column])
71
112
  else
72
113
  record.update!(column => new_record[column])
@@ -90,9 +131,9 @@ module PlatformSdk
90
131
 
91
132
  let(:data) do
92
133
  record.attributes.symbolize_keys
93
- .merge(record.pipeline_additional_attributes)
94
- .except(*record.pipeline_excluded_attributes)
95
- .merge(action:)
134
+ .merge(record.pipeline_additional_attributes)
135
+ .except(*record.pipeline_excluded_attributes)
136
+ .merge(action:)
96
137
  end
97
138
 
98
139
  it 'returns the expected payload' do
@@ -2,10 +2,10 @@
2
2
 
3
3
  module PlatformSdk
4
4
  module SpecSupport
5
- RSpec.shared_examples "OneRosterDataPipelineable" do |record_keys|
5
+ RSpec.shared_examples 'OneRosterDataPipelineable' do |record_keys|
6
6
  let(:data) do
7
7
  record_keys.each_with_object({}) do |key, hash|
8
- if key == "_type"
8
+ if key == '_type'
9
9
  hash[:type] = record.try(key)
10
10
  next
11
11
  end
@@ -17,11 +17,11 @@ module PlatformSdk
17
17
  "noun": "StrongMind.Platform.OneRoster.#{record.one_roster_data_type.capitalize}",
18
18
  "identifiers": { "sourcedId": record.roster_id },
19
19
  "meta": {
20
- "version": "3",
21
- "source": "Central OneRoster API"
20
+ "version": '3',
21
+ "source": 'Central OneRoster API'
22
22
  },
23
23
  "data": one_roster_common_data.merge!(data),
24
- "envelope_version": "1.0.0",
24
+ "envelope_version": '1.0.0',
25
25
  "message_timestamp": Time.current.utc.iso8601
26
26
  }
27
27
  end
@@ -39,27 +39,27 @@ module PlatformSdk
39
39
  before do
40
40
  allow(PlatformSdk::DataPipeline::Client).to receive(:new).and_return(data_pipeline_client)
41
41
  allow(data_pipeline_client).to receive(:post)
42
- Timecop.freeze(DateTime.parse("2024-06-09 04:20:00"))
42
+ Timecop.freeze(DateTime.parse('2024-06-09 04:20:00'))
43
43
  end
44
44
 
45
45
  after do
46
46
  Timecop.return
47
47
  end
48
48
 
49
- context "after_create callbacks" do
50
- let(:action) { "created" }
49
+ context 'create' do
50
+ let(:action) { 'created' }
51
51
 
52
- it "defines an after_create callback" do
52
+ it 'posts to the data pipeline' do
53
53
  record.save!
54
54
  expect(data_pipeline_client).to have_received(:post).with(pipeline_payload)
55
55
  end
56
56
  end
57
57
 
58
- context "before_destroy callbacks" do
59
- let(:action) { "destroyed" }
58
+ context 'destroy' do
59
+ let(:action) { 'destroyed' }
60
60
  let(:one_roster_common_data_deleted) do
61
61
  one_roster_common_data.merge(
62
- "status": "tobedeleted"
62
+ "status": 'tobedeleted'
63
63
  )
64
64
  end
65
65
 
@@ -67,7 +67,7 @@ module PlatformSdk
67
67
  pipeline_payload.merge("data": one_roster_common_data_deleted)
68
68
  end
69
69
 
70
- it "defines an after_destroy callback" do
70
+ it 'posts to the data pipeline' do
71
71
  record.save!
72
72
  record.destroy
73
73
  expect(data_pipeline_client).to have_received(:post).with(pipeline_payload)
@@ -75,18 +75,33 @@ module PlatformSdk
75
75
  end
76
76
  end
77
77
 
78
- context "after_update callbacks" do
79
- let(:action) { "modified" }
78
+ context 'update' do
79
+ let(:action) { 'modified' }
80
80
 
81
81
  before do
82
- allow(record).to receive(:send_pipeline_create)
83
82
  record.save!
84
83
  end
85
84
 
86
- it "defines an after_update callback" do
87
- column = column_to_update(record)
88
- update_record(record, column)
89
- expect(data_pipeline_client).to have_received(:post).with(pipeline_payload)
85
+ context 'after an update' do
86
+
87
+ it 'posts a copy of our data to the data pipeline' do
88
+ column = column_to_update(record)
89
+ update_record(record, column)
90
+ expect(data_pipeline_client).to have_received(:post).with(pipeline_payload)
91
+ end
92
+
93
+ end
94
+
95
+ context 'after an update that does not change data' do
96
+ let(:action) { 'modified' }
97
+
98
+ it 'does not post to the data pipeline' do
99
+ record.save!
100
+ column = column_to_update(record)
101
+ update_record(record, column)
102
+ record.save!
103
+ expect(data_pipeline_client).to have_received(:post).once.with(pipeline_payload)
104
+ end
90
105
  end
91
106
  end
92
107
 
@@ -100,11 +115,12 @@ module PlatformSdk
100
115
  def update_record(record, column)
101
116
  new_record = build(described_class.to_s.underscore.to_sym)
102
117
 
103
- column_class = record[column]
104
- case column_class
105
- when Integer
118
+ column_value = record[column]
119
+ column_class = column_value.class
120
+ case column_class.to_s
121
+ when 'Integer'
106
122
  record.update!(column => 69)
107
- when [true, false].include?(column_class)
123
+ when 'TrueClass', 'FalseClass'
108
124
  record.update!(column => !record[column])
109
125
  else
110
126
  record.update!(column => new_record[column])
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PlatformSdk
4
- VERSION = '3.19.30'
4
+ VERSION = '3.19.32'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strongmind-platform-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.19.30
4
+ version: 3.19.32
5
5
  platform: ruby
6
6
  authors:
7
7
  - Platform Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-07 00:00:00.000000000 Z
11
+ date: 2024-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday