appwrite/src/Appwrite/Advisor/Validator/CTAs.php

84 lines
2.6 KiB
PHP
Raw Normal View History

<?php
namespace Appwrite\Advisor\Validator;
use Utopia\Validator;
class CTAs extends Validator
{
refactor(insights): metadata-only CTAs, platform DB, reports parent Address review feedback on PR #12194: - Pivot CTAs to pure descriptors (id/label/action/params). Drop the server-side execution layer: Action interface, registry, the databases.indexes.create CTA action, the params validator, the /v1/insights/:id/ctas/:id/executions endpoint, the InsightCTAExecution model, the INSIGHT_CTA_* errors, and the corresponding events. The console invokes the existing public API directly with the descriptor's action + params. - Restore Databases\Indexes\Action.php to its pre-CTA shape and inline the index-create body back into Create.php (the createIndex helper was added solely for CTA reuse). - Move insights collection from project DB to platform DB and add a parent reports collection alongside it. Insights carry projectId / projectInternalId for tenant scoping and an optional reportId for grouping. List endpoints filter by projectInternalId; Get/Update/ Delete also enforce project ownership before touching the document. - New Reports module with full CRUD (Create/Get/XList/Update/Delete), Report response model, Reports query validator, REPORT_NOT_FOUND / REPORT_ALREADY_EXISTS errors, reports.read / reports.write scopes, and reports.* event tree. Delete cascades to child insights. - Update.php now mutates the loaded document via setAttribute (instead of passing a partial new Document), reuses CTAsValidator (instead of the looser ArrayList<JSON> + isset check), and rejects duplicate CTA ids. - Create.php enforces unique CTA ids during normalization. - CTAsValidator gained a configurable maxCount (default 16) so the Create path matches the Update path and the DB column size, and oversized payloads return a clean 400. - Validator\Queries\Insights adds status and reportId to ALLOWED_ATTRIBUTES so dismissal / report workflows are filterable. - Realtime channel parser guards $parts[1] for both insights and reports event names. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 01:46:07 +00:00
public const MAX_COUNT_DEFAULT = 16;
protected string $message = 'Value must be an array of CTA descriptors. Each entry must define `label`, `service`, `method`, and an optional `params` object.';
protected array $allowedServices;
protected array $allowedMethods;
public function __construct(
protected int $maxCount = self::MAX_COUNT_DEFAULT,
?array $allowedServices = null,
?array $allowedMethods = null,
) {
$this->allowedServices = $allowedServices ?? ADVISOR_CTA_SERVICES;
$this->allowedMethods = $allowedMethods ?? ADVISOR_CTA_METHODS;
refactor(insights): metadata-only CTAs, platform DB, reports parent Address review feedback on PR #12194: - Pivot CTAs to pure descriptors (id/label/action/params). Drop the server-side execution layer: Action interface, registry, the databases.indexes.create CTA action, the params validator, the /v1/insights/:id/ctas/:id/executions endpoint, the InsightCTAExecution model, the INSIGHT_CTA_* errors, and the corresponding events. The console invokes the existing public API directly with the descriptor's action + params. - Restore Databases\Indexes\Action.php to its pre-CTA shape and inline the index-create body back into Create.php (the createIndex helper was added solely for CTA reuse). - Move insights collection from project DB to platform DB and add a parent reports collection alongside it. Insights carry projectId / projectInternalId for tenant scoping and an optional reportId for grouping. List endpoints filter by projectInternalId; Get/Update/ Delete also enforce project ownership before touching the document. - New Reports module with full CRUD (Create/Get/XList/Update/Delete), Report response model, Reports query validator, REPORT_NOT_FOUND / REPORT_ALREADY_EXISTS errors, reports.read / reports.write scopes, and reports.* event tree. Delete cascades to child insights. - Update.php now mutates the loaded document via setAttribute (instead of passing a partial new Document), reuses CTAsValidator (instead of the looser ArrayList<JSON> + isset check), and rejects duplicate CTA ids. - Create.php enforces unique CTA ids during normalization. - CTAsValidator gained a configurable maxCount (default 16) so the Create path matches the Update path and the DB column size, and oversized payloads return a clean 400. - Validator\Queries\Insights adds status and reportId to ALLOWED_ATTRIBUTES so dismissal / report workflows are filterable. - Realtime channel parser guards $parts[1] for both insights and reports event names. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 01:46:07 +00:00
}
public function getDescription(): string
{
return $this->message;
}
public function isArray(): bool
{
return true;
}
public function getType(): string
{
return self::TYPE_ARRAY;
}
public function isValid($value): bool
{
if (!\is_array($value)) {
return false;
}
refactor(insights): metadata-only CTAs, platform DB, reports parent Address review feedback on PR #12194: - Pivot CTAs to pure descriptors (id/label/action/params). Drop the server-side execution layer: Action interface, registry, the databases.indexes.create CTA action, the params validator, the /v1/insights/:id/ctas/:id/executions endpoint, the InsightCTAExecution model, the INSIGHT_CTA_* errors, and the corresponding events. The console invokes the existing public API directly with the descriptor's action + params. - Restore Databases\Indexes\Action.php to its pre-CTA shape and inline the index-create body back into Create.php (the createIndex helper was added solely for CTA reuse). - Move insights collection from project DB to platform DB and add a parent reports collection alongside it. Insights carry projectId / projectInternalId for tenant scoping and an optional reportId for grouping. List endpoints filter by projectInternalId; Get/Update/ Delete also enforce project ownership before touching the document. - New Reports module with full CRUD (Create/Get/XList/Update/Delete), Report response model, Reports query validator, REPORT_NOT_FOUND / REPORT_ALREADY_EXISTS errors, reports.read / reports.write scopes, and reports.* event tree. Delete cascades to child insights. - Update.php now mutates the loaded document via setAttribute (instead of passing a partial new Document), reuses CTAsValidator (instead of the looser ArrayList<JSON> + isset check), and rejects duplicate CTA ids. - Create.php enforces unique CTA ids during normalization. - CTAsValidator gained a configurable maxCount (default 16) so the Create path matches the Update path and the DB column size, and oversized payloads return a clean 400. - Validator\Queries\Insights adds status and reportId to ALLOWED_ATTRIBUTES so dismissal / report workflows are filterable. - Realtime channel parser guards $parts[1] for both insights and reports event names. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 01:46:07 +00:00
if (\count($value) > $this->maxCount) {
$this->message = "A maximum of {$this->maxCount} CTAs are allowed per insight.";
return false;
}
foreach ($value as $entry) {
if (!\is_array($entry)) {
return false;
}
$maxLengths = ['label' => 256, 'service' => 64, 'method' => 64];
foreach ($maxLengths as $required => $maxLength) {
if (!isset($entry[$required]) || !\is_string($entry[$required]) || $entry[$required] === '') {
return false;
}
if (\strlen($entry[$required]) > $maxLength) {
$this->message = "CTA `{$required}` must not exceed {$maxLength} characters.";
return false;
}
}
if (!empty($this->allowedServices) && !\in_array($entry['service'], $this->allowedServices, true)) {
$this->message = "CTA `service` must be one of: " . \implode(', ', $this->allowedServices) . '.';
return false;
}
if (!empty($this->allowedMethods) && !\in_array($entry['method'], $this->allowedMethods, true)) {
$this->message = "CTA `method` must be one of: " . \implode(', ', $this->allowedMethods) . '.';
return false;
}
if (isset($entry['params']) && !\is_array($entry['params']) && !\is_object($entry['params'])) {
return false;
}
}
return true;
}
}