atomic_lti 1.8.5 → 1.10.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: ba4c43d0a67a951d858b5610d4b7a26a4b0898c863113c515d554f961d172131
4
- data.tar.gz: cdf108a92d6e62a73b0294a38badb1ebd519de71520bf4f2ef5bb027de4fab21
3
+ metadata.gz: 51f6a8b44052a79ca2848b1b32f9789ce2033c79cc168b6b43467429f463efe7
4
+ data.tar.gz: 9fc1c514d21fcec53c9b74d7b7a673d774052539f5313480ca12d0b3ce886643
5
5
  SHA512:
6
- metadata.gz: 33fe99f4b5131ed6df49d4d36ee87058416c100f7bfc3a0fc06b163a6de8c3d30336a8260347d4d4c9db4b028e4e83b000582f94797254b932ff6433ea998ea4
7
- data.tar.gz: 9b0812047d37e222c6b49e7abffe288afe7c0836c2eb15c970d97ae50d3446c348f5b64cdbbc6eb70848d378a40893be518f084b9d97e85cb8d455080b04a63f
6
+ metadata.gz: 2d87e7f1666d050da989f2d10b017fbc90bc4f8e213f6082e1b45c96b907636ebfd4be09085bcc73bc251610e1b0e727b0204250906f1ef7a351cab50db502d8
7
+ data.tar.gz: d0cba43fba4d45d186dd45a804531409cf4d0b9a2453bb68e8ea9207048727c1e943147845034aa952991ce360a6380f44b90e479fd1317466fe9ac1d6eb7a44
@@ -11,6 +11,7 @@ module AtomicLti
11
11
  TOOL_PLATFORM_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/tool_platform".freeze
12
12
  AGS_CLAIM = "https://purl.imsglobal.org/spec/lti-ags/claim/endpoint".freeze
13
13
  BASIC_OUTCOME_CLAIM = "https://purl.imsglobal.org/spec/lti-bo/claim/basicoutcome".freeze
14
+ FOR_USER_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/for_user".freeze
14
15
 
15
16
  MENTOR_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/role_scope_mentor".freeze
16
17
  ROLES_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/roles".freeze
@@ -30,6 +31,12 @@ module AtomicLti
30
31
 
31
32
  NAMES_AND_ROLES_SERVICE_VERSIONS = ["2.0"].freeze
32
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
+
33
40
  CALIPER_CLAIM = "https://purl.imsglobal.org/spec/lti-ces/claim/caliper-endpoint-service".freeze
34
41
 
35
42
  TOOL_LAUNCH_CALIPER_CONTEXT = "http://purl.imsglobal.org/ctx/caliper/v1p1/ToolLaunchProfile-extension".freeze
@@ -42,6 +49,7 @@ module AtomicLti
42
49
  AGS_SCOPE_SCORE = "https://purl.imsglobal.org/spec/lti-ags/scope/score".freeze
43
50
  NAMES_AND_ROLES_SCOPE = "https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly".freeze
44
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
45
53
 
46
54
  STUDENT_SCOPE = "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Student".freeze
47
55
  INSTRUCTOR_SCOPE = "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Instructor".freeze
@@ -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
@@ -23,7 +23,8 @@ module AtomicLti
23
23
  resource_id: nil,
24
24
  tag: nil,
25
25
  resource_link_id: nil,
26
- external_tool_url: nil
26
+ external_tool_url: nil,
27
+ submission_review: nil
27
28
  )
28
29
  attrs = {
29
30
  scoreMaximum: max_score,
@@ -40,6 +41,9 @@ module AtomicLti
40
41
  external_tool_url: external_tool_url,
41
42
  }
42
43
  end
44
+ if submission_review
45
+ attrs[:submissionReview] = submission_review
46
+ end
43
47
  attrs
44
48
  end
45
49
 
@@ -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,3 +1,3 @@
1
1
  module AtomicLti
2
- VERSION = "1.8.5".freeze
2
+ VERSION = "1.10.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.8.5
4
+ version: 1.10.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-06-18 00:00:00.000000000 Z
13
+ date: 2024-07-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: pg
@@ -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.19
138
+ rubygems_version: 3.4.10
138
139
  signing_key:
139
140
  specification_version: 4
140
141
  summary: AtomicLti implements the LTI Advantage specification.