mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge pull request #11582 from appwrite/fix-webhooks-duplication
Fix: webhook endpoints duplication
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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']);
|
||||
|
||||
Reference in New Issue
Block a user