Merge pull request #11582 from appwrite/fix-webhooks-duplication

Fix: webhook endpoints duplication
This commit is contained in:
Matej Bačo
2026-03-19 14:16:30 +01:00
committed by GitHub
16 changed files with 112 additions and 358 deletions
-310
View File
@@ -4,7 +4,6 @@ use Ahc\Jwt\JWT;
use Appwrite\Auth\Validator\MockNumber;
use Appwrite\Event\Delete;
use Appwrite\Event\Mail;
use Appwrite\Event\Validator\Event;
use Appwrite\Extend\Exception;
use Appwrite\Network\Platform;
use Appwrite\Network\Validator\Email;
@@ -30,7 +29,6 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\UID;
use Utopia\Domains\Validator\PublicDomain;
use Utopia\Http\Http;
use Utopia\Locale\Locale;
use Utopia\System\System;
@@ -38,11 +36,9 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Hostname;
use Utopia\Validator\Integer;
use Utopia\Validator\Multiple;
use Utopia\Validator\Nullable;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
use Utopia\Validator\URL;
use Utopia\Validator\WhiteList;
Http::init()
@@ -773,312 +769,6 @@ Http::delete('/v1/projects/:projectId')
$response->noContent();
});
// Webhooks
Http::post('/v1/projects/:projectId/webhooks')
->desc('Create webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'webhooks',
name: 'createWebhook',
description: '/docs/references/projects/create-webhook.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_CREATED,
model: Response::MODEL_WEBHOOK,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
->param('enabled', true, new Boolean(true), 'Enable or disable a webhook.', true)
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
->param('url', '', fn ($request) => new Multiple([new URL(['http', 'https']), new PublicDomain()], Multiple::TYPE_STRING), 'Webhook URL.', false, ['request'])
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true)
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, string $name, bool $enabled, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$security = (bool) filter_var($security, FILTER_VALIDATE_BOOLEAN);
$webhook = new Document([
'$id' => ID::unique(),
'$permissions' => [
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getSequence(),
'projectId' => $project->getId(),
'name' => $name,
'events' => $events,
'url' => $url,
'security' => $security,
'httpUser' => $httpUser,
'httpPass' => $httpPass,
'signatureKey' => \bin2hex(\random_bytes(64)),
'enabled' => $enabled,
]);
$webhook = $dbForPlatform->createDocument('webhooks', $webhook);
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($webhook, Response::MODEL_WEBHOOK);
});
Http::get('/v1/projects/:projectId/webhooks')
->desc('List webhooks')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk', new Method(
namespace: 'projects',
group: 'webhooks',
name: 'listWebhooks',
description: '/docs/references/projects/list-webhooks.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_WEBHOOK_LIST,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, bool $includeTotal, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$webhooks = $dbForPlatform->find('webhooks', [
Query::equal('projectInternalId', [$project->getSequence()]),
Query::limit(5000),
]);
$response->dynamic(new Document([
'webhooks' => $webhooks,
'total' => $includeTotal ? count($webhooks) : 0,
]), Response::MODEL_WEBHOOK_LIST);
});
Http::get('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Get webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk', new Method(
namespace: 'projects',
group: 'webhooks',
name: 'getWebhook',
description: '/docs/references/projects/get-webhook.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_WEBHOOK,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('webhookId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForPlatform'])
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
}
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
});
Http::put('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Update webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'webhooks',
name: 'updateWebhook',
description: '/docs/references/projects/update-webhook.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_WEBHOOK,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('webhookId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForPlatform'])
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
->param('enabled', true, new Boolean(true), 'Enable or disable a webhook.', true)
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
->param('url', '', fn ($request) => new Multiple([new URL(['http', 'https']), new PublicDomain()], Multiple::TYPE_STRING), 'Webhook URL.', false, ['request'])
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true)
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, string $webhookId, string $name, bool $enabled, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
}
$webhook
->setAttribute('name', $name)
->setAttribute('events', $events)
->setAttribute('url', $url)
->setAttribute('security', $security)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
->setAttribute('enabled', $enabled);
if ($enabled) {
$webhook->setAttribute('attempts', 0);
}
$dbForPlatform->updateDocument('webhooks', $webhook->getId(), $webhook);
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
});
Http::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
->desc('Update webhook signature key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'webhooks',
name: 'updateWebhookSignature',
description: '/docs/references/projects/update-webhook-signature.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_WEBHOOK,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('webhookId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForPlatform'])
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
}
$webhook->setAttribute('signatureKey', \bin2hex(\random_bytes(64)));
$dbForPlatform->updateDocument('webhooks', $webhook->getId(), $webhook);
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
});
Http::delete('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Delete webhook')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'webhooks',
name: 'deleteWebhook',
description: '/docs/references/projects/delete-webhook.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_NOCONTENT,
model: Response::MODEL_NONE,
)
],
contentType: ContentType::NONE
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('webhookId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForPlatform'])
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
}
$dbForPlatform->deleteDocument('webhooks', $webhook->getId());
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
$response->noContent();
});
// Keys
Http::post('/v1/projects/:projectId/keys')
+1 -1
View File
@@ -888,7 +888,7 @@ Http::init()
$dbForProject = $getProjectDB($project);
$request->addFilter(new RequestV20($dbForProject, $route->getPathValues($request)));
}
if (version_compare($requestFormat, '1.9.0', '<')) {
if (version_compare($requestFormat, '1.8.2', '<')) {
$request->addFilter(new RequestV21());
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ const APP_RESOURCE_TOKEN_ACCESS = 24 * 60 * 60; // 24 hours
const APP_FILE_ACCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 4321;
const APP_VERSION_STABLE = '1.8.1';
const APP_VERSION_STABLE = '1.8.2';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
+26 -7
View File
@@ -478,7 +478,7 @@ Http::setResource('user', function (string $mode, Document $project, Document $c
return $user;
}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForPlatform', 'store', 'proofForToken', 'authorization']);
Http::setResource('project', function ($dbForPlatform, $request, $console, $authorization) {
Http::setResource('project', function ($dbForPlatform, $request, $console, $authorization, Http $utopia) {
/** @var Appwrite\Utopia\Request $request */
/** @var Utopia\Database\Database $dbForPlatform */
/** @var Utopia\Database\Document $console */
@@ -488,6 +488,20 @@ Http::setResource('project', function ($dbForPlatform, $request, $console, $auth
$projectId = $request->getHeader('x-appwrite-project', '');
}
// Backwards compatibility for new services, originally project resources
// These endpoints moved from /v1/projects/:projectId/<resource> to /v1/<resource>
// When accessed via the old alias path, extract projectId from the URI
$deprecatedProjectPathPrefix = '/v1/projects/';
$route = $utopia->match($request);
if (!empty($route)) {
$isDeprecatedAlias = \str_starts_with($request->getURI(), $deprecatedProjectPathPrefix) &&
!\str_starts_with($route->getPath(), $deprecatedProjectPathPrefix);
if ($isDeprecatedAlias) {
$projectId = \explode('/', $request->getURI(), 5)[3] ?? '';
}
}
if (empty($projectId) || $projectId === 'console') {
return $console;
}
@@ -495,7 +509,7 @@ Http::setResource('project', function ($dbForPlatform, $request, $console, $auth
$project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
return $project;
}, ['dbForPlatform', 'request', 'console', 'authorization']);
}, ['dbForPlatform', 'request', 'console', 'authorization', 'utopia']);
Http::setResource('session', function (User $user, Store $store, Token $proofForToken) {
if ($user->isEmpty()) {
@@ -1236,16 +1250,21 @@ function getDevice(string $root, string $connection = ''): Device
}
}
Http::setResource('mode', function ($request) {
/** @var Appwrite\Utopia\Request $request */
Http::setResource('mode', function (Request $request, Document $project) {
/**
* Defines the mode for the request:
* - 'default' => Requests for Client and Server Side
* - 'admin' => Request from the Console on non-console projects
*/
return $request->getParam('mode', $request->getHeader('x-appwrite-mode', APP_MODE_DEFAULT));
}, ['request']);
$mode = $request->getParam('mode', $request->getHeader('x-appwrite-mode', APP_MODE_DEFAULT));
$projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', ''));
if (!empty($projectId) && $project->getId() !== $projectId) {
$mode = APP_MODE_ADMIN;
}
return $mode;
}, ['request', 'project']);
Http::setResource('geodb', function ($register) {
/** @var Utopia\Registry\Registry $register */
+1
View File
@@ -91,6 +91,7 @@ abstract class Migration
'1.7.4' => 'V22',
'1.8.0' => 'V23',
'1.8.1' => 'V23',
'1.8.2' => 'V23',
];
/**
@@ -39,6 +39,7 @@ class Create extends Base
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/webhooks')
->httpAlias('/v1/projects/:projectId/webhooks')
->desc('Create webhook')
->groups(['api', 'webhooks'])
->label('scope', 'webhooks.write')
@@ -32,6 +32,7 @@ class Delete extends Base
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_DELETE)
->setHttpPath('/v1/webhooks/:webhookId')
->httpAlias('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Delete webhook')
->groups(['api', 'webhooks'])
->label('scope', 'webhooks.write')
@@ -30,6 +30,7 @@ class Get extends Base
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/webhooks/:webhookId')
->httpAlias('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Get webhook')
->groups(['api', 'webhooks'])
->label('scope', 'webhooks.read')
@@ -30,6 +30,7 @@ class Update extends Base
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/webhooks/:webhookId/signature')
->httpAlias('/v1/projects/:projectId/webhooks/:webhookId/signature')
->desc('Update webhook signature key')
->groups(['api', 'webhooks'])
->label('scope', 'webhooks.write')
@@ -37,6 +37,7 @@ class Update extends Base
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT)
->setHttpPath('/v1/webhooks/:webhookId')
->httpAlias('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Update webhook')
->groups(['api', 'webhooks'])
->label('scope', 'webhooks.write')
@@ -34,6 +34,7 @@ class XList extends Base
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/webhooks')
->httpAlias('/v1/projects/:projectId/webhooks')
->desc('List webhooks')
->groups(['api', 'webhooks'])
->label('scope', 'webhooks.read')
+10 -1
View File
@@ -6,10 +6,13 @@ use Appwrite\Utopia\Request\Filter;
class V21 extends Filter
{
// Convert 1.8.0 params to 1.9.0
// Convert 1.8.0 params to 1.8.2
public function parse(array $content, string $model): array
{
switch ($model) {
case 'webhooks.create':
$content = $this->fillWebhookid($content);
break;
case 'functions.createTemplateDeployment':
case 'sites.createTemplateDeployment':
$content = $this->convertVersionToTypeAndReference($content);
@@ -48,4 +51,10 @@ class V21 extends Filter
return $content;
}
protected function fillWebhookid(array $content): array
{
$content['webhookId'] = $content['webhookId'] ?? 'unique()';
return $content;
}
}
+4 -2
View File
@@ -193,12 +193,14 @@ trait ProjectCustom
$this->assertNotEmpty($devKey['body']);
$this->assertNotEmpty($devKey['body']['secret']);
$webhook = $this->client->call(Client::METHOD_POST, '/projects/' . $project['body']['$id'] . '/webhooks', [
$webhook = $this->client->call(Client::METHOD_POST, '/webhooks', [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => 'console',
'x-appwrite-project' => $project['body']['$id'],
'x-appwrite-mode' => 'admin'
], [
'webhookId' => 'unique()',
'name' => 'Webhook Test',
'events' => [
'databases.*',
@@ -1711,6 +1711,7 @@ trait WebhooksBase
'content-type' => 'application/json',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => 'console',
'X-Appwrite-Response-Format' => '1.8.0'
], [
'name' => 'Webhook Test',
'enabled' => true,
@@ -1740,6 +1741,7 @@ trait WebhooksBase
'content-type' => 'application/json',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => 'console',
'X-Appwrite-Response-Format' => '1.8.0'
], [
'name' => 'Webhook Test',
'enabled' => true,
@@ -1779,6 +1781,7 @@ trait WebhooksBase
'content-type' => 'application/json',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => 'console',
'X-Appwrite-Response-Format' => '1.8.0'
], [
'name' => 'Webhook Test',
'enabled' => true,
@@ -1824,6 +1827,7 @@ trait WebhooksBase
'content-type' => 'application/json',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => 'console',
'X-Appwrite-Response-Format' => '1.8.0'
]));
// assert that the webhook is now disabled after 10 consecutive failures
+4 -2
View File
@@ -81,10 +81,12 @@ trait ProjectsBase
$projectData = $this->setupProjectData();
$id = $projectData['projectId'];
$response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
$response = $this->client->call(Client::METHOD_POST, '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin',
], $this->getHeaders()), [
'webhookId' => 'unique()',
'name' => 'Webhook Test',
'events' => ['users.*.create', 'users.*.update.email'],
'url' => 'https://appwrite.io',
@@ -2850,10 +2850,12 @@ class ProjectsConsoleClientTest extends Scope
$data = $this->setupProjectData();
$id = $data['projectId'];
$response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
$response = $this->client->call(Client::METHOD_POST, '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'webhookId' => 'unique()',
'name' => 'Webhook Test',
'events' => ['users.*.create', 'users.*.update.email'],
'url' => 'https://appwrite.io',
@@ -2875,10 +2877,12 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
$response = $this->client->call(Client::METHOD_POST, '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'webhookId' => 'unique()',
'name' => 'Webhook Test',
'events' => ['account.unknown', 'users.*.update.email'],
'url' => 'https://appwrite.io',
@@ -2889,10 +2893,12 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
$response = $this->client->call(Client::METHOD_POST, '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'webhookId' => 'unique()',
'name' => 'Webhook Test',
'events' => ['users.*.create', 'users.*.update.email'],
'url' => 'invalid://appwrite.io',
@@ -2906,9 +2912,10 @@ class ProjectsConsoleClientTest extends Scope
$data = $this->setupProjectWithWebhook();
$id = $data['projectId'];
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
@@ -2926,9 +2933,10 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'];
$webhookId = $data['webhookId'];
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_GET, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
@@ -2944,9 +2952,10 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/error', array_merge([
$response = $this->client->call(Client::METHOD_GET, '/webhooks/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(404, $response['headers']['status-code']);
@@ -2958,9 +2967,10 @@ class ProjectsConsoleClientTest extends Scope
$id = $data['projectId'];
$webhookId = $data['webhookId'];
$response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_PUT, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
@@ -2982,9 +2992,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals('', $response['body']['httpUser']);
$this->assertEquals('', $response['body']['httpPass']);
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_GET, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
@@ -3004,9 +3015,10 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_PUT, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.unknown'],
@@ -3016,9 +3028,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_PUT, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
@@ -3028,9 +3041,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_PUT, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_PUT, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'name' => 'Webhook Test Update',
'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
@@ -3047,9 +3061,10 @@ class ProjectsConsoleClientTest extends Scope
$webhookId = $data['webhookId'];
$signatureKey = $data['signatureKey'];
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/webhooks/' . $webhookId . '/signature', array_merge([
$response = $this->client->call(Client::METHOD_PATCH, '/webhooks/' . $webhookId . '/signature', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
@@ -3064,10 +3079,12 @@ class ProjectsConsoleClientTest extends Scope
$id = $projectData['projectId'];
// Create a webhook to delete
$response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/webhooks', array_merge([
$response = $this->client->call(Client::METHOD_POST, '/webhooks', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'webhookId' => 'unique()',
'name' => 'Webhook To Delete',
'events' => ['users.*.create'],
'url' => 'https://appwrite.io',
@@ -3079,17 +3096,19 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(201, $response['headers']['status-code']);
$webhookId = $response['body']['$id'];
$response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_DELETE, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([
$response = $this->client->call(Client::METHOD_GET, '/webhooks/' . $webhookId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(404, $response['headers']['status-code']);
@@ -3097,9 +3116,10 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([
$response = $this->client->call(Client::METHOD_DELETE, '/webhooks/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(404, $response['headers']['status-code']);
@@ -4457,9 +4477,10 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $id . '/webhooks/error', array_merge([
$response = $this->client->call(Client::METHOD_DELETE, '/webhooks/error', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $id,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), []);
$this->assertEquals(404, $response['headers']['status-code']);