Skip to content

Commit 3a192de

Browse files
authored
Merge pull request #47 from IMSGlobal/groups_and_sub_review
Add support for the groups service and submission review
2 parents 8a42ff7 + b124206 commit 3a192de

7 files changed

+256
-1
lines changed

src/lti/LTI_Course_Groups_Service.php

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
namespace IMSGlobal\LTI;
3+
4+
class LTI_Course_Groups_Service {
5+
6+
private $service_connector;
7+
private $service_data;
8+
9+
public function __construct(LTI_Service_Connector $service_connector, $service_data) {
10+
$this->service_connector = $service_connector;
11+
$this->service_data = $service_data;
12+
}
13+
14+
public function get_groups() {
15+
16+
$groups = [];
17+
18+
$next_page = $this->service_data['context_groups_url'];
19+
20+
while ($next_page) {
21+
$page = $this->service_connector->make_service_request(
22+
$this->service_data['scope'],
23+
'GET',
24+
$next_page,
25+
null,
26+
null,
27+
'application/vnd.ims.lti-gs.v1.contextgroupcontainer+json'
28+
);
29+
30+
$groups = array_merge($groups, $page['body']['groups']);
31+
32+
$next_page = false;
33+
foreach($page['headers'] as $header) {
34+
if (preg_match(LTI_Service_Connector::NEXT_PAGE_REGEX, $header, $matches)) {
35+
$next_page = $matches[1];
36+
break;
37+
}
38+
}
39+
}
40+
return $groups;
41+
42+
}
43+
44+
public function get_sets() {
45+
46+
$sets = [];
47+
48+
// Sets are optional.
49+
if (!isset($this->service_data['context_group_sets_url'])) {
50+
return [];
51+
}
52+
53+
$next_page = $this->service_data['context_group_sets_url'];
54+
55+
while ($next_page) {
56+
$page = $this->service_connector->make_service_request(
57+
$this->service_data['scope'],
58+
'GET',
59+
$next_page,
60+
null,
61+
null,
62+
'application/vnd.ims.lti-gs.v1.contextgroupcontainer+json'
63+
);
64+
65+
$sets = array_merge($sets, $page['body']['sets']);
66+
67+
$next_page = false;
68+
foreach($page['headers'] as $header) {
69+
if (preg_match(LTI_Service_Connector::NEXT_PAGE_REGEX, $header, $matches)) {
70+
$next_page = $matches[1];
71+
break;
72+
}
73+
}
74+
}
75+
return $sets;
76+
77+
}
78+
79+
public function get_groups_by_set() {
80+
$groups = $this->get_groups();
81+
$sets = $this->get_sets();
82+
83+
$groups_by_set = [];
84+
$unsetted = [];
85+
86+
foreach ($sets as $key => $set) {
87+
$groups_by_set[$set['id']] = $set;
88+
$groups_by_set[$set['id']]['groups'] = [];
89+
}
90+
91+
foreach ($groups as $key => $group) {
92+
if (isset($group['set_id']) && isset($groups_by_set[$group['set_id']])) {
93+
$groups_by_set[$group['set_id']]['groups'][$group['id']] = $group;
94+
} else {
95+
$unsetted[$group['id']] = $group;
96+
}
97+
}
98+
99+
if (!empty($unsetted)) {
100+
$groups_by_set['none'] = [
101+
"name" => "None",
102+
"id" => "none",
103+
"groups" => $unsetted,
104+
];
105+
}
106+
107+
return $groups_by_set;
108+
}
109+
}
110+
?>

src/lti/LTI_Grade.php

+22
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
class LTI_Grade {
55
private $score_given;
66
private $score_maximum;
7+
private $comment;
78
private $activity_progress;
89
private $grading_progress;
910
private $timestamp;
1011
private $user_id;
12+
private $submission_review;
1113

1214
/**
1315
* Static function to allow for method chaining without having to assign to a variable first.
@@ -34,6 +36,15 @@ public function set_score_maximum($value) {
3436
return $this;
3537
}
3638

39+
public function get_comment() {
40+
return $this->comment;
41+
}
42+
43+
public function set_comment($comment) {
44+
$this->comment = $comment;
45+
return $this;
46+
}
47+
3748
public function get_activity_progress() {
3849
return $this->activity_progress;
3950
}
@@ -70,14 +81,25 @@ public function set_user_id($value) {
7081
return $this;
7182
}
7283

84+
public function get_submission_review() {
85+
return $this->submission_review;
86+
}
87+
88+
public function set_submission_review($value) {
89+
$this->submission_review = $value;
90+
return $this;
91+
}
92+
7393
public function __toString() {
7494
return json_encode(array_filter([
7595
"scoreGiven" => 0 + $this->score_given,
7696
"scoreMaximum" => 0 + $this->score_maximum,
97+
"comment" => $this->comment,
7798
"activityProgress" => $this->activity_progress,
7899
"gradingProgress" => $this->grading_progress,
79100
"timestamp" => $this->timestamp,
80101
"userId" => $this->user_id,
102+
"submissionReview" => $this->submission_review,
81103
]));
82104
}
83105
}
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
namespace IMSGlobal\LTI;
3+
4+
class LTI_Grade_Submission_Review {
5+
private $reviewable_status;
6+
private $label;
7+
private $url;
8+
private $custom;
9+
10+
/**
11+
* Static function to allow for method chaining without having to assign to a variable first.
12+
*/
13+
public static function new() {
14+
return new LTI_Grade_Submission_Review();
15+
}
16+
17+
public function get_reviewable_status() {
18+
return $this->reviewable_status;
19+
}
20+
21+
public function set_reviewable_status($value) {
22+
$this->reviewable_status = $value;
23+
return $this;
24+
}
25+
26+
public function get_label() {
27+
return $this->label;
28+
}
29+
30+
public function set_label($value) {
31+
$this->label = $value;
32+
return $this;
33+
}
34+
35+
public function get_url() {
36+
return $this->url;
37+
}
38+
39+
public function set_url($url) {
40+
$this->url = $url;
41+
return $this;
42+
}
43+
44+
public function get_custom() {
45+
return $this->custom;
46+
}
47+
48+
public function set_custom($value) {
49+
$this->custom = $value;
50+
return $this;
51+
}
52+
53+
public function __toString() {
54+
return json_encode(array_filter([
55+
"reviewableStatus" => $this->reviewable_status,
56+
"label" => $this->label,
57+
"url" => $this->url,
58+
"custom" => $this->custom,
59+
]));
60+
}
61+
}
62+
?>

src/lti/LTI_Message_Launch.php

+29
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,26 @@ public function get_nrps() {
108108
$this->jwt['body']['https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice']);
109109
}
110110

111+
/**
112+
* Returns whether or not the current launch can use the groups service.
113+
*
114+
* @return boolean Returns a boolean indicating the availability of groups.
115+
*/
116+
public function has_gs() {
117+
return !empty($this->jwt['body']['https://purl.imsglobal.org/spec/lti-gs/claim/groupsservice']['context_groups_url']);
118+
}
119+
120+
/**
121+
* Fetches an instance of the groups service for the current launch.
122+
*
123+
* @return LTI_Course_Groups_Service An instance of the groups service that can be used to make calls within the scope of the current launch.
124+
*/
125+
public function get_gs() {
126+
return new LTI_Course_Groups_Service(
127+
new LTI_Service_Connector($this->registration),
128+
$this->jwt['body']['https://purl.imsglobal.org/spec/lti-gs/claim/groupsservice']);
129+
}
130+
111131
/**
112132
* Returns whether or not the current launch can use the assignments and grades service.
113133
*
@@ -149,6 +169,15 @@ public function is_deep_link_launch() {
149169
return $this->jwt['body']['https://purl.imsglobal.org/spec/lti/claim/message_type'] === 'LtiDeepLinkingRequest';
150170
}
151171

172+
/**
173+
* Returns whether or not the current launch is a submission review launch.
174+
*
175+
* @return boolean Returns true if the current launch is a submission review launch.
176+
*/
177+
public function is_submission_review_launch() {
178+
return $this->jwt['body']['https://purl.imsglobal.org/spec/lti/claim/message_type'] === 'LtiSubmissionReviewRequest';
179+
}
180+
152181
/**
153182
* Returns whether or not the current launch is a resource launch.
154183
*

src/lti/LTI_Names_Roles_Provisioning_Service.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function get_members() {
3131

3232
$next_page = false;
3333
foreach($page['headers'] as $header) {
34-
if (preg_match("/^Link:.*<([^>]*)>; ?rel=\"next\"/i", $header, $matches)) {
34+
if (preg_match(LTI_Service_Connector::NEXT_PAGE_REGEX, $header, $matches)) {
3535
$next_page = $matches[1];
3636
break;
3737
}

src/lti/LTI_Service_Connector.php

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
use Firebase\JWT\JWT;
55

66
class LTI_Service_Connector {
7+
8+
const NEXT_PAGE_REGEX = "/^Link:.*<([^>]*)>; ?rel=\"next\"/i";
9+
710
private $registration;
811
private $access_tokens = [];
912

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
namespace IMSGlobal\LTI;
3+
4+
class Submission_Review_Message_Validator implements Message_Validator {
5+
public function can_validate($jwt_body) {
6+
return $jwt_body['https://purl.imsglobal.org/spec/lti/claim/message_type'] === 'LtiSubmissionReviewRequest';
7+
}
8+
9+
public function validate($jwt_body) {
10+
if (empty($jwt_body['sub'])) {
11+
throw new LTI_Exception('Must have a user (sub)');
12+
}
13+
if ($jwt_body['https://purl.imsglobal.org/spec/lti/claim/version'] !== '1.3.0') {
14+
throw new LTI_Exception('Incorrect version, expected 1.3.0');
15+
}
16+
if (!isset($jwt_body['https://purl.imsglobal.org/spec/lti/claim/roles'])) {
17+
throw new LTI_Exception('Missing Roles Claim');
18+
}
19+
if (empty($jwt_body['https://purl.imsglobal.org/spec/lti/claim/resource_link']['id'])) {
20+
throw new LTI_Exception('Missing Resource Link Id');
21+
}
22+
if (empty($jwt_body['https://purl.imsglobal.org/spec/lti/claim/for_user'])) {
23+
throw new LTI_Exception('Missing For User');
24+
}
25+
26+
return true;
27+
}
28+
}
29+
?>

0 commit comments

Comments
 (0)