atomic_lti 1.9.0 → 2.0.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: e8b38d2b638688e1308e60601a9586a6d4f44c973bfe82aa3d94c7941f1f3f79
4
- data.tar.gz: b280f79bab178696f88dfb2bb34af9cf1a4cf8b0c2835a2c8040890d7c994b2b
3
+ metadata.gz: aac6096f2a93856e8186ad6dfa5cd43856a0ac2ffd16d2e9a1353d404742c69a
4
+ data.tar.gz: 64b8ffeeb7d74e020ae63fa8c42d2401e4632a4fb4a311fdf06cb177069e801a
5
5
  SHA512:
6
- metadata.gz: 8a117f214fe877902d629474a237edcae89f7635b5028534010e64925a0c845b20066cca8694fa8350e3018f1e1713ec1f25667801216230a1a2f755d6639a8c
7
- data.tar.gz: a20d30b4094c1344fb45fbcb440319182626b08e0ef968dcf80e0a610184c35a71f6f5690322b7f168b39925929ce8f7da47652e5b588fee697fdf7c5c43e2b4
6
+ metadata.gz: d1ad65c60634d64306683166dffbf5cb2fb72a79b5db177c76c720cfa98859e3b5db6e30951f92a198be6c232f0a2ffc84be8449e38bb55279cd90d62de54ee3
7
+ data.tar.gz: 8b1df93f772d15b9e20482928bdcd8f766fe00769818c1217bf98e3a3ff111a80793ad2ee2d005992175bc147ccad024fc2fe3f453f49ceb0b85589c3009d336
@@ -31,6 +31,12 @@ module AtomicLti
31
31
 
32
32
  NAMES_AND_ROLES_SERVICE_VERSIONS = ["2.0"].freeze
33
33
 
34
+ PLATFORM_NOTIFICATION_SERVICE_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/platformnotificationservice".freeze
35
+ PLATFORM_NOTIFICATION_SERVICE_VERSIONS = ["1.0".freeze].freeze
36
+ NOTICE_TYPE_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/notice_type".freeze
37
+ PLATFORM_NOTIFICATION_CONTEXT_COPY_NOTICE = "LtiContextCopyNotice".freeze
38
+ PLATFORM_NOTIFICATION_CONTEXT_COPY_ORIGINS_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/origin_contexts".freeze
39
+
34
40
  CALIPER_CLAIM = "https://purl.imsglobal.org/spec/lti-ces/claim/caliper-endpoint-service".freeze
35
41
 
36
42
  TOOL_LAUNCH_CALIPER_CONTEXT = "http://purl.imsglobal.org/ctx/caliper/v1p1/ToolLaunchProfile-extension".freeze
@@ -43,6 +49,7 @@ module AtomicLti
43
49
  AGS_SCOPE_SCORE = "https://purl.imsglobal.org/spec/lti-ags/scope/score".freeze
44
50
  NAMES_AND_ROLES_SCOPE = "https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly".freeze
45
51
  CALIPER_SCOPE = "https://purl.imsglobal.org/spec/lti-ces/v1p0/scope/send".freeze
52
+ PNS_SCOPE_NOTICEHANDLERS = "https://purl.imsglobal.org/spec/lti/scope/noticehandlers".freeze
46
53
 
47
54
  STUDENT_SCOPE = "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Student".freeze
48
55
  INSTRUCTOR_SCOPE = "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Instructor".freeze
@@ -167,6 +174,7 @@ module AtomicLti
167
174
 
168
175
  OBSERVER_ROLES = [
169
176
  MENTOR_INSTITUTION_ROLE,
177
+ MENTOR_CONTEXT_ROLE,
170
178
  # NON_CREDIT_LEARNER,
171
179
  ].freeze
172
180
 
@@ -14,6 +14,8 @@ module AtomicLti
14
14
  class NamesAndRolesError < AtomicLtiException
15
15
  end
16
16
 
17
+ class PlatformNotificationsError < AtomicLtiException; end
18
+
17
19
  class ScoreError < AtomicLtiException
18
20
  end
19
21
 
@@ -98,5 +100,7 @@ module AtomicLti
98
100
 
99
101
  class PaginationLimitExceeded < AtomicLtiException
100
102
  end
103
+
104
+ class InvalidPlatformNotification < AtomicLtiException; end
101
105
  end
102
106
  end
@@ -0,0 +1,100 @@
1
+ module AtomicLti
2
+ module Services
3
+ class PlatformNotifications < AtomicLti::Services::Base
4
+ def scopes
5
+ [AtomicLti::Definitions::PNS_SCOPE_NOTICEHANDLERS]
6
+ end
7
+
8
+ def endpoint
9
+ url = @id_token_decoded.dig(AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_CLAIM, "platform_notification_service_url")
10
+ raise AtomicLti::Exceptions::PlatformNotificationsError, "Unable to access platform notifications" if url.blank?
11
+
12
+ url
13
+ end
14
+
15
+ def url_for(query = nil)
16
+ url = endpoint.dup
17
+ url << "?#{query}" if query.present?
18
+ url
19
+ end
20
+
21
+ def self.enabled?(id_token_decoded)
22
+ return false unless id_token_decoded&.dig(AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_CLAIM)
23
+
24
+ (AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_VERSIONS &
25
+ (id_token_decoded.dig(AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_CLAIM, "service_versions") || [])).present?
26
+ end
27
+
28
+ def valid?
29
+ self.class.enabled?(@id_token_decoded)
30
+ end
31
+
32
+ # Get platform notifications
33
+ def get(query: {})
34
+ uri = Addressable::URI.parse(endpoint)
35
+ uri.query_values = (uri.query_values || {}).merge(query)
36
+ url = uri.to_str
37
+
38
+ response, = service_get(url, headers:)
39
+ response.parsed_response
40
+ end
41
+
42
+ def update(notice_type, handler)
43
+ content_type = { "Content-Type" => "application/json" }
44
+ payload = { notice_type:, handler: }
45
+ response, = service_put(endpoint, body: JSON.dump(payload), headers: headers(content_type))
46
+ response
47
+ end
48
+
49
+ def self.validate_notification(notification)
50
+ decoded_token = AtomicLti::Authorization.validate_token(notification)
51
+ if decoded_token.blank?
52
+ raise AtomicLti::Exceptions::InvalidPlatformNotification
53
+ end
54
+
55
+ errors = []
56
+
57
+ if decoded_token["iss"].blank?
58
+ errors.push("LTI token is missing required field iss")
59
+ end
60
+
61
+ if decoded_token["aud"].blank?
62
+ errors.push("LTI token is missing required field aud")
63
+ end
64
+
65
+ if decoded_token["aud"].is_a?(Array) && decoded_token["aud"].length > 1
66
+ # OpenID Connect spec specifies the AZP should exist and be an AUD
67
+ if decoded_token["azp"].blank?
68
+ errors.push("LTI token has multiple aud and is missing required field azp")
69
+ elsif decoded_token["aud"].exclude?(decoded_token["azp"])
70
+ errors.push("LTI token azp is not one of the aud's")
71
+ end
72
+ end
73
+
74
+ if decoded_token[AtomicLti::Definitions::DEPLOYMENT_ID].blank?
75
+ errors.push(
76
+ "LTI token is missing required field #{AtomicLti::Definitions::DEPLOYMENT_ID}",
77
+ )
78
+ end
79
+
80
+ if decoded_token[AtomicLti::Definitions::NOTICE_TYPE_CLAIM].blank?
81
+ errors.push(
82
+ "LTI token is missing required claim #{AtomicLti::Definitions::NOTICE_TYPE_CLAIM}",
83
+ )
84
+ end
85
+
86
+ if errors.present?
87
+ raise Exceptions::InvalidPlatformNotification.new(errors.join(" "))
88
+ end
89
+
90
+ if decoded_token[AtomicLti::Definitions::LTI_VERSION].blank?
91
+ raise AtomicLti::Exceptions::NoLTIVersion
92
+ end
93
+
94
+ raise AtomicLti::Exceptions::InvalidLTIVersion unless AtomicLti::Lti.valid_version?(decoded_token)
95
+
96
+ decoded_token
97
+ end
98
+ end
99
+ end
100
+ end
@@ -1,7 +1,8 @@
1
1
  module AtomicLti
2
2
  class Context < ApplicationRecord
3
+ query_constraints :context_id, :deployment_id, :iss
3
4
  belongs_to :platform, primary_key: :iss, foreign_key: :iss
4
- # belongs_to :deployment, primary_key: [:iss, :deployment_id], foreign_key: [:iss, :deployment_id] # TODO: this breaks rspec
5
+ belongs_to :deployment, query_constraints: [:iss, :deployment_id], optional: true
5
6
 
6
7
  validates :context_id, presence: true
7
8
  validates :deployment_id, presence: true
@@ -1,7 +1,9 @@
1
1
  module AtomicLti
2
2
  class Deployment < ApplicationRecord
3
+ query_constraints :deployment_id, :iss
3
4
  belongs_to :platform, primary_key: :iss, foreign_key: :iss
4
- belongs_to :install, primary_key: [:iss, :client_id], foreign_key: [:iss, :client_id], optional: true
5
+ belongs_to :install, query_constraints: [:client_id, :iss], optional: true
6
+ has_many :contexts, query_constraints: [:deployment_id, :iss]
5
7
 
6
8
  # we won't have platform_guid during dynamic registration
7
9
  # belongs_to :platform_instance, primary_key: :guid, foreign_key: :platform_guid, optional: true
@@ -1,11 +1,10 @@
1
1
  module AtomicLti
2
2
  class Install < ApplicationRecord
3
+ query_constraints :client_id, :iss
3
4
  belongs_to :platform, primary_key: :iss, foreign_key: :iss
5
+ has_many :deployments, query_constraints: [:client_id, :iss]
4
6
 
5
7
  validates :client_id, presence: true
6
8
  validates :iss, presence: true
7
- def deployments
8
- AtomicLti::Deployment.where("iss = ? AND client_id = ?", iss, client_id)
9
- end
10
9
  end
11
10
  end
@@ -1,5 +1,9 @@
1
1
  module AtomicLti
2
2
  class Platform < ApplicationRecord
3
+ query_constraints :iss
3
4
  validates :iss, presence: true
5
+ has_many :platform_instances, foreign_key: :iss, primary_key: :iss
6
+ has_many :deployments, foreign_key: :iss, primary_key: :iss
7
+ has_many :contexts, foreign_key: :iss, primary_key: :iss
4
8
  end
5
9
  end
@@ -1,3 +1,3 @@
1
1
  module AtomicLti
2
- VERSION = "1.9.0".freeze
2
+ VERSION = "2.0.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atomic_lti
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Petro
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-07-02 00:00:00.000000000 Z
13
+ date: 2024-10-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: pg
@@ -32,14 +32,14 @@ dependencies:
32
32
  requirements:
33
33
  - - "~>"
34
34
  - !ruby/object:Gem::Version
35
- version: '7.0'
35
+ version: '7.1'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
- version: '7.0'
42
+ version: '7.1'
43
43
  description: AtomicLti implements the LTI Advantage specification. This gem does contain
44
44
  source code specific to other Atomic Jolt products
45
45
  email:
@@ -77,6 +77,7 @@ files:
77
77
  - app/lib/atomic_lti/services/base.rb
78
78
  - app/lib/atomic_lti/services/line_items.rb
79
79
  - app/lib/atomic_lti/services/names_and_roles.rb
80
+ - app/lib/atomic_lti/services/platform_notifications.rb
80
81
  - app/lib/atomic_lti/services/results.rb
81
82
  - app/lib/atomic_lti/services/score.rb
82
83
  - app/lib/atomic_lti/services/score_canvas.rb
@@ -134,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
135
  - !ruby/object:Gem::Version
135
136
  version: '0'
136
137
  requirements: []
137
- rubygems_version: 3.4.10
138
+ rubygems_version: 3.4.19
138
139
  signing_key:
139
140
  specification_version: 4
140
141
  summary: AtomicLti implements the LTI Advantage specification.