diff --git a/api.http b/api.http index 6b225a1d..ed304544 100644 --- a/api.http +++ b/api.http @@ -10,3 +10,19 @@ GET https://ep-reisen.ddev.site/api/hotel &key=abcabc123 ### + +### GET chatbot content manifest (cmsApiKey in extension configuration) +GET https://ep-reisen.ddev.site/api/content/manifest +X-Api-Key: abcabc123 + +### GET chatbot content records (type: product, hotel, region, country, city, concept, news; at most 100 uids) +GET https://ep-reisen.ddev.site/api/content/records + ?type=product + &uids=1,2,3 +X-Api-Key: abcabc123 + +### GET the content-only render of one page (use a contentUrl from the manifest) +GET https://ep-reisen.ddev.site/skireisen/infos/skiurlaub-infos/schneepchen/liegestuhl?type=1730 +X-Api-Key: abcabc123 + +### diff --git a/public/typo3conf/ext/ep_products/Classes/ContentFeed/ContentFeedApi.php b/public/typo3conf/ext/ep_products/Classes/ContentFeed/ContentFeedApi.php index cef76c89..230fd829 100644 --- a/public/typo3conf/ext/ep_products/Classes/ContentFeed/ContentFeedApi.php +++ b/public/typo3conf/ext/ep_products/Classes/ContentFeed/ContentFeedApi.php @@ -26,6 +26,8 @@ class ContentFeedApi private const MAX_RECORDS_PER_REQUEST = 100; + private const DISABLED_RETRY_AFTER = 3600; + private const JSON_FLAGS = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES; /** @@ -73,6 +75,10 @@ class ContentFeedApi return $this->error('Invalid or missing api key', 403); } + if (!$this->configuration->isEnabled()) { + return self::disabledResponse(); + } + if ([] === $this->configuration->getSites()) { // An empty feed would read as "everything was deleted". Refuse instead. return $this->error('Content feed has no sites configured', 503); @@ -137,6 +143,21 @@ class ContentFeedApi return $manifest; } + /** + * The kill switch: contentFeedEnabled = 0 in the extension configuration, for when the host + * is struggling. The consumer stops its run, keeps everything it has and tries again later - + * nothing is deleted on the chatbot side. + */ + public static function disabledResponse(): ResponseInterface + { + return new JsonResponse( + ['message' => 'Content feed is switched off'], + 503, + ['Retry-After' => (string) self::DISABLED_RETRY_AFTER], + self::JSON_FLAGS + ); + } + private function error(string $message, int $status): ResponseInterface { return new JsonResponse(['message' => $message], $status, [], self::JSON_FLAGS); diff --git a/public/typo3conf/ext/ep_products/Classes/Middleware/ContentPageTypeGuardMiddleware.php b/public/typo3conf/ext/ep_products/Classes/Middleware/ContentPageTypeGuardMiddleware.php index 44e07895..4f3409ac 100644 --- a/public/typo3conf/ext/ep_products/Classes/Middleware/ContentPageTypeGuardMiddleware.php +++ b/public/typo3conf/ext/ep_products/Classes/Middleware/ContentPageTypeGuardMiddleware.php @@ -2,6 +2,8 @@ namespace EP\EpProducts\Middleware; +use EP\EpProducts\ContentFeed\ContentFeedApi; +use EP\EpProducts\ContentFeed\ContentFeedConfiguration; use EP\EpProducts\ContentFeed\ManifestBuilder; use EP\EpProducts\Http\ApiKeyAuthenticator; use Psr\Http\Message\ResponseInterface; @@ -27,9 +29,15 @@ class ContentPageTypeGuardMiddleware implements MiddlewareInterface */ private $authenticator; - public function __construct(ApiKeyAuthenticator $authenticator) + /** + * @var ContentFeedConfiguration + */ + private $configuration; + + public function __construct(ApiKeyAuthenticator $authenticator, ContentFeedConfiguration $configuration) { $this->authenticator = $authenticator; + $this->configuration = $configuration; } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface @@ -48,6 +56,10 @@ class ContentPageTypeGuardMiddleware implements MiddlewareInterface ->pageNotFoundAction($request, 'The requested page does not exist'); } + if (!$this->configuration->isEnabled()) { + return ContentFeedApi::disabledResponse(); + } + return $handler->handle($request); } }