diff --git a/src/Appwrite/Platform/Modules/Insights/Http/Cta/Trigger.php b/src/Appwrite/Platform/Modules/Insights/Http/Cta/Trigger.php new file mode 100644 index 0000000000..160eb2eae2 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Insights/Http/Cta/Trigger.php @@ -0,0 +1,130 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/insights/:insightId/ctas/:ctaId/trigger') + ->desc('Trigger insight CTA') + ->groups(['api', 'insights']) + ->label('scope', 'insights.write') + ->label('event', 'insights.[insightId].ctas.[ctaId].trigger') + ->label('resourceType', RESOURCE_TYPE_INSIGHTS) + ->label('audits.event', 'insight.cta.trigger') + ->label('audits.resource', 'insight/{request.insightId}') + ->label('abuse-key', 'projectId:{projectId},userId:{userId}') + ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT) + ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) + ->label('sdk', new Method( + namespace: 'insights', + group: 'insights', + name: 'triggerCta', + description: <<param('insightId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Insight ID.', false, ['dbForProject']) + ->param('ctaId', '', new Text(64), 'CTA ID, unique within the parent insight.') + ->inject('response') + ->inject('project') + ->inject('dbForProject') + ->inject('insightCtaRegistry') + ->inject('queueForEvents') + ->callback($this->action(...)); + } + + public function action( + string $insightId, + string $ctaId, + Response $response, + Document $project, + Database $dbForProject, + InsightCtaRegistry $insightCtaRegistry, + Event $queueForEvents + ) { + $insight = $dbForProject->getDocument('insights', $insightId); + + if ($insight->isEmpty()) { + throw new Exception(Exception::INSIGHT_NOT_FOUND); + } + + $cta = null; + foreach ($insight->getAttribute('ctas', []) as $candidate) { + if (($candidate['id'] ?? null) === $ctaId) { + $cta = $candidate; + break; + } + } + + if ($cta === null) { + throw new Exception(Exception::INSIGHT_CTA_NOT_FOUND); + } + + $actionName = (string) ($cta['action'] ?? ''); + $params = $cta['params'] ?? []; + if (!\is_array($params)) { + $params = []; + } + + $action = $insightCtaRegistry->get($actionName); + $action->validate($params); + + $status = 'succeeded'; + $resultPayload = new \stdClass(); + + try { + $result = $action->execute($params, $insight, $project, $dbForProject); + $resultPayload = $result->getArrayCopy(); + } catch (Exception $e) { + if ($e->getType() === Exception::GENERAL_NOT_IMPLEMENTED) { + throw $e; + } + $status = 'failed'; + $resultPayload = ['error' => $e->getMessage()]; + } + + $queueForEvents + ->setParam('insightId', $insight->getId()) + ->setParam('ctaId', $ctaId); + + $response->dynamic(new Document([ + 'insightId' => $insight->getId(), + 'ctaId' => $ctaId, + 'action' => $actionName, + 'status' => $status, + 'result' => $resultPayload, + ]), Response::MODEL_INSIGHT_CTA_RESULT); + } +} diff --git a/src/Appwrite/Platform/Modules/Insights/Http/Insights/Dismiss.php b/src/Appwrite/Platform/Modules/Insights/Http/Insights/Dismiss.php new file mode 100644 index 0000000000..ab2ef38682 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Insights/Http/Insights/Dismiss.php @@ -0,0 +1,87 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/insights/:insightId/dismiss') + ->desc('Dismiss insight') + ->groups(['api', 'insights']) + ->label('scope', 'insights.write') + ->label('event', 'insights.[insightId].dismiss') + ->label('resourceType', RESOURCE_TYPE_INSIGHTS) + ->label('audits.event', 'insight.dismiss') + ->label('audits.resource', 'insight/{response.$id}') + ->label('abuse-key', 'projectId:{projectId},userId:{userId}') + ->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT) + ->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT) + ->label('sdk', new Method( + namespace: 'insights', + group: 'insights', + name: 'dismiss', + description: <<param('insightId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Insight ID.', false, ['dbForProject']) + ->inject('response') + ->inject('user') + ->inject('dbForProject') + ->inject('queueForEvents') + ->callback($this->action(...)); + } + + public function action( + string $insightId, + Response $response, + Document $user, + Database $dbForProject, + Event $queueForEvents + ) { + $insight = $dbForProject->getDocument('insights', $insightId); + + if ($insight->isEmpty()) { + throw new Exception(Exception::INSIGHT_NOT_FOUND); + } + + $insight = $dbForProject->updateDocument('insights', $insight->getId(), new Document([ + 'dismissedAt' => DateTime::now(), + 'dismissedBy' => $user->getId(), + ])); + + $queueForEvents->setParam('insightId', $insight->getId()); + + $response->dynamic($insight, Response::MODEL_INSIGHT); + } +}