1
0
Fork 0
mirror of synced 2024-05-19 12:12:36 +12:00
appwrite/app/controllers/api/projects.php

1511 lines
62 KiB
PHP
Raw Normal View History

2019-12-15 08:33:29 +13:00
<?php
use Appwrite\Auth\Auth;
2021-12-02 04:09:57 +13:00
use Appwrite\Auth\Validator\Password;
use Appwrite\Event\Certificate;
use Appwrite\Event\Delete;
2022-04-04 18:30:07 +12:00
use Appwrite\Event\Validator\Event;
2020-06-12 07:36:10 +12:00
use Appwrite\Network\Validator\CNAME;
use Appwrite\Network\Validator\Domain as DomainValidator;
use Appwrite\Network\Validator\Origin;
2021-06-07 17:17:29 +12:00
use Appwrite\Network\Validator\URL;
2022-01-19 00:05:04 +13:00
use Appwrite\Utopia\Database\Validator\CustomId;
2020-08-15 09:56:50 +12:00
use Appwrite\Utopia\Response;
2021-08-17 01:27:15 +12:00
use Utopia\Abuse\Adapters\TimeLimit;
2021-06-07 17:17:29 +12:00
use Utopia\App;
2021-08-17 01:27:15 +12:00
use Utopia\Audit\Audit;
2021-06-07 17:17:29 +12:00
use Utopia\Config\Config;
2021-08-17 01:27:15 +12:00
use Utopia\Database\Database;
2021-05-16 10:41:42 +12:00
use Utopia\Database\Document;
2022-08-14 22:33:36 +12:00
use Utopia\Database\ID;
use Utopia\Database\DateTime;
2022-08-14 17:21:11 +12:00
use Utopia\Database\Permission;
2021-05-27 22:09:14 +12:00
use Utopia\Database\Query;
2022-08-14 17:21:11 +12:00
use Utopia\Database\Role;
2021-08-17 01:27:15 +12:00
use Utopia\Database\Validator\Authorization;
2022-07-14 02:07:03 +12:00
use Utopia\Database\Validator\DatetimeValidator;
2021-05-16 10:41:42 +12:00
use Utopia\Database\Validator\UID;
2021-06-07 17:17:29 +12:00
use Utopia\Domains\Domain;
2022-05-07 04:51:02 +12:00
use Utopia\Registry\Registry;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Database\Validator\Queries\Projects;
2021-06-07 17:17:29 +12:00
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
2022-04-20 21:31:17 +12:00
use Utopia\Validator\Hostname;
2022-11-01 03:54:15 +13:00
use Utopia\Validator\Integer;
2021-06-07 17:17:29 +12:00
use Utopia\Validator\Range;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
2019-12-15 08:33:29 +13:00
2022-07-22 18:00:42 +12:00
App::init()
->groups(['projects'])
2022-08-02 13:10:48 +12:00
->inject('project')
2022-07-22 18:00:42 +12:00
->action(function (Document $project) {
if ($project->getId() !== 'console') {
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN);
2022-07-22 18:00:42 +12:00
}
});
2021-08-01 09:36:18 +12:00
2020-06-29 05:31:21 +12:00
App::post('/v1/projects')
2020-02-01 11:34:07 +13:00
->desc('Create Project')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-01 11:34:07 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-01 11:34:07 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'create')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
2022-10-04 09:22:28 +13:00
->param('projectId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string `ID.unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
2020-09-11 02:40:14 +12:00
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
->param('teamId', '', new UID(), 'Team unique ID.')
2022-11-25 17:27:19 +13:00
->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.', true)
2020-09-11 02:40:14 +12:00
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
->param('logo', '', new Text(1024), 'Project logo.', true)
->param('url', '', new URL(), 'Project URL.', true)
2020-09-11 02:40:14 +12:00
->param('legalName', '', new Text(256), 'Project legal Name. Max length: 256 chars.', true)
->param('legalCountry', '', new Text(256), 'Project legal Country. Max length: 256 chars.', true)
->param('legalState', '', new Text(256), 'Project legal State. Max length: 256 chars.', true)
->param('legalCity', '', new Text(256), 'Project legal City. Max length: 256 chars.', true)
->param('legalAddress', '', new Text(256), 'Project legal Address. Max length: 256 chars.', true)
->param('legalTaxId', '', new Text(256), 'Project legal Tax ID. Max length: 256 chars.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
->inject('dbForProject')
->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Database $dbForProject) {
2020-02-01 11:34:07 +13:00
2021-06-07 05:54:01 +12:00
$team = $dbForConsole->getDocument('teams', $teamId);
2020-02-01 11:34:07 +13:00
2021-05-07 10:31:05 +12:00
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2021-08-17 01:27:15 +12:00
2021-08-06 19:42:31 +12:00
$auth = Config::getParam('auth', []);
2022-11-15 23:19:35 +13:00
$auths = ['limit' => 0, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG];
2021-08-06 19:42:31 +12:00
foreach ($auth as $index => $method) {
$auths[$method['key'] ?? ''] = true;
}
2020-02-01 11:34:07 +13:00
2022-08-15 02:22:38 +12:00
$projectId = ($projectId == 'unique()') ? ID::unique() : $projectId;
2022-05-24 02:54:50 +12:00
if ($projectId === 'console') {
2022-07-27 02:56:59 +12:00
throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project.");
2022-04-17 22:18:00 +12:00
}
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId,
'$permissions' => [
2022-08-14 22:33:36 +12:00
Permission::read(Role::team(ID::custom($teamId))),
Permission::update(Role::team(ID::custom($teamId), 'owner')),
Permission::update(Role::team(ID::custom($teamId), 'developer')),
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
],
2021-05-16 10:41:42 +12:00
'name' => $name,
'teamInternalId' => $team->getInternalId(),
'teamId' => $team->getId(),
'region' => $region,
2021-05-16 10:41:42 +12:00
'description' => $description,
'logo' => $logo,
'url' => $url,
'version' => APP_VERSION_STABLE,
2021-05-16 10:41:42 +12:00
'legalName' => $legalName,
'legalCountry' => $legalCountry,
'legalState' => $legalState,
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
2022-08-14 22:33:36 +12:00
'legalTaxId' => ID::custom($legalTaxId),
'services' => new stdClass(),
'platforms' => null,
2022-04-14 21:54:29 +12:00
'authProviders' => [],
'webhooks' => null,
'keys' => null,
'domains' => null,
2021-08-06 19:42:31 +12:00
'auths' => $auths,
'search' => implode(' ', [$projectId, $name]),
2021-05-16 10:41:42 +12:00
]));
/** @var array $collections */
2022-05-24 02:54:50 +12:00
$collections = Config::getParam('collections', []);
2020-07-01 03:46:42 +12:00
$dbForProject->setNamespace("_{$project->getInternalId()}");
2022-11-01 01:02:51 +13:00
$dbForProject->create();
2021-05-03 20:28:31 +12:00
$audit = new Audit($dbForProject);
2021-06-07 17:52:40 +12:00
$audit->setup();
$adapter = new TimeLimit('', 0, 1, $dbForProject);
2021-06-07 17:52:40 +12:00
$adapter->setup();
2021-05-03 20:28:31 +12:00
foreach ($collections as $key => $collection) {
2022-05-24 02:54:50 +12:00
if (($collection['$collection'] ?? '') !== Database::METADATA) {
continue;
}
2022-06-20 23:44:04 +12:00
2021-07-05 00:05:46 +12:00
$attributes = [];
$indexes = [];
foreach ($collection['attributes'] as $attribute) {
$attributes[] = new Document([
'$id' => $attribute['$id'],
'type' => $attribute['type'],
'size' => $attribute['size'],
'required' => $attribute['required'],
'signed' => $attribute['signed'],
'array' => $attribute['array'],
'filters' => $attribute['filters'],
2022-03-27 21:01:50 +13:00
'default' => $attribute['default'] ?? null,
'format' => $attribute['format'] ?? ''
2021-07-05 00:05:46 +12:00
]);
2021-05-03 20:28:31 +12:00
}
2021-07-05 00:05:46 +12:00
foreach ($collection['indexes'] as $index) {
$indexes[] = new Document([
'$id' => $index['$id'],
'type' => $index['type'],
'attributes' => $index['attributes'],
'lengths' => $index['lengths'],
'orders' => $index['orders'],
]);
2021-05-03 20:28:31 +12:00
}
$dbForProject->createCollection($key, $attributes, $indexes);
2021-05-03 20:28:31 +12:00
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($project, Response::MODEL_PROJECT);
2020-12-27 05:33:36 +13:00
});
2020-02-01 11:34:07 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects')
2019-12-15 08:33:29 +13:00
->desc('List Projects')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-15 08:33:29 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-15 08:33:29 +13:00
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'list')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT_LIST)
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
2020-09-11 02:40:14 +12:00
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
->action(function (array $queries, string $search, Response $response, Database $dbForConsole) {
2020-07-09 03:07:52 +12:00
$queries = Query::parseQueries($queries);
2021-08-07 00:36:17 +12:00
2022-08-12 11:53:52 +12:00
if (!empty($search)) {
$queries[] = Query::search('search', $search);
2021-08-07 00:36:17 +12:00
}
// Get cursor document if there was a cursor query
2022-09-03 02:19:36 +12:00
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
$projectId = $cursor->getValue();
$cursorDocument = $dbForConsole->getDocument('projects', $projectId);
2021-08-19 01:42:03 +12:00
2022-08-12 11:53:52 +12:00
if ($cursorDocument->isEmpty()) {
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Project '{$projectId}' for the 'cursor' value not found.");
2022-08-12 11:53:52 +12:00
}
$cursor->setValue($cursorDocument);
2021-08-19 01:42:03 +12:00
}
$filterQueries = Query::groupByType($queries)['filters'];
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic(new Document([
'projects' => $dbForConsole->find('projects', $queries),
'total' => $dbForConsole->count('projects', $filterQueries, APP_LIMIT_COUNT),
2020-09-12 20:07:28 +12:00
]), Response::MODEL_PROJECT_LIST);
2020-12-27 05:33:36 +13:00
});
2019-12-15 08:33:29 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId')
2019-12-15 08:33:29 +13:00
->desc('Get Project')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-15 08:33:29 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-15 08:33:29 +13:00
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'get')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, Response $response, Database $dbForConsole) {
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-15 08:33:29 +13:00
2021-07-26 02:47:18 +12:00
$response->dynamic($project, Response::MODEL_PROJECT);
2020-12-27 05:33:36 +13:00
});
2019-12-15 08:33:29 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/usage')
->desc('Get usage stats for a project')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-15 08:33:29 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-15 08:33:29 +13:00
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'getUsage')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USAGE_PROJECT)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
->inject('dbForProject')
2020-12-27 05:33:36 +13:00
->inject('register')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $range, Response $response, Database $dbForConsole, Database $dbForProject, Registry $register) {
2020-07-01 03:46:42 +12:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-07-01 03:46:42 +12:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-15 08:33:29 +13:00
$usage = [];
2021-06-07 17:17:29 +12:00
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
2021-10-28 11:17:15 +13:00
$periods = [
'24h' => [
2022-10-21 18:45:25 +13:00
'period' => '1h',
'limit' => 24,
],
'7d' => [
2021-08-17 01:27:15 +12:00
'period' => '1d',
'limit' => 7,
],
'30d' => [
2021-08-17 01:27:15 +12:00
'period' => '1d',
'limit' => 30,
],
'90d' => [
2021-08-17 01:27:15 +12:00
'period' => '1d',
'limit' => 90,
],
];
2021-06-07 17:17:29 +12:00
$dbForProject->setNamespace("_{$project->getInternalId()}");
2021-08-17 01:27:15 +12:00
$metrics = [
2022-08-11 18:05:38 +12:00
'project.$all.network.requests',
'project.$all.network.bandwidth',
2022-08-13 17:00:22 +12:00
'project.$all.storage.size',
2022-08-11 18:05:38 +12:00
'users.$all.count.total',
'databases.$all.count.total',
2022-08-13 17:00:22 +12:00
'documents.$all.count.total',
'executions.$all.compute.total',
'buckets.$all.count.total'
];
$stats = [];
2022-05-24 02:54:50 +12:00
Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
foreach ($metrics as $metric) {
2021-10-28 11:17:15 +13:00
$limit = $periods[$range]['limit'];
$period = $periods[$range]['period'];
$requestDocs = $dbForProject->find('stats', [
2022-08-12 11:53:52 +12:00
Query::equal('period', [$period]),
Query::equal('metric', [$metric]),
Query::limit($limit),
Query::orderDesc('time'),
]);
2021-10-27 02:19:28 +13:00
$stats[$metric] = [];
foreach ($requestDocs as $requestDoc) {
$stats[$metric][] = [
'value' => $requestDoc->getAttribute('value'),
'date' => $requestDoc->getAttribute('time'),
];
}
// backfill metrics with empty values for graphs
$backfill = $limit - \count($requestDocs);
while ($backfill > 0) {
$last = $limit - $backfill - 1; // array index of last added metric
2022-05-24 02:54:50 +12:00
$diff = match ($period) { // convert period to seconds for unix timestamp math
2022-10-21 18:45:25 +13:00
'1h' => 3600,
'1d' => 86400,
};
$stats[$metric][] = [
'value' => 0,
2022-09-16 11:48:09 +12:00
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
];
$backfill--;
}
$stats[$metric] = array_reverse($stats[$metric]);
2021-10-27 02:19:28 +13:00
}
});
$usage = new Document([
'range' => $range,
2022-08-20 23:20:31 +12:00
'requests' => $stats[$metrics[0]] ?? [],
'network' => $stats[$metrics[1]] ?? [],
'storage' => $stats[$metrics[2]] ?? [],
'users' => $stats[$metrics[3]] ?? [],
'databases' => $stats[$metrics[4]] ?? [],
2022-08-20 23:20:31 +12:00
'documents' => $stats[$metrics[5]] ?? [],
'executions' => $stats[$metrics[6]] ?? [],
'buckets' => $stats[$metrics[7]] ?? [],
]);
2020-07-01 03:46:42 +12:00
}
2019-12-15 08:33:29 +13:00
$response->dynamic($usage, Response::MODEL_USAGE_PROJECT);
2020-12-27 05:33:36 +13:00
});
2019-12-15 08:33:29 +13:00
2020-06-29 05:31:21 +12:00
App::patch('/v1/projects/:projectId')
2019-12-15 08:33:29 +13:00
->desc('Update Project')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-15 08:33:29 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-15 08:33:29 +13:00
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'update')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
->param('logo', '', new Text(1024), 'Project logo.', true)
->param('url', '', new URL(), 'Project URL.', true)
2020-09-11 02:40:14 +12:00
->param('legalName', '', new Text(256), 'Project legal name. Max length: 256 chars.', true)
->param('legalCountry', '', new Text(256), 'Project legal country. Max length: 256 chars.', true)
->param('legalState', '', new Text(256), 'Project legal state. Max length: 256 chars.', true)
->param('legalCity', '', new Text(256), 'Project legal city. Max length: 256 chars.', true)
->param('legalAddress', '', new Text(256), 'Project legal address. Max length: 256 chars.', true)
->param('legalTaxId', '', new Text(256), 'Project legal tax ID. Max length: 256 chars.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-11-14 22:15:55 +13:00
->action(function (string $projectId, string $name, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole) {
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
2021-06-07 17:17:29 +12:00
->setAttribute('name', $name)
->setAttribute('description', $description)
->setAttribute('logo', $logo)
->setAttribute('url', $url)
->setAttribute('legalName', $legalName)
->setAttribute('legalCountry', $legalCountry)
->setAttribute('legalState', $legalState)
->setAttribute('legalCity', $legalCity)
->setAttribute('legalAddress', $legalAddress)
->setAttribute('legalTaxId', $legalTaxId)
2022-05-24 02:54:50 +12:00
->setAttribute('search', implode(' ', [$projectId, $name])));
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($project, Response::MODEL_PROJECT);
2020-12-27 05:33:36 +13:00
});
2019-12-15 08:33:29 +13:00
2021-07-29 22:28:17 +12:00
App::patch('/v1/projects/:projectId/service')
->desc('Update service status')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
2021-08-01 08:54:50 +12:00
->label('sdk.method', 'updateServiceStatus')
2021-07-29 22:28:17 +12:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
2022-05-24 04:42:27 +12:00
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])), true), 'Service name.')
2021-08-01 09:36:18 +12:00
->param('status', null, new Boolean(), 'Service status.')
2021-07-29 22:28:17 +12:00
->inject('response')
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $service, bool $status, Response $response, Database $dbForConsole) {
2021-07-29 22:28:17 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2021-07-29 22:56:25 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2021-07-29 22:28:17 +12:00
}
2021-08-01 08:54:50 +12:00
$services = $project->getAttribute('services', []);
$services[$service] = $status;
2021-07-29 22:28:17 +12:00
2021-08-01 08:54:50 +12:00
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('services', $services));
2021-07-29 22:28:17 +12:00
$response->dynamic($project, Response::MODEL_PROJECT);
});
2020-06-29 05:31:21 +12:00
App::patch('/v1/projects/:projectId/oauth2')
2020-02-17 00:41:03 +13:00
->desc('Update Project OAuth2')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-15 08:33:29 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-15 08:33:29 +13:00
->label('sdk.namespace', 'projects')
2020-02-17 00:41:03 +13:00
->label('sdk.method', 'updateOAuth2')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'Provider Name')
->param('appId', null, new Text(256), 'Provider app ID. Max length: 256 chars.', true)
->param('secret', null, new text(512), 'Provider secret key. Max length: 512 chars.', true)
->param('enabled', null, new Boolean(), 'Provider status. Set to \'false\' to disable new session creation.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-08-19 21:43:03 +12:00
->action(function (string $projectId, string $provider, ?string $appId, ?string $secret, ?bool $enabled, Response $response, Database $dbForConsole) {
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-15 08:33:29 +13:00
2022-04-14 21:54:29 +12:00
$providers = $project->getAttribute('authProviders', []);
2022-08-19 21:43:03 +12:00
if ($appId !== null) {
$providers[$provider . 'Appid'] = $appId;
}
2022-08-19 21:43:03 +12:00
if ($secret !== null) {
$providers[$provider . 'Secret'] = $secret;
}
2022-08-19 21:43:03 +12:00
if ($enabled !== null) {
$providers[$provider . 'Enabled'] = $enabled;
}
2021-08-06 22:35:50 +12:00
2022-04-14 21:54:29 +12:00
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers));
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($project, Response::MODEL_PROJECT);
2020-12-27 05:33:36 +13:00
});
2019-12-15 08:33:29 +13:00
2021-03-01 04:00:27 +13:00
App::patch('/v1/projects/:projectId/auth/limit')
->desc('Update Project users limit')
2021-03-01 00:40:59 +13:00
->groups(['api', 'projects'])
->label('scope', 'projects.write')
2021-04-23 18:31:22 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2021-03-01 00:40:59 +13:00
->label('sdk.namespace', 'projects')
2021-03-01 04:00:27 +13:00
->label('sdk.method', 'updateAuthLimit')
2021-03-01 00:40:59 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
2022-01-16 12:25:00 +13:00
->param('limit', false, new Range(0, APP_LIMIT_USERS), 'Set the max number of users allowed in this project. Use 0 for unlimited.')
2021-03-01 00:40:59 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
2021-03-01 00:40:59 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2021-03-01 00:40:59 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2021-03-01 00:40:59 +13:00
}
2021-08-06 20:34:17 +12:00
$auths = $project->getAttribute('auths', []);
$auths['limit'] = $limit;
2021-05-16 10:41:42 +12:00
$dbForConsole->updateDocument('projects', $project->getId(), $project
2022-05-24 02:54:50 +12:00
->setAttribute('auths', $auths));
2021-03-01 00:40:59 +13:00
2021-07-26 02:47:18 +12:00
$response->dynamic($project, Response::MODEL_PROJECT);
2022-11-14 22:15:55 +13:00
});
2022-11-14 22:33:49 +13:00
App::patch('/v1/projects/:projectId/auth/duration')
2022-11-14 22:15:55 +13:00
->desc('Update Project Authentication Duration')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateAuthDuration')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
2022-11-15 23:25:34 +13:00
->param('duration', 31536000, new Range(0, 31536000), 'Project session length in seconds. Max length: 31536000 seconds.')
2022-11-14 22:15:55 +13:00
->inject('response')
->inject('dbForConsole')
2022-11-14 22:42:18 +13:00
->action(function (string $projectId, int $duration, Response $response, Database $dbForConsole) {
2022-11-14 22:15:55 +13:00
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
2022-11-15 23:25:34 +13:00
$auths['duration'] = $duration;
2022-11-14 22:15:55 +13:00
$dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
2022-11-14 22:15:55 +13:00
$response->dynamic($project, Response::MODEL_PROJECT);
2021-03-01 00:40:59 +13:00
});
2021-03-01 04:00:27 +13:00
App::patch('/v1/projects/:projectId/auth/:method')
->desc('Update Project auth method status. Use this endpoint to enable or disable a given auth method for this project.')
2021-03-01 00:40:59 +13:00
->groups(['api', 'projects'])
->label('scope', 'projects.write')
2021-04-23 18:31:22 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2021-03-01 00:40:59 +13:00
->label('sdk.namespace', 'projects')
2021-03-01 04:00:27 +13:00
->label('sdk.method', 'updateAuthStatus')
2021-03-01 00:40:59 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
2021-06-07 17:17:29 +12:00
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: ' . implode(',', \array_keys(Config::getParam('auth'))), false)
2021-03-01 04:00:27 +13:00
->param('status', false, new Boolean(true), 'Set the status of this auth method.')
2021-03-01 00:40:59 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $method, bool $status, Response $response, Database $dbForConsole) {
2021-03-01 00:40:59 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2021-03-01 04:00:27 +13:00
$auth = Config::getParam('auth')[$method] ?? [];
$authKey = $auth['key'] ?? '';
$status = ($status === '1' || $status === 'true' || $status === 1 || $status === true);
2021-03-01 00:40:59 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2021-03-01 00:40:59 +13:00
}
2021-08-06 19:42:31 +12:00
$auths = $project->getAttribute('auths', []);
$auths[$authKey] = $status;
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('auths', $auths));
2021-03-01 00:40:59 +13:00
2021-07-26 02:47:18 +12:00
$response->dynamic($project, Response::MODEL_PROJECT);
2021-03-01 00:40:59 +13:00
});
2020-06-29 05:31:21 +12:00
App::delete('/v1/projects/:projectId')
2019-12-15 08:33:29 +13:00
->desc('Delete Project')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-15 08:33:29 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-15 08:33:29 +13:00
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'delete')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('password', '', new Password(), 'Your user password for confirmation. Must be at least 8 chars.')
2020-12-27 05:33:36 +13:00
->inject('response')
->inject('user')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2020-12-27 05:33:36 +13:00
->inject('deletes')
->action(function (string $projectId, string $password, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
2020-07-01 03:46:42 +12:00
2022-05-05 23:21:31 +12:00
if (!Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
2020-07-01 03:46:42 +12:00
}
2020-01-31 12:50:17 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-15 08:33:29 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-15 08:33:29 +13:00
2020-12-19 00:08:58 +13:00
$deletes
2022-04-18 08:34:32 +12:00
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($project)
2020-12-19 00:08:58 +13:00
;
2021-06-07 17:17:29 +12:00
2021-05-16 10:41:42 +12:00
if (!$dbForConsole->deleteDocument('projects', $projectId)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB');
2019-12-18 23:24:54 +13:00
}
2020-07-01 03:46:42 +12:00
$response->noContent();
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
// Webhooks
2020-06-29 05:31:21 +12:00
App::post('/v1/projects/:projectId/webhooks')
2020-02-01 11:34:07 +13:00
->desc('Create Webhook')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-01 11:34:07 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-01 11:34:07 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createWebhook')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-09-11 02:40:14 +12:00
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
2022-02-17 04:16:37 +13:00
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
2020-09-11 02:40:14 +12:00
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) {
2020-02-01 11:34:07 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-01 11:34:07 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-01 11:34:07 +13:00
2022-02-22 00:11:48 +13:00
$security = (bool) filter_var($security, FILTER_VALIDATE_BOOLEAN);
2020-07-01 03:46:42 +12:00
2021-05-16 10:41:42 +12:00
$webhook = new Document([
2022-08-15 02:22:38 +12:00
'$id' => ID::unique(),
'$permissions' => [
2022-08-14 17:21:11 +12:00
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
2020-07-01 03:46:42 +12:00
'name' => $name,
'events' => $events,
'url' => $url,
2020-07-09 21:11:42 +12:00
'security' => $security,
2020-07-01 03:46:42 +12:00
'httpUser' => $httpUser,
'httpPass' => $httpPass,
2022-06-08 03:11:07 +12:00
'signatureKey' => \bin2hex(\random_bytes(64)),
2020-07-01 03:46:42 +12:00
]);
$webhook = $dbForConsole->createDocument('webhooks', $webhook);
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($webhook, Response::MODEL_WEBHOOK);
2020-12-27 05:33:36 +13:00
});
2020-02-01 11:34:07 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/webhooks')
2019-12-18 23:24:54 +13:00
->desc('List Webhooks')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listWebhooks')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK_LIST)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$webhooks = $dbForConsole->find('webhooks', [
2022-08-12 11:53:52 +12:00
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::limit(5000),
]);
2019-12-18 23:24:54 +13:00
2021-07-26 02:47:18 +12:00
$response->dynamic(new Document([
2021-05-27 22:09:14 +12:00
'webhooks' => $webhooks,
2022-02-27 22:57:09 +13:00
'total' => count($webhooks),
2020-08-15 09:56:50 +12:00
]), Response::MODEL_WEBHOOK_LIST);
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/webhooks/:webhookId')
2019-12-18 23:24:54 +13:00
->desc('Get Webhook')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getWebhook')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('webhookId', '', new UID(), 'Webhook unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$webhook = $dbForConsole->findOne('webhooks', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2019-12-18 23:24:54 +13:00
if ($webhook === false || $webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
2021-07-26 02:47:18 +12:00
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
2020-06-29 05:31:21 +12:00
App::put('/v1/projects/:projectId/webhooks/:webhookId')
2019-12-18 23:24:54 +13:00
->desc('Update Webhook')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateWebhook')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('webhookId', '', new UID(), 'Webhook unique ID.')
2020-09-11 02:40:14 +12:00
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
2022-02-17 04:16:37 +13:00
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
2020-09-11 02:40:14 +12:00
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
2020-07-01 03:46:42 +12:00
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$webhook = $dbForConsole->findOne('webhooks', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2020-07-01 03:46:42 +12:00
if ($webhook === false || $webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$webhook
->setAttribute('name', $name)
->setAttribute('events', $events)
->setAttribute('url', $url)
->setAttribute('security', $security)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
;
2020-07-01 03:46:42 +12:00
$dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook);
$dbForConsole->deleteCachedDocument('projects', $project->getId());
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
});
App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
->desc('Update Webhook Signature Key')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateWebhookSignature')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('webhookId', '', new UID(), 'Webhook unique ID.')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2022-06-08 19:19:50 +12:00
}
2020-07-01 03:46:42 +12:00
$webhook = $dbForConsole->findOne('webhooks', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
if ($webhook === false || $webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
}
$webhook->setAttribute('signatureKey', \bin2hex(\random_bytes(64)));
2022-06-08 19:19:50 +12:00
$dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook);
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2021-06-07 17:17:29 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
2020-06-29 05:31:21 +12:00
App::delete('/v1/projects/:projectId/webhooks/:webhookId')
2019-12-18 23:24:54 +13:00
->desc('Delete Webhook')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteWebhook')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('webhookId', '', new UID(), 'Webhook unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$webhook = $dbForConsole->findOne('webhooks', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2022-05-24 02:54:50 +12:00
if ($webhook === false || $webhook->isEmpty()) {
throw new Exception(Exception::WEBHOOK_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$dbForConsole->deleteDocument('webhooks', $webhook->getId());
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
$response->noContent();
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
// Keys
2020-06-29 05:31:21 +12:00
App::post('/v1/projects/:projectId/keys')
2020-02-01 11:34:07 +13:00
->desc('Create Key')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-01 11:34:07 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
2020-02-01 11:34:07 +13:00
->label('sdk.method', 'createKey')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-09-11 02:40:14 +12:00
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
2022-05-01 19:54:58 +12:00
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.')
2022-09-05 09:33:52 +12:00
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
->action(function (string $projectId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$key = new Document([
2022-08-15 02:22:38 +12:00
'$id' => ID::unique(),
'$permissions' => [
2022-08-14 17:21:11 +12:00
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
2020-07-01 03:46:42 +12:00
'name' => $name,
'scopes' => $scopes,
2022-06-01 03:41:12 +12:00
'expire' => $expire,
2022-08-05 22:20:48 +12:00
'sdks' => [],
2022-08-19 21:54:26 +12:00
'accessedAt' => null,
2020-07-01 03:46:42 +12:00
'secret' => \bin2hex(\random_bytes(128)),
]);
$key = $dbForConsole->createDocument('keys', $key);
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($key, Response::MODEL_KEY);
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/keys')
2020-02-01 11:34:07 +13:00
->desc('List Keys')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-01 11:34:07 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-01 11:34:07 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listKeys')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY_LIST)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, Response $response, Database $dbForConsole) {
2021-06-07 17:17:29 +12:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-07-01 03:46:42 +12:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-02-01 11:34:07 +13:00
}
2020-07-01 03:46:42 +12:00
$keys = $dbForConsole->find('keys', [
2022-08-12 11:53:52 +12:00
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::limit(5000),
]);
2020-08-15 09:56:50 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic(new Document([
2021-05-27 22:09:14 +12:00
'keys' => $keys,
2022-02-27 22:57:09 +13:00
'total' => count($keys),
2020-08-15 09:56:50 +12:00
]), Response::MODEL_KEY_LIST);
2020-12-27 05:33:36 +13:00
});
2020-02-01 11:34:07 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/keys/:keyId')
2020-02-01 11:34:07 +13:00
->desc('Get Key')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-01 11:34:07 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-01 11:34:07 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getKey')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('keyId', '', new UID(), 'Key unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-01 11:34:07 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-01 11:34:07 +13:00
$key = $dbForConsole->findOne('keys', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2020-02-01 11:34:07 +13:00
if ($key === false || $key->isEmpty()) {
throw new Exception(Exception::KEY_NOT_FOUND);
2020-02-01 11:34:07 +13:00
}
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($key, Response::MODEL_KEY);
2020-12-27 05:33:36 +13:00
});
2020-02-01 11:34:07 +13:00
2020-06-29 05:31:21 +12:00
App::put('/v1/projects/:projectId/keys/:keyId')
2019-12-18 23:24:54 +13:00
->desc('Update Key')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateKey')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('keyId', '', new UID(), 'Key unique ID.')
2020-09-11 02:40:14 +12:00
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
2022-05-01 19:54:58 +12:00
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
2022-09-05 09:33:52 +12:00
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
->action(function (string $projectId, string $keyId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$key = $dbForConsole->findOne('keys', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2019-12-18 23:24:54 +13:00
if ($key === false || $key->isEmpty()) {
throw new Exception(Exception::KEY_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$key
->setAttribute('name', $name)
->setAttribute('scopes', $scopes)
2022-06-01 03:41:12 +12:00
->setAttribute('expire', $expire)
;
2019-12-18 23:24:54 +13:00
$dbForConsole->updateDocument('keys', $key->getId(), $key);
2019-12-18 23:24:54 +13:00
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2021-06-07 17:17:29 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($key, Response::MODEL_KEY);
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
2020-06-29 05:31:21 +12:00
App::delete('/v1/projects/:projectId/keys/:keyId')
2019-12-18 23:24:54 +13:00
->desc('Delete Key')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteKey')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('keyId', '', new UID(), 'Key unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$key = $dbForConsole->findOne('keys', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2022-05-24 02:54:50 +12:00
if ($key === false || $key->isEmpty()) {
throw new Exception(Exception::KEY_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$dbForConsole->deleteDocument('keys', $key->getId());
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
$response->noContent();
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
// Platforms
2020-06-29 05:31:21 +12:00
App::post('/v1/projects/:projectId/platforms')
2019-12-18 23:24:54 +13:00
->desc('Create Platform')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createPlatform')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('type', null, new WhiteList([Origin::CLIENT_TYPE_WEB, Origin::CLIENT_TYPE_FLUTTER_IOS, Origin::CLIENT_TYPE_FLUTTER_ANDROID, Origin::CLIENT_TYPE_FLUTTER_LINUX, Origin::CLIENT_TYPE_FLUTTER_MACOS, Origin::CLIENT_TYPE_FLUTTER_WINDOWS, Origin::CLIENT_TYPE_APPLE_IOS, Origin::CLIENT_TYPE_APPLE_MACOS, Origin::CLIENT_TYPE_APPLE_WATCHOS, Origin::CLIENT_TYPE_APPLE_TVOS, Origin::CLIENT_TYPE_ANDROID, Origin::CLIENT_TYPE_UNITY], true), 'Platform type.')
2020-09-11 02:40:14 +12:00
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
2021-09-28 23:24:54 +13:00
->param('key', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.', true)
2020-09-11 02:40:14 +12:00
->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true)
2022-05-13 06:53:54 +12:00
->param('hostname', '', new Hostname(), 'Platform client hostname. Max length: 256 chars.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $type, string $name, string $key, string $store, string $hostname, Response $response, Database $dbForConsole) {
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$platform = new Document([
2022-08-15 02:22:38 +12:00
'$id' => ID::unique(),
'$permissions' => [
2022-08-15 22:11:17 +12:00
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
2020-07-01 03:46:42 +12:00
'type' => $type,
'name' => $name,
'key' => $key,
'store' => $store,
'hostname' => $hostname
2020-07-01 03:46:42 +12:00
]);
$platform = $dbForConsole->createDocument('platforms', $platform);
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($platform, Response::MODEL_PLATFORM);
2020-12-27 05:33:36 +13:00
});
2021-06-07 17:17:29 +12:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/platforms')
2020-02-01 11:34:07 +13:00
->desc('List Platforms')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-01 11:34:07 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-01 11:34:07 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listPlatforms')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM_LIST)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, Response $response, Database $dbForConsole) {
2020-02-01 11:34:07 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-01 11:34:07 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-02-01 11:34:07 +13:00
}
2020-07-01 03:46:42 +12:00
$platforms = $dbForConsole->find('platforms', [
2022-08-12 11:53:52 +12:00
Query::equal('projectId', [$project->getId()]),
Query::limit(5000),
]);
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic(new Document([
2021-05-27 22:09:14 +12:00
'platforms' => $platforms,
2022-02-27 22:57:09 +13:00
'total' => count($platforms),
2020-08-15 09:56:50 +12:00
]), Response::MODEL_PLATFORM_LIST);
2020-12-27 05:33:36 +13:00
});
2020-02-01 11:34:07 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/platforms/:platformId')
2020-02-01 11:34:07 +13:00
->desc('Get Platform')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-01 11:34:07 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-01 11:34:07 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getPlatform')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('platformId', '', new UID(), 'Platform unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
2020-02-01 11:34:07 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-01 11:34:07 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-01 11:34:07 +13:00
$platform = $dbForConsole->findOne('platforms', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2020-02-01 11:34:07 +13:00
if ($platform === false || $platform->isEmpty()) {
throw new Exception(Exception::PLATFORM_NOT_FOUND);
2020-02-01 11:34:07 +13:00
}
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($platform, Response::MODEL_PLATFORM);
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
2020-06-29 05:31:21 +12:00
App::put('/v1/projects/:projectId/platforms/:platformId')
2019-12-18 23:24:54 +13:00
->desc('Update Platform')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updatePlatform')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('platformId', '', new UID(), 'Platform unique ID.')
2020-09-11 02:40:14 +12:00
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
->param('key', '', new Text(256), 'Package name for android or bundle ID for iOS. Max length: 256 chars.', true)
->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true)
2022-05-13 06:53:54 +12:00
->param('hostname', '', new Hostname(), 'Platform client URL. Max length: 256 chars.', true)
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $platformId, string $name, string $key, string $store, string $hostname, Response $response, Database $dbForConsole) {
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$platform = $dbForConsole->findOne('platforms', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2019-12-18 23:24:54 +13:00
if ($platform === false || $platform->isEmpty()) {
throw new Exception(Exception::PLATFORM_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
2020-07-01 03:46:42 +12:00
$platform
->setAttribute('name', $name)
->setAttribute('key', $key)
->setAttribute('store', $store)
->setAttribute('hostname', $hostname)
;
2019-12-18 23:24:54 +13:00
$dbForConsole->updateDocument('platforms', $platform->getId(), $platform);
2020-07-01 03:46:42 +12:00
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2021-05-16 10:41:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($platform, Response::MODEL_PLATFORM);
2020-12-27 05:33:36 +13:00
});
2019-12-18 23:24:54 +13:00
2020-06-29 05:31:21 +12:00
App::delete('/v1/projects/:projectId/platforms/:platformId')
2019-12-18 23:24:54 +13:00
->desc('Delete Platform')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2019-12-18 23:24:54 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deletePlatform')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('platformId', '', new UID(), 'Platform unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2019-12-18 23:24:54 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$platform = $dbForConsole->findOne('platforms', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
if ($platform === false || $platform->isEmpty()) {
throw new Exception(Exception::PLATFORM_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2019-12-18 23:24:54 +13:00
$dbForConsole->deleteDocument('platforms', $platformId);
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
$response->noContent();
2020-12-27 05:33:36 +13:00
});
2020-02-22 21:10:30 +13:00
// Domains
2020-06-29 05:31:21 +12:00
App::post('/v1/projects/:projectId/domains')
2020-02-22 21:10:30 +13:00
->desc('Create Domain')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-22 21:10:30 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-22 21:10:30 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createDomain')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-09-11 02:40:14 +12:00
->param('domain', null, new DomainValidator(), 'Domain name.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $domain, Response $response, Database $dbForConsole) {
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-24 06:05:42 +13:00
$document = $dbForConsole->findOne('domains', [
2022-08-12 11:53:52 +12:00
Query::equal('domain', [$domain]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2020-02-24 06:05:42 +13:00
if ($document && !$document->isEmpty()) {
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
2020-07-01 03:46:42 +12:00
}
2020-07-01 03:46:42 +12:00
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
2020-02-22 21:10:30 +13:00
2020-07-01 03:46:42 +12:00
if (!$target->isKnown() || $target->isTest()) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
2020-07-01 03:46:42 +12:00
$domain = new Domain($domain);
2021-05-16 10:41:42 +12:00
$domain = new Document([
2022-08-15 02:22:38 +12:00
'$id' => ID::unique(),
'$permissions' => [
2022-08-15 22:11:17 +12:00
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
2022-07-14 02:02:49 +12:00
'updated' => DateTime::now(),
2020-07-01 03:46:42 +12:00
'domain' => $domain->get(),
'tld' => $domain->getSuffix(),
'registerable' => $domain->getRegisterable(),
'verification' => false,
'certificateId' => null,
]);
$domain = $dbForConsole->createDocument('domains', $domain);
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($domain, Response::MODEL_DOMAIN);
2020-12-27 05:33:36 +13:00
});
2020-02-22 21:10:30 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/domains')
2020-02-22 21:10:30 +13:00
->desc('List Domains')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-22 21:10:30 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-22 21:10:30 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listDomains')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN_LIST)
2020-09-11 02:40:14 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, Response $response, Database $dbForConsole) {
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-02-22 21:10:30 +13:00
}
2020-07-01 03:46:42 +12:00
$domains = $dbForConsole->find('domains', [
2022-08-12 11:53:52 +12:00
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::limit(5000),
]);
2021-06-07 17:17:29 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic(new Document([
2021-05-27 22:09:14 +12:00
'domains' => $domains,
2022-02-27 22:57:09 +13:00
'total' => count($domains),
2020-08-15 09:56:50 +12:00
]), Response::MODEL_DOMAIN_LIST);
2020-12-27 05:33:36 +13:00
});
2020-02-22 21:10:30 +13:00
2020-06-29 05:31:21 +12:00
App::get('/v1/projects/:projectId/domains/:domainId')
2020-02-22 21:10:30 +13:00
->desc('Get Domain')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-22 21:10:30 +13:00
->label('scope', 'projects.read')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-22 21:10:30 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getDomain')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('domainId', '', new UID(), 'Domain unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
$domain = $dbForConsole->findOne('domains', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$domainId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2020-02-22 21:10:30 +13:00
if ($domain === false || $domain->isEmpty()) {
throw new Exception(Exception::DOMAIN_NOT_FOUND);
2020-02-22 21:10:30 +13:00
}
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($domain, Response::MODEL_DOMAIN);
2020-12-27 05:33:36 +13:00
});
2020-02-22 21:10:30 +13:00
2020-06-29 05:31:21 +12:00
App::patch('/v1/projects/:projectId/domains/:domainId/verification')
2020-02-22 21:10:30 +13:00
->desc('Update Domain Verification Status')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-22 21:10:30 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-22 21:10:30 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateDomainVerification')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('domainId', '', new UID(), 'Domain unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2022-05-07 04:51:02 +12:00
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
$domain = $dbForConsole->findOne('domains', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$domainId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
if ($domain === false || $domain->isEmpty()) {
throw new Exception(Exception::DOMAIN_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-07-01 03:46:42 +12:00
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
2020-02-23 22:10:32 +13:00
2020-07-01 03:46:42 +12:00
if (!$target->isKnown() || $target->isTest()) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
2020-07-01 03:46:42 +12:00
if ($domain->getAttribute('verification') === true) {
2021-07-26 02:47:18 +12:00
return $response->dynamic($domain, Response::MODEL_DOMAIN);
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
$validator = new CNAME($target->get()); // Verify Domain with DNS records
2020-02-22 21:10:30 +13:00
2020-07-01 03:46:42 +12:00
if (!$validator->isValid($domain->getAttribute('domain', ''))) {
throw new Exception(Exception::DOMAIN_VERIFICATION_FAILED);
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
$dbForConsole->updateDocument('domains', $domain->getId(), $domain->setAttribute('verification', true));
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2020-07-01 03:46:42 +12:00
// Issue a TLS certificate when domain is verified
$event = new Certificate();
$event
->setDomain($domain)
->trigger();
2020-07-01 03:46:42 +12:00
2021-07-26 02:47:18 +12:00
$response->dynamic($domain, Response::MODEL_DOMAIN);
2020-12-27 05:33:36 +13:00
});
2020-02-22 21:10:30 +13:00
2020-06-29 05:31:21 +12:00
App::delete('/v1/projects/:projectId/domains/:domainId')
2020-02-22 21:10:30 +13:00
->desc('Delete Domain')
2020-06-26 06:32:12 +12:00
->groups(['api', 'projects'])
2020-02-22 21:10:30 +13:00
->label('scope', 'projects.write')
2021-04-16 19:22:17 +12:00
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
2020-02-22 21:10:30 +13:00
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteDomain')
2020-11-12 10:02:24 +13:00
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
2022-09-19 22:05:42 +12:00
->param('projectId', '', new UID(), 'Project unique ID.')
->param('domainId', '', new UID(), 'Domain unique ID.')
2020-12-27 05:33:36 +13:00
->inject('response')
2021-05-16 10:41:42 +12:00
->inject('dbForConsole')
2021-02-05 22:05:46 +13:00
->inject('deletes')
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, Delete $deletes) {
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
$project = $dbForConsole->getDocument('projects', $projectId);
2020-02-22 21:10:30 +13:00
2021-05-16 10:41:42 +12:00
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
$domain = $dbForConsole->findOne('domains', [
2022-08-12 11:53:52 +12:00
Query::equal('_uid', [$domainId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
2020-02-22 21:10:30 +13:00
if ($domain === false || $domain->isEmpty()) {
throw new Exception(Exception::DOMAIN_NOT_FOUND);
2020-07-01 03:46:42 +12:00
}
2020-02-22 21:10:30 +13:00
$dbForConsole->deleteDocument('domains', $domain->getId());
2021-10-07 00:56:44 +13:00
$dbForConsole->deleteCachedDocument('projects', $project->getId());
2021-05-16 10:41:42 +12:00
$deletes
2022-04-18 08:34:32 +12:00
->setType(DELETE_TYPE_CERTIFICATES)
->setDocument($domain);
2020-07-01 03:46:42 +12:00
$response->noContent();
2021-06-07 17:17:29 +12:00
});