. // }}} namespace Plugin\WebHooks; use App\Core\DB\DB; use App\Core\Event; use App\Core\HTTPClient; use App\Core\Log; use App\Core\Modules\Plugin; use App\Core\Queue\Queue; use App\Core\Router\RouteLoader; use App\Entity\Activity; use App\Entity\Actor; use App\Util\Exception\ServerException; use Functional as F; use Plugin\WebHooks\Controller as C; use Plugin\WebHooks\Entity as E; use Symfony\Component\HttpFoundation\Request; class WebHooks extends Plugin { public const controller_route = 'webhook'; public function onAddRoute(RouteLoader $r) { $r->connect(self::controller_route, '/webhook-settings', C\WebHooks::class); } public function onPopulateSettingsTabs(Request $request, string $section, array &$tabs): bool { if ($section === 'others') { $tabs[] = [ 'title' => 'Web Hooks', 'desc' => 'Add hooks that run when an internal event occurs, allowing your third party resource to react', 'id' => 'settings-webhooks', 'controller' => C\WebHooks::setup(), ]; } return Event::next; } public function onNewNotificationEnd(Actor $sender, Activity $activity, array $effective_targets, ?string $reason) { foreach ($effective_targets as $actor) { $target = DB::findOneBy(E\WebHook::class, ['actor_id' => $actor->getId(), 'event' => 'notifications'], return_null: true)?->getTarget(); if (!\is_null($target)) { Queue::enqueue(['notifications', $target, $actor, [$sender, $activity, $effective_targets, $reason]], queue: 'webhook'); } } return Event::next; } /** * @param array $args */ public function onQueueWebhook(string $type, string $target, Actor $actor, array $args) { switch ($type) { case 'notifications': [$sender, $activity, $targets, $reason] = $args; $data = [ 'type' => 'notification', 'actor' => ['id' => $sender->getId(), 'nickname' => $sender->getNickname()], 'activity' => ['id' => $activity->getId(), 'object_type' => $activity->getObjectType(), 'object_id' => $activity->getObjectId(), 'verb' => $activity->getVerb()], 'targets' => F\map(array_values($targets), fn (Actor $actor) => ['id' => $actor->getId(), 'nickname' => $actor->getNickname()]), 'reason' => $reason, ]; Log::debug("WebHook: POST {$target} on behalf of actor {$actor->getId()} ({$actor->getNickname()})", [$data, ['json' => json_encode($data)]]); HTTPClient::post($target, ['json' => json_encode($data)]); return Event::stop; default: throw new ServerException("Webhook notification handler for event {$type} not implemented"); } } }