Skip to content

Commit b13ebf5

Browse files
authored
Merge pull request #142 from danielmaier42/hotfix/executeActionsEmail
Fix executeActionsEmail via explicit ContentType declaration
2 parents ab02f04 + f8cd4fe commit b13ebf5

File tree

10 files changed

+82
-20
lines changed

10 files changed

+82
-20
lines changed

src/Http/Command.php

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public function __construct(
2020
/** @var Representation|Collection|array<mixed>|null */
2121
private readonly Representation|Collection|array|null $payload = null,
2222
private readonly ?Criteria $criteria = null,
23+
private readonly ContentType $contentType = ContentType::JSON,
2324
) {}
2425

2526
public function getMethod(): Method
@@ -61,4 +62,9 @@ public function getQuery(): string
6162

6263
return '?' . http_build_query($this->criteria->jsonSerialize());
6364
}
65+
66+
public function getContentType(): ContentType
67+
{
68+
return $this->contentType;
69+
}
6470
}

src/Http/CommandExecutor.php

+9-18
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,20 @@ public function __construct(
2020

2121
public function executeCommand(Command $command): void
2222
{
23-
$payload = $command->getPayload();
24-
25-
if (is_array($payload)) {
26-
$this->client->request(
27-
$command->getMethod()->value,
28-
$command->getPath(),
29-
[
30-
'form_params' => $payload,
23+
$options = match ($command->getContentType()) {
24+
ContentType::JSON => [
25+
'body' => $this->serializer->serialize($command->getPayload()),
26+
'headers' => [
27+
'Content-Type' => $command->getContentType()->value,
3128
],
32-
);
33-
34-
return;
35-
}
29+
],
30+
ContentType::FORM_PARAMS => ['form_params' => $command->getPayload()],
31+
};
3632

3733
$this->client->request(
3834
$command->getMethod()->value,
3935
$command->getPath(),
40-
[
41-
'body' => $this->serializer->serialize($command->getPayload()),
42-
'headers' => [
43-
'Content-Type' => 'application/json',
44-
],
45-
],
36+
$options,
4637
);
4738
}
4839
}

src/Http/ContentType.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Fschmtt\Keycloak\Http;
6+
7+
/**
8+
* @internal
9+
*/
10+
enum ContentType: string
11+
{
12+
case JSON = 'application/json';
13+
case FORM_PARAMS = 'application/x-www-form-urlencoded';
14+
}

src/Resource/Organizations.php

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Fschmtt\Keycloak\Collection\OrganizationCollection;
88
use Fschmtt\Keycloak\Http\Command;
9+
use Fschmtt\Keycloak\Http\ContentType;
910
use Fschmtt\Keycloak\Http\Criteria;
1011
use Fschmtt\Keycloak\Http\Method;
1112
use Fschmtt\Keycloak\Http\Query;
@@ -71,6 +72,7 @@ public function inviteUser(string $realm, string $id, string $email, string $fir
7172
'firstName' => $firstName,
7273
'lastName' => $lastName,
7374
],
75+
contentType: ContentType::FORM_PARAMS,
7476
),
7577
);
7678
}

src/Resource/Users.php

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Fschmtt\Keycloak\Collection\RoleCollection;
1010
use Fschmtt\Keycloak\Collection\UserCollection;
1111
use Fschmtt\Keycloak\Http\Command;
12+
use Fschmtt\Keycloak\Http\ContentType;
1213
use Fschmtt\Keycloak\Http\Criteria;
1314
use Fschmtt\Keycloak\Http\Method;
1415
use Fschmtt\Keycloak\Http\Query;

tests/Integration/Resource/UsersTest.php

+28
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Fschmtt\Keycloak\Representation\Role;
1414
use Fschmtt\Keycloak\Representation\User;
1515
use Fschmtt\Keycloak\Test\Integration\IntegrationTestBehaviour;
16+
use GuzzleHttp\Exception\ServerException;
1617
use PHPUnit\Framework\TestCase;
1718
use Ramsey\Uuid\Uuid;
1819

@@ -189,6 +190,33 @@ public function testGetUserCredentials(): void
189190
static::assertNull($user);
190191
}
191192

193+
public function testExecuteActionsEmail(): void
194+
{
195+
$users = $this->getKeycloak()->users();
196+
$username = Uuid::uuid4()->toString();
197+
198+
$users->create('master', new User(
199+
200+
enabled: true,
201+
username: $username,
202+
));
203+
204+
$user = $this->searchUserByUsername($username);
205+
static::assertInstanceOf(User::class, $user);
206+
207+
try {
208+
$users->executeActionsEmail('master', $user->getId(), ['UPDATE_PASSWORD']);
209+
} catch (ServerException $e) {
210+
static::assertSame(500, $e->getResponse()->getStatusCode());
211+
static::assertStringContainsString('Failed to send execute actions email', $e->getResponse()->getBody()->getContents());
212+
}
213+
214+
$users->delete('master', $user->getId());
215+
216+
$user = $this->searchUserByUsername($username);
217+
static::assertNull($user);
218+
}
219+
192220
private function searchUserByUsername(string $username, string $realm = 'master'): ?User
193221
{
194222
/** @var User|null $user */

tests/Unit/Http/CommandExecutorTest.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Fschmtt\Keycloak\Http\Client;
88
use Fschmtt\Keycloak\Http\Command;
99
use Fschmtt\Keycloak\Http\CommandExecutor;
10+
use Fschmtt\Keycloak\Http\ContentType;
1011
use Fschmtt\Keycloak\Http\Method;
1112
use Fschmtt\Keycloak\Json\JsonEncoder;
1213
use Fschmtt\Keycloak\Serializer\Serializer;
@@ -43,7 +44,7 @@ public function testCallsClientWithoutBodyIfCommandHasNoRepresentation(): void
4344
);
4445
}
4546

46-
public function testCallsClientWithBodyIfCommandHasRepresentation(): void
47+
public function testCallsClientWithJsonIfCommandHasRepresentation(): void
4748
{
4849
$command = new Command(
4950
'/path/to/resource',
@@ -101,13 +102,14 @@ public function testCallsClientWithBodyIfCommandHasCollection(): void
101102
$executor->executeCommand($command);
102103
}
103104

104-
public function testCallsClientWithFormParamsIfCommandHasArrayPayload(): void
105+
public function testCallsClientWithFormParamsIfCommandFormParamContentType(): void
105106
{
106107
$command = new Command(
107108
'/path/to/resource',
108109
Method::PUT,
109110
[],
110111
$payload = ['UPDATE_PASSWORD', 'VERIFY_EMAIL'],
112+
contentType: ContentType::FORM_PARAMS,
111113
);
112114

113115
$client = $this->createMock(Client::class);

tests/Unit/Http/CommandTest.php

+15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Fschmtt\Keycloak\Test\Unit\Http;
66

77
use Fschmtt\Keycloak\Http\Command;
8+
use Fschmtt\Keycloak\Http\ContentType;
89
use Fschmtt\Keycloak\Http\Criteria;
910
use Fschmtt\Keycloak\Http\Method;
1011
use Fschmtt\Keycloak\Test\Unit\Stub\Collection;
@@ -84,4 +85,18 @@ public function testBuildsPathWithQueryIfCriteriaIsProvided(): void
8485
))->getPath(),
8586
);
8687
}
88+
89+
public function testContentTypeDefaultsToJson(): void
90+
{
91+
$command = new Command('/path', Method::GET);
92+
93+
static::assertSame(ContentType::JSON, $command->getContentType());
94+
}
95+
96+
public function testContentTypeCanBeSetToFormParams(): void
97+
{
98+
$command = new Command('/path', Method::GET, contentType: ContentType::FORM_PARAMS);
99+
100+
static::assertSame(ContentType::FORM_PARAMS, $command->getContentType());
101+
}
87102
}

tests/Unit/Resource/OrganizationsTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Fschmtt\Keycloak\Collection\OrganizationCollection;
88
use Fschmtt\Keycloak\Http\Command;
99
use Fschmtt\Keycloak\Http\CommandExecutor;
10+
use Fschmtt\Keycloak\Http\ContentType;
1011
use Fschmtt\Keycloak\Http\Method;
1112
use Fschmtt\Keycloak\Http\Query;
1213
use Fschmtt\Keycloak\Http\QueryExecutor;
@@ -148,6 +149,7 @@ public function testInviteUser(): void
148149
'firstName' => 'first name',
149150
'lastName' => 'last name',
150151
],
152+
contentType: ContentType::FORM_PARAMS,
151153
);
152154

153155
$commandExecutor = $this->createMock(CommandExecutor::class);

tests/Unit/Resource/UsersTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Fschmtt\Keycloak\Collection\UserCollection;
1111
use Fschmtt\Keycloak\Http\Command;
1212
use Fschmtt\Keycloak\Http\CommandExecutor;
13+
use Fschmtt\Keycloak\Http\ContentType;
1314
use Fschmtt\Keycloak\Http\Criteria;
1415
use Fschmtt\Keycloak\Http\Method;
1516
use Fschmtt\Keycloak\Http\Query;

0 commit comments

Comments
 (0)