Skip to content

Commit e098715

Browse files
committed
feat: AJDA-2680 add listSubscriptions() and deleteSubscription() to SubscriptionClient
Add two missing methods to the upstream SubscriptionClient so consumers no longer need to subclass the client to reach these endpoints.
1 parent 1039c14 commit e098715

3 files changed

Lines changed: 176 additions & 0 deletions

File tree

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,34 @@ $clientFactory = new ClientFactory('https://connection.keboola.com');
4545
$clientFactory->getEventsClient('xxx-xxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
4646
```
4747

48+
### Subscription client
49+
50+
```php
51+
use Keboola\NotificationClient\ClientFactory;
52+
use Keboola\NotificationClient\Requests\PostSubscription\EmailRecipient;
53+
use Keboola\NotificationClient\Requests\PostSubscription\Filter;
54+
use Keboola\NotificationClient\Requests\Subscription;
55+
56+
$clientFactory = new ClientFactory('https://connection.keboola.com');
57+
$subscriptionClient = $clientFactory->getSubscriptionClient('xxx-storage-api-token');
58+
59+
// create a subscription
60+
$created = $subscriptionClient->createSubscription(new Subscription(
61+
'job-failed',
62+
new EmailRecipient('you@example.com'),
63+
[new Filter('project.id', '123')],
64+
));
65+
66+
// list all subscriptions for the project (returned by token)
67+
$subscriptions = $subscriptionClient->listSubscriptions();
68+
foreach ($subscriptions as $subscription) {
69+
echo $subscription->getId() . ': ' . $subscription->getEvent() . "\n";
70+
}
71+
72+
// delete a subscription
73+
$subscriptionClient->deleteSubscription($created->getId());
74+
```
75+
4876
## Development
4977
- Create an Azure service principal to download the required images and login:
5078

src/SubscriptionClient.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,30 @@ public function createSubscription(RequestSubscription $requestData): ResponseSu
4141
}
4242
return new ResponseSubscription($this->sendRequest($request));
4343
}
44+
45+
public function deleteSubscription(string $id): void
46+
{
47+
$request = new Request(
48+
'DELETE',
49+
'project-subscriptions/' . rawurlencode($id),
50+
);
51+
$this->sendRequest($request);
52+
}
53+
54+
/**
55+
* @return array<ResponseSubscription>
56+
*/
57+
public function listSubscriptions(): array
58+
{
59+
$request = new Request(
60+
'GET',
61+
'project-subscriptions',
62+
);
63+
$response = $this->sendRequest($request);
64+
65+
return array_values(array_map(
66+
fn(array $item): ResponseSubscription => new ResponseSubscription($item),
67+
$response,
68+
));
69+
}
4470
}

tests/SubscriptionClientFunctionalTest.php

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,126 @@ public function testCreateSubscriptionHeaders(): void
117117
);
118118
self::assertSame(['application/json'], $request->getHeaders()['Content-type']);
119119
}
120+
121+
public function testDeleteSubscriptionHeaders(): void
122+
{
123+
$mock = new MockHandler([
124+
new Response(204, [], ''),
125+
]);
126+
$requestHistory = [];
127+
$history = Middleware::history($requestHistory);
128+
$stack = HandlerStack::create($mock);
129+
$stack->push($history);
130+
$client = new SubscriptionClient(
131+
'https://example.com/',
132+
'testToken',
133+
['handler' => $stack, 'backoffMaxTries' => 3, 'userAgent' => 'Test'],
134+
);
135+
136+
$client->deleteSubscription('subscription-123');
137+
138+
/** @var Request $request */
139+
$request = $requestHistory[0]['request'];
140+
self::assertSame('DELETE', $request->getMethod());
141+
self::assertSame('project-subscriptions/subscription-123', (string) $request->getUri());
142+
self::assertSame(
143+
['User-Agent', 'X-StorageApi-Token', 'Host'],
144+
array_keys($request->getHeaders()),
145+
);
146+
}
147+
148+
public function testListSubscriptionsHeaders(): void
149+
{
150+
$responseBody = json_encode([
151+
[
152+
'id' => 'sub-1',
153+
'event' => 'job-failed',
154+
'filters' => [
155+
['field' => 'project.id', 'value' => '123'],
156+
],
157+
'recipient' => ['channel' => 'email', 'address' => 'a@example.com'],
158+
],
159+
[
160+
'id' => 'sub-2',
161+
'event' => 'job-succeeded',
162+
'filters' => [],
163+
'recipient' => ['channel' => 'email', 'address' => 'b@example.com'],
164+
],
165+
]);
166+
167+
$mock = new MockHandler([
168+
new Response(200, ['Content-Type' => 'application/json'], (string) $responseBody),
169+
]);
170+
$requestHistory = [];
171+
$history = Middleware::history($requestHistory);
172+
$stack = HandlerStack::create($mock);
173+
$stack->push($history);
174+
$client = new SubscriptionClient(
175+
'https://example.com/',
176+
'testToken',
177+
['handler' => $stack, 'backoffMaxTries' => 3, 'userAgent' => 'Test'],
178+
);
179+
180+
$result = $client->listSubscriptions();
181+
182+
/** @var Request $request */
183+
$request = $requestHistory[0]['request'];
184+
self::assertSame('GET', $request->getMethod());
185+
self::assertSame('project-subscriptions', (string) $request->getUri());
186+
self::assertSame(
187+
['User-Agent', 'X-StorageApi-Token', 'Host'],
188+
array_keys($request->getHeaders()),
189+
);
190+
191+
self::assertCount(2, $result);
192+
self::assertContainsOnlyInstancesOf(
193+
\Keboola\NotificationClient\Responses\Subscription::class,
194+
$result,
195+
);
196+
self::assertSame('sub-1', $result[0]->getId());
197+
self::assertSame('job-failed', $result[0]->getEvent());
198+
self::assertSame('project.id', $result[0]->getFilters()[0]->getField());
199+
self::assertSame('123', $result[0]->getFilters()[0]->getValue());
200+
self::assertSame('email', $result[0]->getRecipientChannel());
201+
self::assertSame('a@example.com', $result[0]->getRecipientAddress());
202+
self::assertSame('sub-2', $result[1]->getId());
203+
}
204+
205+
public function testListAndDeleteSubscriptionLifecycle(): void
206+
{
207+
$client = $this->getClient();
208+
209+
// create
210+
$created = $client->createSubscription(new Subscription(
211+
'job-failed',
212+
new EmailRecipient('ajda-2680@example.com'),
213+
[
214+
new Filter('project.id', (string) getenv('TEST_STORAGE_API_PROJECT_ID')),
215+
],
216+
));
217+
self::assertNotEmpty($created->getId());
218+
219+
// list — must contain the new subscription
220+
$beforeDelete = $client->listSubscriptions();
221+
self::assertContainsOnlyInstancesOf(
222+
\Keboola\NotificationClient\Responses\Subscription::class,
223+
$beforeDelete,
224+
);
225+
$ids = array_map(
226+
fn(\Keboola\NotificationClient\Responses\Subscription $s): string => $s->getId(),
227+
$beforeDelete,
228+
);
229+
self::assertContains($created->getId(), $ids);
230+
231+
// delete
232+
$client->deleteSubscription($created->getId());
233+
234+
// list — must no longer contain it
235+
$afterDelete = $client->listSubscriptions();
236+
$idsAfter = array_map(
237+
fn(\Keboola\NotificationClient\Responses\Subscription $s): string => $s->getId(),
238+
$afterDelete,
239+
);
240+
self::assertNotContains($created->getId(), $idsAfter);
241+
}
120242
}

0 commit comments

Comments
 (0)