mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
feat(projects): add onboarding stages tracking and stages API
Add configurable onboarding stages keyed by SDK method, persist completion in project onboarding JSON on successful API responses, and expose listStages and updateStage routes with stages.read/write scopes and stage/stageList models. Made-with: Cursor
This commit is contained in:
@@ -342,6 +342,17 @@ $platformCollections = [
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('onboarding'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 65536,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => false,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
[
|
||||
'$id' => 'status',
|
||||
'type' => Database::VAR_STRING,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Project onboarding: each stage maps to an SDK method key (namespace + method name, same as Appwrite\SDK\Method).
|
||||
* The sdk index is built once for O(1) lookup in the API shutdown hook.
|
||||
*/
|
||||
$stages = [
|
||||
[
|
||||
'id' => 'create_database',
|
||||
'sdk' => 'databases.create',
|
||||
],
|
||||
[
|
||||
'id' => 'create_bucket',
|
||||
'sdk' => 'storage.createBucket',
|
||||
],
|
||||
[
|
||||
'id' => 'create_function',
|
||||
'sdk' => 'functions.create',
|
||||
],
|
||||
];
|
||||
|
||||
$sdkIndex = [];
|
||||
foreach ($stages as $stage) {
|
||||
$sdkIndex[$stage['sdk']] = $stage['id'];
|
||||
}
|
||||
|
||||
return [
|
||||
'stages' => $stages,
|
||||
'sdkIndex' => $sdkIndex,
|
||||
];
|
||||
@@ -95,6 +95,8 @@ $admins = [
|
||||
'tokens.write',
|
||||
'schedules.read',
|
||||
'schedules.write',
|
||||
'stages.read',
|
||||
'stages.write',
|
||||
];
|
||||
|
||||
return [
|
||||
|
||||
@@ -151,6 +151,12 @@ return [ // List of publicly visible scopes
|
||||
'schedules.write' => [
|
||||
'description' => 'Access to create, update, and delete your project\'s schedules',
|
||||
],
|
||||
'stages.read' => [
|
||||
'description' => 'Access to read your project\'s stages',
|
||||
],
|
||||
'stages.write' => [
|
||||
'description' => 'Access to update your project\'s stages',
|
||||
],
|
||||
'migrations.read' => [
|
||||
'description' => 'Access to read your project\'s migrations',
|
||||
],
|
||||
|
||||
@@ -800,16 +800,61 @@ Http::shutdown()
|
||||
->inject('queueForWebhooks')
|
||||
->inject('queueForRealtime')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->inject('authorization')
|
||||
->inject('timelimit')
|
||||
->inject('eventProcessor')
|
||||
->inject('bus')
|
||||
->inject('apiKey')
|
||||
->inject('mode')
|
||||
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, Audit $queueForAudits, Context $usage, UsagePublisher $publisherForUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization, callable $timelimit, EventProcessor $eventProcessor, Bus $bus, ?Key $apiKey, string $mode) use ($parseLabel) {
|
||||
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, Audit $queueForAudits, Context $usage, UsagePublisher $publisherForUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Database $dbForPlatform, Authorization $authorization, callable $timelimit, EventProcessor $eventProcessor, Bus $bus, ?Key $apiKey, string $mode) use ($parseLabel) {
|
||||
|
||||
$responsePayload = $response->getPayload();
|
||||
|
||||
/**
|
||||
* Persist completed stage when the route matches a configured SDK method (stored on project as `onboarding`: stageId → row).
|
||||
*/
|
||||
if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300 && $project->getId() !== 'console') {
|
||||
$sdkLabel = $utopia->getRoute()?->getLabel('sdk', false);
|
||||
$stageId = null;
|
||||
if ($sdkLabel !== false && $sdkLabel !== null) {
|
||||
$sdkIndex = Config::getParam('onboarding', [])['sdkIndex'] ?? [];
|
||||
foreach ($sdkLabel instanceof Method ? [$sdkLabel] : (\is_array($sdkLabel) ? $sdkLabel : []) as $sdkMethod) {
|
||||
if ($sdkMethod instanceof Method && isset($sdkIndex[$k = $sdkMethod->getNamespace() . '.' . $sdkMethod->getMethodName()])) {
|
||||
$stageId = $sdkIndex[$k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($stageId !== null) {
|
||||
$byStageId = $project->getAttribute('onboarding', []);
|
||||
if (! \is_array($byStageId)) {
|
||||
$byStageId = [];
|
||||
}
|
||||
$done = \is_array($byStageId[$stageId] ?? null) ? ($byStageId[$stageId]['status'] ?? '') : '';
|
||||
if ($done !== ONBOARDING_STATUS_COMPLETED && $done !== ONBOARDING_STATUS_SKIPPED) {
|
||||
$actorType = ($apiKey !== null && $apiKey->getRole() === User::ROLE_APPS)
|
||||
? match ($apiKey->getType()) {
|
||||
API_KEY_ACCOUNT => ACTIVITY_TYPE_KEY_ACCOUNT,
|
||||
API_KEY_ORGANIZATION => ACTIVITY_TYPE_KEY_ORGANIZATION,
|
||||
API_KEY_STANDARD, API_KEY_DYNAMIC => ACTIVITY_TYPE_KEY_PROJECT,
|
||||
default => ACTIVITY_TYPE_KEY_PROJECT,
|
||||
}
|
||||
: (! $user->isEmpty()
|
||||
? ($mode === APP_MODE_ADMIN ? ACTIVITY_TYPE_ADMIN : ACTIVITY_TYPE_USER)
|
||||
: ACTIVITY_TYPE_GUEST);
|
||||
$byStageId[$stageId] = [
|
||||
'status' => ONBOARDING_STATUS_COMPLETED,
|
||||
'at' => DateTime::now(),
|
||||
'actorType' => $actorType,
|
||||
];
|
||||
$authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), new Document([
|
||||
'onboarding' => $byStageId,
|
||||
])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($queueForEvents->getEvent())) {
|
||||
if (empty($queueForEvents->getPayload())) {
|
||||
$queueForEvents->setPayload($responsePayload);
|
||||
|
||||
@@ -26,6 +26,7 @@ Config::load('projectScopes', __DIR__ . '/../config/scopes/project.php', $config
|
||||
Config::load('organizationScopes', __DIR__ . '/../config/scopes/organization.php', $configAdapter);
|
||||
Config::load('accountScopes', __DIR__ . '/../config/scopes/account.php', $configAdapter);
|
||||
Config::load('services', __DIR__ . '/../config/services.php', $configAdapter); // List of services
|
||||
Config::load('onboarding', __DIR__ . '/../config/onboarding.php', $configAdapter); // Project onboarding stages → routes
|
||||
Config::load('variables', __DIR__ . '/../config/variables.php', $configAdapter); // List of env variables
|
||||
Config::load('regions', __DIR__ . '/../config/regions.php', $configAdapter); // List of available regions
|
||||
Config::load('avatar-browsers', __DIR__ . '/../config/avatars/browsers.php', $configAdapter);
|
||||
|
||||
@@ -163,6 +163,12 @@ const ACTIVITY_TYPE_KEY_PROJECT = 'keyProject';
|
||||
const ACTIVITY_TYPE_KEY_ACCOUNT = 'keyAccount';
|
||||
const ACTIVITY_TYPE_KEY_ORGANIZATION = 'keyOrganization';
|
||||
|
||||
/**
|
||||
* Project onboarding stage status (stored per stage id under project.onboarding JSON).
|
||||
*/
|
||||
const ONBOARDING_STATUS_COMPLETED = 'completed';
|
||||
const ONBOARDING_STATUS_SKIPPED = 'skipped';
|
||||
|
||||
/**
|
||||
* MFA
|
||||
*/
|
||||
|
||||
@@ -126,6 +126,7 @@ use Appwrite\Utopia\Response\Model\Schedule;
|
||||
use Appwrite\Utopia\Response\Model\Session;
|
||||
use Appwrite\Utopia\Response\Model\Site;
|
||||
use Appwrite\Utopia\Response\Model\Specification;
|
||||
use Appwrite\Utopia\Response\Model\Stage;
|
||||
use Appwrite\Utopia\Response\Model\Subscriber;
|
||||
use Appwrite\Utopia\Response\Model\Table;
|
||||
use Appwrite\Utopia\Response\Model\Target;
|
||||
@@ -212,6 +213,7 @@ Response::setModel(new BaseList('Variables List', Response::MODEL_VARIABLE_LIST,
|
||||
Response::setModel(new BaseList('Status List', Response::MODEL_HEALTH_STATUS_LIST, 'statuses', Response::MODEL_HEALTH_STATUS));
|
||||
Response::setModel(new BaseList('Rule List', Response::MODEL_PROXY_RULE_LIST, 'rules', Response::MODEL_PROXY_RULE));
|
||||
Response::setModel(new BaseList('Schedules List', Response::MODEL_SCHEDULE_LIST, 'schedules', Response::MODEL_SCHEDULE));
|
||||
Response::setModel(new BaseList('Stages List', Response::MODEL_STAGE_LIST, 'stages', Response::MODEL_STAGE, false, false));
|
||||
Response::setModel(new BaseList('Locale codes list', Response::MODEL_LOCALE_CODE_LIST, 'localeCodes', Response::MODEL_LOCALE_CODE));
|
||||
Response::setModel(new BaseList('Provider list', Response::MODEL_PROVIDER_LIST, 'providers', Response::MODEL_PROVIDER));
|
||||
Response::setModel(new BaseList('Message list', Response::MODEL_MESSAGE_LIST, 'messages', Response::MODEL_MESSAGE));
|
||||
@@ -373,6 +375,7 @@ Response::setModel(new Headers());
|
||||
Response::setModel(new Specification());
|
||||
Response::setModel(new Rule());
|
||||
Response::setModel(new Schedule());
|
||||
Response::setModel(new Stage());
|
||||
Response::setModel(new TemplateSMS());
|
||||
Response::setModel(new TemplateEmail());
|
||||
Response::setModel(new ConsoleVariables());
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Projects\Http\Stages;
|
||||
|
||||
use Appwrite\Auth\Key;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'updateStage';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
|
||||
->setHttpPath('/v1/projects/:projectId/stages/:stageId')
|
||||
->desc('Update stage')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'stages.write')
|
||||
->label('audits.event', 'stages.update')
|
||||
->label('audits.resource', 'project/{request.projectId}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'stages',
|
||||
name: 'updateStage',
|
||||
description: '/docs/references/projects/update-stage.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_STAGE,
|
||||
)
|
||||
],
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('stageId', '', new Text(64), 'Stage ID.')
|
||||
->param('skip', true, new Boolean(), 'Mark the stage as skipped.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('apiKey')
|
||||
->inject('user')
|
||||
->inject('mode')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $projectId, string $stageId, bool $skip, Response $response, Database $dbForPlatform, ?Key $apiKey, User $user, string $mode): void
|
||||
{
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$definition = $this->getStageDefinition($stageId);
|
||||
|
||||
$byStageId = $project->getAttribute('onboarding', []);
|
||||
if (! \is_array($byStageId)) {
|
||||
$byStageId = [];
|
||||
}
|
||||
|
||||
$row = \is_array($byStageId[$stageId] ?? null) ? $byStageId[$stageId] : null;
|
||||
|
||||
if ($skip) {
|
||||
$prev = \is_array($row) ? ($row['status'] ?? '') : '';
|
||||
if ($prev !== ONBOARDING_STATUS_COMPLETED) {
|
||||
$byStageId[$stageId] = [
|
||||
'status' => ONBOARDING_STATUS_SKIPPED,
|
||||
'at' => DateTime::now(),
|
||||
'actorType' => $this->resolveActorType($apiKey, $user, $mode),
|
||||
];
|
||||
$project = $dbForPlatform->updateDocument('projects', $project->getId(), $project->setAttribute('onboarding', $byStageId));
|
||||
$byStageId = $project->getAttribute('onboarding', []);
|
||||
$row = \is_array($byStageId[$stageId] ?? null) ? $byStageId[$stageId] : null;
|
||||
}
|
||||
}
|
||||
|
||||
$response->dynamic(new Document($this->formatStageRow($definition, $row)), Response::MODEL_STAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{id: string, sdk: string}
|
||||
*/
|
||||
private function getStageDefinition(string $stageId): array
|
||||
{
|
||||
foreach (Config::getParam('onboarding', [])['stages'] ?? [] as $definition) {
|
||||
if (($definition['id'] ?? '') === $stageId) {
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Unknown stage ID: ' . $stageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|null $row
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function formatStageRow(array $definition, ?array $row): array
|
||||
{
|
||||
$stageId = $definition['id'];
|
||||
$status = \is_array($row) ? ($row['status'] ?? null) : null;
|
||||
$at = \is_array($row) ? ($row['at'] ?? '') : '';
|
||||
$actorType = \is_array($row) ? ($row['actorType'] ?? '') : '';
|
||||
|
||||
return [
|
||||
'id' => $stageId,
|
||||
'sdk' => $definition['sdk'] ?? '',
|
||||
'status' => $status ?? 'pending',
|
||||
'at' => $at,
|
||||
'actorType' => $actorType,
|
||||
];
|
||||
}
|
||||
|
||||
private function resolveActorType(?Key $apiKey, User $user, string $mode): string
|
||||
{
|
||||
if ($apiKey !== null && $apiKey->getRole() === User::ROLE_APPS) {
|
||||
return match ($apiKey->getType()) {
|
||||
API_KEY_ACCOUNT => ACTIVITY_TYPE_KEY_ACCOUNT,
|
||||
API_KEY_ORGANIZATION => ACTIVITY_TYPE_KEY_ORGANIZATION,
|
||||
API_KEY_STANDARD, API_KEY_DYNAMIC => ACTIVITY_TYPE_KEY_PROJECT,
|
||||
default => ACTIVITY_TYPE_KEY_PROJECT,
|
||||
};
|
||||
}
|
||||
|
||||
if (! $user->isEmpty()) {
|
||||
return $mode === APP_MODE_ADMIN ? ACTIVITY_TYPE_ADMIN : ACTIVITY_TYPE_USER;
|
||||
}
|
||||
|
||||
return ACTIVITY_TYPE_GUEST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Projects\Http\Stages;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
|
||||
class XList extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'listStages';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath('/v1/projects/:projectId/stages')
|
||||
->desc('List stages')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'stages.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'stages',
|
||||
name: 'listStages',
|
||||
description: '/docs/references/projects/list-stages.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_STAGE_LIST,
|
||||
)
|
||||
],
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $projectId, Response $response, Database $dbForPlatform): void
|
||||
{
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'stages' => $this->buildStagesList($project),
|
||||
]), Response::MODEL_STAGE_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
private function buildStagesList(Document $project): array
|
||||
{
|
||||
$definitions = Config::getParam('onboarding', [])['stages'] ?? [];
|
||||
$byStageId = $project->getAttribute('onboarding', []);
|
||||
if (! \is_array($byStageId)) {
|
||||
$byStageId = [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($definitions as $definition) {
|
||||
$stageId = $definition['id'];
|
||||
$row = $byStageId[$stageId] ?? null;
|
||||
$status = \is_array($row) ? ($row['status'] ?? null) : null;
|
||||
|
||||
$at = \is_array($row) ? ($row['at'] ?? '') : '';
|
||||
$actorType = \is_array($row) ? ($row['actorType'] ?? '') : '';
|
||||
|
||||
$out[] = [
|
||||
'id' => $stageId,
|
||||
'sdk' => $definition['sdk'] ?? '',
|
||||
'status' => $status ?? 'pending',
|
||||
'at' => $at,
|
||||
'actorType' => $actorType,
|
||||
];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ use Appwrite\Platform\Modules\Projects\Http\Projects\XList as ListProjects;
|
||||
use Appwrite\Platform\Modules\Projects\Http\Schedules\Create as CreateSchedule;
|
||||
use Appwrite\Platform\Modules\Projects\Http\Schedules\Get as GetSchedule;
|
||||
use Appwrite\Platform\Modules\Projects\Http\Schedules\XList as ListSchedules;
|
||||
use Appwrite\Platform\Modules\Projects\Http\Stages\Update as UpdateStages;
|
||||
use Appwrite\Platform\Modules\Projects\Http\Stages\XList as ListStages;
|
||||
use Utopia\Platform\Service;
|
||||
|
||||
class Http extends Service
|
||||
@@ -35,5 +37,8 @@ class Http extends Service
|
||||
$this->addAction(CreateSchedule::getName(), new CreateSchedule());
|
||||
$this->addAction(GetSchedule::getName(), new GetSchedule());
|
||||
$this->addAction(ListSchedules::getName(), new ListSchedules());
|
||||
|
||||
$this->addAction(ListStages::getName(), new ListStages());
|
||||
$this->addAction(UpdateStages::getName(), new UpdateStages());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +247,8 @@ class Response extends SwooleResponse
|
||||
// Project
|
||||
public const MODEL_PROJECT = 'project';
|
||||
public const MODEL_PROJECT_LIST = 'projectList';
|
||||
public const MODEL_STAGE = 'stage';
|
||||
public const MODEL_STAGE_LIST = 'stageList';
|
||||
public const MODEL_WEBHOOK = 'webhook';
|
||||
public const MODEL_WEBHOOK_LIST = 'webhookList';
|
||||
public const MODEL_KEY = 'key';
|
||||
|
||||
@@ -308,6 +308,12 @@ class Project extends Model
|
||||
'default' => 'active',
|
||||
'example' => 'active',
|
||||
])
|
||||
->addRule('onboarding', [
|
||||
'type' => self::TYPE_JSON,
|
||||
'description' => 'Stage progress (completed or skipped) with timestamps and actor types, keyed by stage id.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
])
|
||||
;
|
||||
|
||||
$services = Config::getParam('services', []);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Stage extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Stage ID.',
|
||||
'default' => '',
|
||||
'example' => 'create_database',
|
||||
])
|
||||
->addRule('sdk', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'SDK method key (namespace.name) for this stage.',
|
||||
'default' => '',
|
||||
'example' => 'databases.create',
|
||||
])
|
||||
->addRule('status', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Stage status.',
|
||||
'default' => 'pending',
|
||||
'example' => 'completed',
|
||||
])
|
||||
->addRule('at', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'description' => 'When the stage was completed or skipped, in ISO 8601 format.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('actorType', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Actor type when the stage was recorded.',
|
||||
'default' => '',
|
||||
'example' => 'user',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Stage';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_STAGE;
|
||||
}
|
||||
|
||||
public function filter(Document $document): Document
|
||||
{
|
||||
return $document;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user