Skip to content

Commit d46d357

Browse files
committed
Merge remote-tracking branch 'packback/master' into patch-2
2 parents a80095e + 731813c commit d46d357

14 files changed

Lines changed: 173 additions & 82 deletions

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 5.1.7
2+
3+
Add `AssignmentGradesService::updateLineitem()` to update a line item [#58](https://github.com/packbackbooks/lti-1-3-php-library/pull/58).
4+
5+
## 5.1.0
6+
7+
Add `AssignmentGradesService::getLineItem()` to fetch a single line item [#47](https://github.com/packbackbooks/lti-1-3-php-library/pull/47).
8+
19
## 5.0.0
210

311
Implemented several changes to comply with (OpenID Connect Core)[https://openid.net/specs/openid-connect-core-1_0.html]. Nonce validation changed such that it now verifies that the nonce and state associated with an LTI Message Launch request matches the state associated with the nonce and state created during the OIDC login request.

PULL_REQUEST_TEMPLATE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@
77
<!-- Describe how this PR has been tested, manually and automatically. -->
88

99
- [ ] I have added automated tests for my changes
10+
- [ ] I ran `composer test` before opening this PR
11+
- [ ] I ran `composer lint-fix` before opening this PR

src/Interfaces/ILtiServiceConnector.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@ public function makeServiceRequest(
1616
ILtiRegistration $registration,
1717
array $scopes,
1818
IServiceRequest $request,
19-
?int $requestType = null,
2019
bool $shouldRetry = true
2120
): array;
2221

2322
public function getAll(
2423
ILtiRegistration $registration,
2524
array $scopes,
2625
IServiceRequest $request,
27-
string $key,
28-
?int $requestType = null
26+
string $key
2927
): array;
3028

3129
public function setDebuggingMode(bool $enable): void;

src/Interfaces/IServiceRequest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ public function setBody(string $body): self;
1919
public function setAccept(string $accept): self;
2020

2121
public function setContentType(string $contentType): self;
22+
23+
public function getErrorPrefix(): string;
2224
}

src/LtiAbstractService.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,22 @@ public function setServiceData(array $serviceData): self
3636

3737
abstract public function getScope(): array;
3838

39-
protected function makeServiceRequest(IServiceRequest $request, ?int $requestType = null): array
39+
protected function makeServiceRequest(IServiceRequest $request): array
4040
{
4141
return $this->serviceConnector->makeServiceRequest(
4242
$this->registration,
4343
$this->getScope(),
4444
$request,
45-
$requestType
4645
);
4746
}
4847

49-
protected function getAll(IServiceRequest $request, string $key = null, ?int $requestType = null): array
48+
protected function getAll(IServiceRequest $request, string $key = null): array
5049
{
5150
return $this->serviceConnector->getAll(
5251
$this->registration,
5352
$this->getScope(),
5453
$request,
55-
$key,
56-
$requestType
54+
$key
5755
);
5856
}
5957
}

src/LtiAssignmentsGradesService.php

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,15 @@ public function putGrade(LtiGrade $grade, LtiLineitem $lineitem = null)
4242
$pos = strpos($scoreUrl, '?');
4343
$scoreUrl = $pos === false ? $scoreUrl.'/scores' : substr_replace($scoreUrl, '/scores', $pos, 0);
4444

45-
$request = new ServiceRequest(LtiServiceConnector::METHOD_POST, $scoreUrl);
45+
$request = new ServiceRequest(
46+
ServiceRequest::METHOD_POST,
47+
$scoreUrl,
48+
ServiceRequest::TYPE_SYNC_GRADE
49+
);
4650
$request->setBody($grade);
4751
$request->setContentType(static::CONTENTTYPE_SCORE);
4852

49-
return $this->makeServiceRequest($request, LtiServiceConnector::SYNC_GRADE_REQUEST);
53+
return $this->makeServiceRequest($request);
5054
}
5155

5256
public function findLineItem(LtiLineitem $newLineItem): ?LtiLineitem
@@ -62,13 +66,34 @@ public function findLineItem(LtiLineitem $newLineItem): ?LtiLineitem
6266
return null;
6367
}
6468

69+
public function updateLineitem(LtiLineItem $lineitemToUpdate): LtiLineitem
70+
{
71+
$request = new ServiceRequest(
72+
ServiceRequest::METHOD_PUT,
73+
$this->getServiceData()['lineitems'],
74+
ServiceRequest::TYPE_UPDATE_LINEITEM
75+
);
76+
77+
$request->setBody($lineitemToUpdate)
78+
->setContentType(static::CONTENTTYPE_LINEITEM)
79+
->setAccept(static::CONTENTTYPE_LINEITEM);
80+
81+
$updatedLineitem = $this->makeServiceRequest($request);
82+
83+
return new LtiLineitem($updatedLineitem['body']);
84+
}
85+
6586
public function createLineitem(LtiLineitem $newLineItem): LtiLineitem
6687
{
67-
$request = new ServiceRequest(LtiServiceConnector::METHOD_POST, $this->getServiceData()['lineitems']);
88+
$request = new ServiceRequest(
89+
ServiceRequest::METHOD_POST,
90+
$this->getServiceData()['lineitems'],
91+
ServiceRequest::TYPE_CREATE_LINEITEM
92+
);
6893
$request->setBody($newLineItem)
6994
->setContentType(static::CONTENTTYPE_LINEITEM)
7095
->setAccept(static::CONTENTTYPE_LINEITEM);
71-
$createdLineItem = $this->makeServiceRequest($request, LtiServiceConnector::CREATE_LINEITEM_REQUEST);
96+
$createdLineItem = $this->makeServiceRequest($request);
7297

7398
return new LtiLineitem($createdLineItem['body']);
7499
}
@@ -87,7 +112,11 @@ public function getGrades(LtiLineitem $lineitem = null)
87112
$pos = strpos($resultsUrl, '?');
88113
$resultsUrl = $pos === false ? $resultsUrl.'/results' : substr_replace($resultsUrl, '/results', $pos, 0);
89114

90-
$request = new ServiceRequest(LtiServiceConnector::METHOD_GET, $resultsUrl);
115+
$request = new ServiceRequest(
116+
ServiceRequest::METHOD_GET,
117+
$resultsUrl,
118+
ServiceRequest::TYPE_GET_GRADES
119+
);
91120
$request->setAccept(static::CONTENTTYPE_RESULTCONTAINER);
92121
$scores = $this->makeServiceRequest($request);
93122

@@ -101,12 +130,13 @@ public function getLineItems(): array
101130
}
102131

103132
$request = new ServiceRequest(
104-
LtiServiceConnector::METHOD_GET,
105-
$this->getServiceData()['lineitems']
133+
ServiceRequest::METHOD_GET,
134+
$this->getServiceData()['lineitems'],
135+
ServiceRequest::TYPE_GET_LINEITEMS
106136
);
107137
$request->setAccept(static::CONTENTTYPE_LINEITEMCONTAINER);
108138

109-
$lineitems = $this->getAll($request, null, LtiServiceConnector::GET_LINEITEMS_REQUEST);
139+
$lineitems = $this->getAll($request);
110140

111141
// If there is only one item, then wrap it in an array so the foreach works
112142
if (isset($lineitems['body']['id'])) {
@@ -122,7 +152,11 @@ public function getLineItem(string $url): LtiLineitem
122152
throw new LtiException('Missing required scope', 1);
123153
}
124154

125-
$request = new ServiceRequest(LtiServiceConnector::METHOD_GET, $url);
155+
$request = new ServiceRequest(
156+
ServiceRequest::METHOD_GET,
157+
$url,
158+
ServiceRequest::TYPE_GET_LINEITEM
159+
);
126160
$request->setAccept(static::CONTENTTYPE_LINEITEM);
127161

128162
$response = $this->makeServiceRequest($request)['body'];

src/LtiCourseGroupsService.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ public function getScope(): array
1414
public function getGroups(): array
1515
{
1616
$request = new ServiceRequest(
17-
LtiServiceConnector::METHOD_GET,
18-
$this->getServiceData()['context_groups_url']
17+
ServiceRequest::METHOD_GET,
18+
$this->getServiceData()['context_groups_url'],
19+
ServiceRequest::TYPE_GET_GROUPS
1920
);
2021
$request->setAccept(static::CONTENTTYPE_CONTEXTGROUPCONTAINER);
2122

@@ -30,8 +31,9 @@ public function getSets(): array
3031
}
3132

3233
$request = new ServiceRequest(
33-
LtiServiceConnector::METHOD_GET,
34-
$this->getServiceData()['context_group_sets_url']
34+
ServiceRequest::METHOD_GET,
35+
$this->getServiceData()['context_group_sets_url'],
36+
ServiceRequest::TYPE_GET_SETS
3537
);
3638
$request->setAccept(static::CONTENTTYPE_CONTEXTGROUPCONTAINER);
3739

src/LtiMessageLaunch.php

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@ class LtiMessageLaunch
2828
public const ERR_INVALID_ID_TOKEN = 'Invalid id_token, JWT must contain 3 parts';
2929
public const ERR_MISSING_NONCE = 'Missing Nonce.';
3030
public const ERR_INVALID_NONCE = 'Invalid Nonce.';
31-
public const ERR_MISSING_REGISTRATION = 'Registration not found. Please have your admin confirm your Issuer URL, client ID, and deployment ID.';
31+
32+
/**
33+
* :issuerUrl and :clientId are used to substitute the queried issuerUrl
34+
* and clientId. Do not change those substrings without changing how the
35+
* error message is built.
36+
*/
37+
public const ERR_MISSING_REGISTRATION = 'LTI 1.3 Registration not found for Issuer :issuerUrl and Client ID :clientId. Please make sure the LMS has provided the right information, and that the LMS has been registered correctly in the tool.';
38+
3239
public const ERR_CLIENT_NOT_REGISTERED = 'Client id not registered for this issuer.';
3340
public const ERR_NO_KID = 'No KID specified in the JWT Header.';
3441
public const ERR_INVALID_SIGNATURE = 'Invalid signature on id_token';
@@ -91,7 +98,7 @@ public static function new(
9198
ICache $cache = null,
9299
ICookie $cookie = null,
93100
ILtiServiceConnector $serviceConnector = null
94-
) {
101+
) {
95102
return new LtiMessageLaunch($database, $cache, $cookie, $serviceConnector);
96103
}
97104

@@ -276,10 +283,26 @@ public function getLaunchId()
276283
return $this->launch_id;
277284
}
278285

286+
public static function getMissingRegistrationErrorMsg(string $issuerUrl, ?string $clientId = null): string
287+
{
288+
// Guard against client ID being null
289+
if (!isset($clientId)) {
290+
$clientId = '(N/A)';
291+
}
292+
293+
$search = [':issuerUrl', ':clientId'];
294+
$replace = [$issuerUrl, $clientId];
295+
296+
return str_replace($search, $replace, static::ERR_MISSING_REGISTRATION);
297+
}
298+
279299
private function getPublicKey()
280300
{
281-
$keySetUrl = $this->registration->getKeySetUrl();
282-
$request = new ServiceRequest(LtiServiceConnector::METHOD_GET, $keySetUrl);
301+
$request = new ServiceRequest(
302+
ServiceRequest::METHOD_GET,
303+
$this->registration->getKeySetUrl(),
304+
ServiceRequest::TYPE_GET_KEYSET
305+
);
283306

284307
// Download key set
285308
try {
@@ -400,15 +423,16 @@ private function validateNonce()
400423
private function validateRegistration()
401424
{
402425
// Find registration.
403-
$client_id = is_array($this->jwt['body']['aud']) ? $this->jwt['body']['aud'][0] : $this->jwt['body']['aud'];
404-
$this->registration = $this->db->findRegistrationByIssuer($this->jwt['body']['iss'], $client_id);
426+
$clientId = is_array($this->jwt['body']['aud']) ? $this->jwt['body']['aud'][0] : $this->jwt['body']['aud'];
427+
$issuerUrl = $this->jwt['body']['iss'];
428+
$this->registration = $this->db->findRegistrationByIssuer($issuerUrl, $clientId);
405429

406430
if (empty($this->registration)) {
407-
throw new LtiException(static::ERR_MISSING_REGISTRATION);
431+
throw new LtiException($this->getMissingRegistrationErrorMsg($issuerUrl, $clientId));
408432
}
409433

410434
// Check client id.
411-
if ($client_id !== $this->registration->getClientId()) {
435+
if ($clientId !== $this->registration->getClientId()) {
412436
// Client not registered.
413437
throw new LtiException(static::ERR_CLIENT_NOT_REGISTERED);
414438
}

src/LtiNamesRolesProvisioningService.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ public function getScope(): array
1414
public function getMembers(): array
1515
{
1616
$request = new ServiceRequest(
17-
LtiServiceConnector::METHOD_GET,
18-
$this->getServiceData()['context_memberships_url']
17+
ServiceRequest::METHOD_GET,
18+
$this->getServiceData()['context_memberships_url'],
19+
ServiceRequest::TYPE_GET_MEMBERSHIPS
1920
);
2021
$request->setAccept(static::CONTENTTYPE_MEMBERSHIPCONTAINER);
2122

0 commit comments

Comments
 (0)