diff --git a/src/Appwrite/Platform/Modules/Webhooks/Http/Init.php b/src/Appwrite/Platform/Modules/Webhooks/Http/Init.php new file mode 100644 index 0000000000..3a14a12ffb --- /dev/null +++ b/src/Appwrite/Platform/Modules/Webhooks/Http/Init.php @@ -0,0 +1,32 @@ +setType(Action::TYPE_INIT) + ->groups(['webhooks']) + ->inject('project') + ->callback(function (Document $project) { + if ($project->getId() === 'console') { + throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN); + } + + if ($project->isEmpty()) { + throw new Exception(Exception::PROJECT_NOT_FOUND); + } + }); + } +} diff --git a/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/Create.php b/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/Create.php new file mode 100644 index 0000000000..c3d2260be4 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/Create.php @@ -0,0 +1,130 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/webhooks') + ->desc('Create webhook') + ->groups(['api', 'webhooks']) + ->label('scope', 'webhooks.write') + ->label('event', 'webhooks.[webhookId].create') + ->label('audits.event', 'webhook.create') + ->label('audits.resource', 'webhook/{response.$id}') + ->label('sdk', new Method( + namespace: 'webhooks', + group: null, + name: 'create', + description: <<param('webhokId', '', fn (Database $dbForPlatform) => new CustomId(false, $dbForPlatform->getAdapter()->getMaxUIDLength()), 'Webhook ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['$dbForPlatform']) + ->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.') + ->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('enabled', true, new Boolean(), 'Enable or disable a webhook.', true) + ->param('url', '', fn () => new Multiple([new URL(['http', 'https']), new PublicDomain()], Multiple::TYPE_STRING), 'Webhook URL.', false) + ->param('security', false, new Boolean(), 'Certificate verification, false for disabled or true for enabled.', true) + ->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('project') + ->inject('queueForEvents') + ->inject('dbForPlatform') + ->inject('authorization') + ->callback($this->action(...)); + } + + /** + * @param array $events + */ + public function action( + string $webhookId, + string $name, + array $events, + bool $enabled, + string $url, + bool $security, + string $httpUser, + string $httpPass, + Response $response, + Document $project, + QueueEvent $queueForEvents, + Database $dbForPlatform, + Authorization $authorization + ) { + $security = (bool) filter_var($security, FILTER_VALIDATE_BOOLEAN); + + $webhookId = ($webhookId == 'unique()') ? ID::unique() : $webhookId; + + $webhook = new Document([ + '$id' => $webhookId, + '$permissions' => [], + '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, + ]); + + try { + $webhook = $authorization->skip(fn () => $dbForPlatform->createDocument('webhooks', $webhook)); + } catch (DuplicateException) { + throw new Exception(Exception::SITE_ALREADY_EXISTS); + } + + $authorization->skip(fn () => $dbForPlatform->purgeCachedDocument('projects', $project->getId())); + + $queueForEvents->setParam('webhookId', $webhook->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($webhook, Response::MODEL_WEBHOOK); + } +} diff --git a/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/Get.php b/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/Get.php new file mode 100644 index 0000000000..3401f827aa --- /dev/null +++ b/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/Get.php @@ -0,0 +1,76 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/webhooks/:webhookId') + ->desc('Get webhook') + ->groups(['api', 'webhooks']) + ->label('scope', 'webhooks.read') + ->label('sdk', new Method( + namespace: 'webhooks', + group: null, + name: 'get', + description: <<param('webhookId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Webhook ID.', false, ['dbForPlatform']) + ->inject('project') + ->inject('response') + ->inject('dbForPlatform') + ->inject('authorization') + ->callback($this->action(...)); + } + + public function action( + string $webhookId, + Document $project, + Response $response, + Database $dbForPlatform, + Authorization $authorization + ) { + $webhook = $authorization->skip(fn () => $dbForPlatform->getDocument('webhooks', $webhookId, [ + Query::equal('projectInternalId', [$project->getSequence()]) + ])); + + if ($webhook->isEmpty()) { + throw new Exception(Exception::WEBHOOK_NOT_FOUND); + } + + $response->dynamic($webhook, Response::MODEL_WEBHOOK); + } +} diff --git a/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/XList.php b/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/XList.php index d12fee0789..7f753129f1 100644 --- a/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/XList.php +++ b/src/Appwrite/Platform/Modules/Webhooks/Http/Webhooks/XList.php @@ -61,12 +61,17 @@ class XList extends Base ->callback($this->action(...)); } - public function action(array $queries, bool $includeTotal, Document $project, Response $response, Database $dbForPlatform, Authorization $authorization) - { - if ($project->isEmpty()) { - throw new Exception(Exception::PROJECT_NOT_FOUND); - } - + /** + * @param array $queries + */ + public function action( + array $queries, + bool $includeTotal, + Document $project, + Response $response, + Database $dbForPlatform, + Authorization $authorization + ) { try { $queries = Query::parseQueries($queries); } catch (QueryException $e) { diff --git a/src/Appwrite/Platform/Modules/Webhooks/Services/Http.php b/src/Appwrite/Platform/Modules/Webhooks/Services/Http.php index 602ca02074..ab74104c1f 100644 --- a/src/Appwrite/Platform/Modules/Webhooks/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Webhooks/Services/Http.php @@ -2,6 +2,8 @@ namespace Appwrite\Platform\Modules\Webhooks\Services; +use Appwrite\Platform\Modules\Webhooks\Http\Init; +use Appwrite\Platform\Modules\Webhooks\Http\Webhooks\Get as GetWebhook; use Appwrite\Platform\Modules\Webhooks\Http\Webhooks\XList as ListWebhooks; use Utopia\Platform\Service; @@ -11,7 +13,11 @@ class Http extends Service { $this->type = Service::TYPE_HTTP; + // Hooks + $this->addAction(Init::getName(), new Init()); + // Webhooks $this->addAction(ListWebhooks::getName(), new ListWebhooks()); + $this->addAction(GetWebhook::getName(), new GetWebhook()); } }