1
0
Fork 0
mirror of synced 2024-05-29 17:09:48 +12:00
appwrite/app/controllers/api/projects.php

1398 lines
59 KiB
PHP
Raw Normal View History

2019-12-15 08:33:29 +13:00
<?php
global $utopia, $request, $response, $register, $user, $consoleDB, $projectDB, $providers;
2020-01-31 12:50:17 +13:00
use Auth\Auth;
2019-12-15 08:33:29 +13:00
use Utopia\Exception;
use Utopia\Response;
2019-12-18 23:24:54 +13:00
use Utopia\Validator\ArrayList;
use Utopia\Validator\Domain as DomainValidator;
2019-12-15 08:33:29 +13:00
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
2019-12-18 23:24:54 +13:00
use Utopia\Validator\Range;
2019-12-15 08:33:29 +13:00
use Utopia\Validator\URL;
use Task\Validator\Cron;
use Database\Database;
use Database\Document;
use Database\Validator\UID;
use OpenSSL\OpenSSL;
2019-12-18 23:24:54 +13:00
use Cron\CronExpression;
2020-02-22 21:10:30 +13:00
use Network\Validators\CNAME;
use Utopia\Domains\Domain;
2019-12-15 08:33:29 +13:00
2019-12-17 08:35:33 +13:00
include_once __DIR__ . '/../shared/api.php';
2019-12-15 08:33:29 +13:00
$scopes = include __DIR__.'/../../../app/config/scopes.php';
2019-12-18 23:24:54 +13:00
2020-02-01 11:34:07 +13:00
$utopia->post('/v1/projects')
->desc('Create Project')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'create')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(100); }, 'Project name.')
2020-02-01 11:34:07 +13:00
->param('teamId', '', function () { return new UID(); }, 'Team unique ID.')
2020-02-10 18:54:26 +13:00
->param('description', '', function () { return new Text(255); }, 'Project description.', true)
->param('logo', '', function () { return new Text(1024); }, 'Project logo.', true)
->param('url', '', function () { return new URL(); }, 'Project URL.', true)
->param('legalName', '', function () { return new Text(256); }, 'Project legal Name.', true)
->param('legalCountry', '', function () { return new Text(256); }, 'Project legal Country.', true)
->param('legalState', '', function () { return new Text(256); }, 'Project legal State.', true)
->param('legalCity', '', function () { return new Text(256); }, 'Project legal City.', true)
->param('legalAddress', '', function () { return new Text(256); }, 'Project legal Address.', true)
->param('legalTaxId', '', function () { return new Text(256); }, 'Project legal Tax ID.', true)
2020-02-01 11:34:07 +13:00
->action(
function ($name, $teamId, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId) use ($response, $user, $consoleDB, $projectDB) {
$team = $projectDB->getDocument($teamId);
2020-02-17 20:16:11 +13:00
if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Team not found', 404);
}
$project = $consoleDB->createDocument(
[
'$collection' => Database::SYSTEM_COLLECTION_PROJECTS,
'$permissions' => [
'read' => ['team:'.$teamId],
'write' => ['team:'.$teamId.'/owner', 'team:'.$teamId.'/developer'],
],
'name' => $name,
'description' => $description,
'logo' => $logo,
'url' => $url,
'legalName' => $legalName,
'legalCountry' => $legalCountry,
'legalState' => $legalState,
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
'legalTaxId' => $legalTaxId,
2020-02-17 20:16:11 +13:00
'teamId' => $team->getId(),
2020-02-04 20:14:03 +13:00
'platforms' => [],
2020-02-01 11:34:07 +13:00
'webhooks' => [],
'keys' => [],
2020-02-04 20:14:03 +13:00
'tasks' => [],
2020-02-01 11:34:07 +13:00
]
);
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
2020-02-17 20:16:11 +13:00
$consoleDB->createNamespace($project->getId());
2020-02-01 11:34:07 +13:00
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($project->getArrayCopy())
;
}
);
2019-12-15 08:33:29 +13:00
$utopia->get('/v1/projects')
->desc('List Projects')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'list')
2019-12-15 08:33:29 +13:00
->action(
function () use ($request, $response, $providers, $consoleDB) {
$results = $consoleDB->getCollection([
'limit' => 20,
'offset' => 0,
'orderField' => 'name',
'orderType' => 'ASC',
'orderCast' => 'string',
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_PROJECTS,
],
]);
foreach ($results as $project) {
foreach ($providers as $provider => $node) {
2020-02-17 00:41:03 +13:00
$secret = json_decode($project->getAttribute('usersOauth2'.ucfirst($provider).'Secret', '{}'), true);
2019-12-15 08:33:29 +13:00
if (!empty($secret) && isset($secret['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$secret['version']);
2020-02-17 00:41:03 +13:00
$project->setAttribute('usersOauth2'.ucfirst($provider).'Secret', OpenSSL::decrypt($secret['data'], $secret['method'], $key, 0, hex2bin($secret['iv']), hex2bin($secret['tag'])));
2019-12-15 08:33:29 +13:00
}
}
}
$response->json($results);
}
);
$utopia->get('/v1/projects/:projectId')
->desc('Get Project')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'get')
2019-12-15 08:33:29 +13:00
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->action(
function ($projectId) use ($request, $response, $providers, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-15 08:33:29 +13:00
throw new Exception('Project not found', 404);
}
foreach ($providers as $provider => $node) {
2020-02-17 00:41:03 +13:00
$secret = json_decode($project->getAttribute('usersOauth2'.ucfirst($provider).'Secret', '{}'), true);
2019-12-15 08:33:29 +13:00
if (!empty($secret) && isset($secret['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$secret['version']);
2020-02-17 00:41:03 +13:00
$project->setAttribute('usersOauth2'.ucfirst($provider).'Secret', OpenSSL::decrypt($secret['data'], $secret['method'], $key, 0, hex2bin($secret['iv']), hex2bin($secret['tag'])));
2019-12-15 08:33:29 +13:00
}
}
$response->json($project->getArrayCopy());
}
);
$utopia->get('/v1/projects/:projectId/usage')
->desc('Get Project')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'getUsage')
2019-12-15 08:33:29 +13:00
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->action(
function ($projectId) use ($response, $consoleDB, $projectDB, $register) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-15 08:33:29 +13:00
throw new Exception('Project not found', 404);
}
$client = $register->get('influxdb');
$requests = [];
$network = [];
if ($client) {
$start = DateTime::createFromFormat('U', strtotime('last day of last month'));
$start = $start->format(DateTime::RFC3339);
$end = DateTime::createFromFormat('U', strtotime('last day of this month'));
$end = $end->format(DateTime::RFC3339);
$database = $client->selectDB('telegraf');
// Requests
2020-02-17 20:16:11 +13:00
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_requests_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time(1d) FILL(null)');
2019-12-15 08:33:29 +13:00
$points = $result->getPoints();
foreach ($points as $point) {
$requests[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
'date' => strtotime($point['time']),
];
}
// Network
2020-02-17 20:16:11 +13:00
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_network_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time(1d) FILL(null)');
2019-12-15 08:33:29 +13:00
$points = $result->getPoints();
foreach ($points as $point) {
$network[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
'date' => strtotime($point['time']),
];
}
}
// Users
$projectDB->getCollection([
'limit' => 0,
'offset' => 0,
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_USERS,
],
]);
$usersTotal = $projectDB->getSum();
// Documents
$collections = $projectDB->getCollection([
'limit' => 100,
'offset' => 0,
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_COLLECTIONS,
],
]);
$collectionsTotal = $projectDB->getSum();
$documents = [];
foreach ($collections as $collection) {
$result = $projectDB->getCollection([
'limit' => 0,
'offset' => 0,
'filters' => [
2020-02-17 20:16:11 +13:00
'$collection='.$collection['$id'],
2019-12-15 08:33:29 +13:00
],
]);
$documents[] = ['name' => $collection['name'], 'total' => $projectDB->getSum()];
}
// Tasks
$tasksTotal = count($project->getAttribute('tasks', []));
$response->json([
'requests' => [
'data' => $requests,
'total' => array_sum(array_map(function ($item) {
return $item['value'];
}, $requests)),
],
'network' => [
'data' => $network,
'total' => array_sum(array_map(function ($item) {
return $item['value'];
}, $network)),
],
'collections' => [
'data' => $collections,
'total' => $collectionsTotal,
],
'documents' => [
'data' => $documents,
'total' => array_sum(array_map(function ($item) {
return $item['total'];
}, $documents)),
],
'users' => [
'data' => [],
'total' => $usersTotal,
],
'tasks' => [
'data' => [],
'total' => $tasksTotal,
],
'storage' => [
'total' => $projectDB->getCount(
[
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_FILES,
],
]
),
],
]);
}
);
$utopia->patch('/v1/projects/:projectId')
->desc('Update Project')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'update')
2019-12-15 08:33:29 +13:00
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(100); }, 'Project name.')
->param('description', '', function () { return new Text(255); }, 'Project description.', true)
->param('logo', '', function () { return new Text(1024); }, 'Project logo.', true)
->param('url', '', function () { return new URL(); }, 'Project URL.', true)
->param('legalName', '', function () { return new Text(256); }, 'Project legal name.', true)
->param('legalCountry', '', function () { return new Text(256); }, 'Project legal country..', true)
->param('legalState', '', function () { return new Text(256); }, 'Project legal state.', true)
->param('legalCity', '', function () { return new Text(256); }, 'Project legal city.', true)
->param('legalAddress', '', function () { return new Text(256); }, 'Project legal address.', true)
->param('legalTaxId', '', function () { return new Text(256); }, 'Project legal tax ID.', true)
2019-12-15 08:33:29 +13:00
->action(
function ($projectId, $name, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-15 08:33:29 +13:00
throw new Exception('Project not found', 404);
}
$project = $consoleDB->updateDocument(array_merge($project->getArrayCopy(), [
'name' => $name,
'description' => $description,
'logo' => $logo,
'url' => $url,
'legalName' => $legalName,
'legalCountry' => $legalCountry,
'legalState' => $legalState,
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
'legalTaxId' => $legalTaxId,
]));
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
$response->json($project->getArrayCopy());
}
);
2020-02-17 00:41:03 +13:00
$utopia->patch('/v1/projects/:projectId/oauth2')
->desc('Update Project OAuth2')
2019-12-15 08:33:29 +13:00
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
2020-02-17 00:41:03 +13:00
->label('sdk.method', 'updateOAuth2')
2019-12-15 08:33:29 +13:00
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->param('provider', '', function () use ($providers) { return new WhiteList(array_keys($providers)); }, 'Provider Name', false)
2020-02-10 18:54:26 +13:00
->param('appId', '', function () { return new Text(256); }, 'Provider app ID.', true)
->param('secret', '', function () { return new text(256); }, 'Provider secret key.', true)
2019-12-15 08:33:29 +13:00
->action(
function ($projectId, $provider, $appId, $secret) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-15 08:33:29 +13:00
throw new Exception('Project not found', 404);
}
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$secret = json_encode([
'data' => OpenSSL::encrypt($secret, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => bin2hex($iv),
'tag' => bin2hex($tag),
'version' => '1',
]);
$project = $consoleDB->updateDocument(array_merge($project->getArrayCopy(), [
2020-02-17 00:41:03 +13:00
'usersOauth2'.ucfirst($provider).'Appid' => $appId,
'usersOauth2'.ucfirst($provider).'Secret' => $secret,
2019-12-15 08:33:29 +13:00
]));
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
$response->json($project->getArrayCopy());
}
);
$utopia->delete('/v1/projects/:projectId')
->desc('Delete Project')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
2020-01-31 05:18:46 +13:00
->label('sdk.method', 'delete')
2019-12-15 08:33:29 +13:00
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
2020-02-10 18:58:29 +13:00
->param('password', '', function () { return new UID(); }, 'Your user password for confirmation.')
2019-12-15 08:33:29 +13:00
->action(
2020-01-31 12:50:17 +13:00
function ($projectId, $password) use ($response, $consoleDB, $user) {
if (!Auth::passwordVerify($password, $user->getAttribute('password'))) { // Double check user password
throw new Exception('Invalid credentials', 401);
}
2019-12-15 08:33:29 +13:00
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-15 08:33:29 +13:00
throw new Exception('Project not found', 404);
}
// Delete all children (keys, webhooks, tasks [stop tasks?], platforms)
if (!$consoleDB->deleteDocument($projectId)) {
throw new Exception('Failed to remove project from DB', 500);
}
// Delete all DBs
2020-02-17 20:16:11 +13:00
// $consoleDB->deleteNamespace($project->getId());
2019-12-15 08:33:29 +13:00
// Optimize DB?
// Delete all storage files
// Delete all storage cache
2019-12-18 23:24:54 +13:00
$response->noContent();
}
);
// Webhooks
2020-02-01 11:34:07 +13:00
$utopia->post('/v1/projects/:projectId/webhooks')
->desc('Create Webhook')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(256); }, 'Webhook name.')
->param('events', null, function () { return new ArrayList(new Text(256)); }, 'Webhook events list.')
->param('url', null, function () { return new Text(2000); }, 'Webhook URL.')
->param('security', null, function () { return new Range(0, 1); }, 'Certificate verification, 0 for disabled or 1 for enabled.')
->param('httpUser', '', function () { return new Text(256); }, 'Webhook HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Webhook HTTP password.', true)
2020-02-01 11:34:07 +13:00
->action(
function ($projectId, $name, $events, $url, $security, $httpUser, $httpPass) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Project not found', 404);
}
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => bin2hex($iv),
'tag' => bin2hex($tag),
'version' => '1',
]);
$webhook = $consoleDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_WEBHOOKS,
'$permissions' => [
'read' => ['team:'.$project->getAttribute('teamId', null)],
'write' => ['team:'.$project->getAttribute('teamId', null).'/owner', 'team:'.$project->getAttribute('teamId', null).'/developer'],
],
'name' => $name,
'events' => $events,
'url' => $url,
'security' => (int) $security,
'httpUser' => $httpUser,
'httpPass' => $httpPass,
]);
if (false === $webhook) {
throw new Exception('Failed saving webhook to DB', 500);
}
$project->setAttribute('webhooks', $webhook, Document::SET_TYPE_APPEND);
$project = $consoleDB->updateDocument($project->getArrayCopy());
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($webhook->getArrayCopy())
;
}
);
2019-12-18 23:24:54 +13:00
$utopia->get('/v1/projects/:projectId/webhooks')
->desc('List Webhooks')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listWebhooks')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->action(
function ($projectId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
$webhooks = $project->getAttribute('webhooks', []);
foreach ($webhooks as $webhook) { /* @var $webhook Document */
$httpPass = json_decode($webhook->getAttribute('httpPass', '{}'), true);
if (empty($httpPass) || !isset($httpPass['version'])) {
continue;
}
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$webhook->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, hex2bin($httpPass['iv']), hex2bin($httpPass['tag'])));
}
$response->json($webhooks);
}
);
$utopia->get('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Get Webhook')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('webhookId', null, function () { return new UID(); }, 'Webhook unique ID.')
->action(
function ($projectId, $webhookId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$webhook = $project->search('$id', $webhookId, $project->getAttribute('webhooks', []));
2019-12-18 23:24:54 +13:00
if (empty($webhook) || !$webhook instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Webhook not found', 404);
}
$httpPass = json_decode($webhook->getAttribute('httpPass', '{}'), true);
if (!empty($httpPass) && isset($httpPass['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$webhook->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, hex2bin($httpPass['iv']), hex2bin($httpPass['tag'])));
}
$response->json($webhook->getArrayCopy());
}
);
$utopia->put('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Update Webhook')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('webhookId', null, function () { return new UID(); }, 'Webhook unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(256); }, 'Webhook name.')
->param('events', null, function () { return new ArrayList(new Text(256)); }, 'Webhook events list.')
->param('url', null, function () { return new Text(2000); }, 'Webhook URL.')
->param('security', null, function () { return new Range(0, 1); }, 'Certificate verification, 0 for disabled or 1 for enabled.')
->param('httpUser', '', function () { return new Text(256); }, 'Webhook HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Webhook HTTP password.', true)
2019-12-18 23:24:54 +13:00
->action(
function ($projectId, $webhookId, $name, $events, $url, $security, $httpUser, $httpPass) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => bin2hex($iv),
'tag' => bin2hex($tag),
'version' => '1',
]);
2020-02-17 20:16:11 +13:00
$webhook = $project->search('$id', $webhookId, $project->getAttribute('webhooks', []));
2019-12-18 23:24:54 +13:00
if (empty($webhook) || !$webhook instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Webhook not found', 404);
}
$webhook
->setAttribute('name', $name)
->setAttribute('events', $events)
->setAttribute('url', $url)
->setAttribute('security', (int) $security)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
;
if (false === $consoleDB->updateDocument($webhook->getArrayCopy())) {
throw new Exception('Failed saving webhook to DB', 500);
}
$response->json($webhook->getArrayCopy());
}
);
$utopia->delete('/v1/projects/:projectId/webhooks/:webhookId')
->desc('Delete Webhook')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteWebhook')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('webhookId', null, function () { return new UID(); }, 'Webhook unique ID.')
->action(
function ($projectId, $webhookId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$webhook = $project->search('$id', $webhookId, $project->getAttribute('webhooks', []));
2019-12-18 23:24:54 +13:00
if (empty($webhook) || !$webhook instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Webhook not found', 404);
}
2020-02-17 20:16:11 +13:00
if (!$consoleDB->deleteDocument($webhook->getId())) {
2019-12-18 23:24:54 +13:00
throw new Exception('Failed to remove webhook from DB', 500);
}
$response->noContent();
}
);
// Keys
2020-02-01 11:34:07 +13:00
$utopia->post('/v1/projects/:projectId/keys')
->desc('Create Key')
->label('scope', 'projects.write')
2019-12-18 23:24:54 +13:00
->label('sdk.namespace', 'projects')
2020-02-01 11:34:07 +13:00
->label('sdk.method', 'createKey')
2019-12-18 23:24:54 +13:00
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(256); }, 'Key name.')
->param('scopes', null, function () use ($scopes) { return new ArrayList(new WhiteList($scopes)); }, 'Key scopes list.')
2019-12-18 23:24:54 +13:00
->action(
function ($projectId, $name, $scopes) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
$key = $consoleDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_KEYS,
'$permissions' => [
'read' => ['team:'.$project->getAttribute('teamId', null)],
'write' => ['team:'.$project->getAttribute('teamId', null).'/owner', 'team:'.$project->getAttribute('teamId', null).'/developer'],
],
'name' => $name,
'scopes' => $scopes,
'secret' => bin2hex(random_bytes(128)),
]);
if (false === $key) {
throw new Exception('Failed saving key to DB', 500);
}
$project->setAttribute('keys', $key, Document::SET_TYPE_APPEND);
$project = $consoleDB->updateDocument($project->getArrayCopy());
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($key->getArrayCopy())
;
}
);
2020-02-01 11:34:07 +13:00
$utopia->get('/v1/projects/:projectId/keys')
->desc('List Keys')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listKeys')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->action(
function ($projectId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Project not found', 404);
}
$response->json($project->getAttribute('keys', [])); //FIXME make sure array objects return correctly
}
);
$utopia->get('/v1/projects/:projectId/keys/:keyId')
->desc('Get Key')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getKey')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('keyId', null, function () { return new UID(); }, 'Key unique ID.')
->action(
function ($projectId, $keyId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$key = $project->search('$id', $keyId, $project->getAttribute('keys', []));
2020-02-01 11:34:07 +13:00
if (empty($key) || !$key instanceof Document) {
2020-02-01 11:34:07 +13:00
throw new Exception('Key not found', 404);
}
$response->json($key->getArrayCopy());
}
);
2019-12-18 23:24:54 +13:00
$utopia->put('/v1/projects/:projectId/keys/:keyId')
->desc('Update Key')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateKey')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('keyId', null, function () { return new UID(); }, 'Key unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(256); }, 'Key name.')
2019-12-18 23:24:54 +13:00
->param('scopes', null, function () use ($scopes) { return new ArrayList(new WhiteList($scopes)); }, 'Key scopes list')
->action(
function ($projectId, $keyId, $name, $scopes) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$key = $project->search('$id', $keyId, $project->getAttribute('keys', []));
2019-12-18 23:24:54 +13:00
if (empty($key) || !$key instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Key not found', 404);
}
$key
->setAttribute('name', $name)
->setAttribute('scopes', $scopes)
;
if (false === $consoleDB->updateDocument($key->getArrayCopy())) {
throw new Exception('Failed saving key to DB', 500);
}
$response->json($key->getArrayCopy());
}
);
$utopia->delete('/v1/projects/:projectId/keys/:keyId')
->desc('Delete Key')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteKey')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('keyId', null, function () { return new UID(); }, 'Key unique ID.')
->action(
function ($projectId, $keyId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$key = $project->search('$id', $keyId, $project->getAttribute('keys', []));
2019-12-18 23:24:54 +13:00
if (empty($key) || !$key instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Key not found', 404);
}
2020-02-17 20:16:11 +13:00
if (!$consoleDB->deleteDocument($key->getId())) {
2019-12-18 23:24:54 +13:00
throw new Exception('Failed to remove key from DB', 500);
}
$response->noContent();
}
);
// Tasks
$utopia->post('/v1/projects/:projectId/tasks')
->desc('Create Task')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(256); }, 'Task name.')
->param('status', null, function () { return new WhiteList(['play', 'pause']); }, 'Task status.')
->param('schedule', null, function () { return new Cron(); }, 'Task schedule CRON syntax.')
->param('security', null, function () { return new Range(0, 1); }, 'Certificate verification, 0 for disabled or 1 for enabled.')
->param('httpMethod', '', function () { return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']); }, 'Task HTTP method.')
2019-12-18 23:24:54 +13:00
->param('httpUrl', '', function () { return new URL(); }, 'Task HTTP URL')
2020-02-10 18:54:26 +13:00
->param('httpHeaders', null, function () { return new ArrayList(new Text(256)); }, 'Task HTTP headers list.', true)
->param('httpUser', '', function () { return new Text(256); }, 'Task HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Task HTTP password.', true)
2019-12-18 23:24:54 +13:00
->action(
function ($projectId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
$cron = CronExpression::factory($schedule);
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => bin2hex($iv),
'tag' => bin2hex($tag),
'version' => '1',
]);
$task = $consoleDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_TASKS,
'$permissions' => [
'read' => ['team:'.$project->getAttribute('teamId', null)],
'write' => ['team:'.$project->getAttribute('teamId', null).'/owner', 'team:'.$project->getAttribute('teamId', null).'/developer'],
],
'name' => $name,
'status' => $status,
'schedule' => $schedule,
'updated' => time(),
'previous' => null,
'next' => $next,
'security' => (int) $security,
'httpMethod' => $httpMethod,
'httpUrl' => $httpUrl,
'httpHeaders' => $httpHeaders,
'httpUser' => $httpUser,
'httpPass' => $httpPass,
'log' => '{}',
'failures' => 0,
]);
if (false === $task) {
throw new Exception('Failed saving tasks to DB', 500);
}
$project->setAttribute('tasks', $task, Document::SET_TYPE_APPEND);
$project = $consoleDB->updateDocument($project->getArrayCopy());
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
if ($next) {
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy());
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($task->getArrayCopy())
;
}
);
2020-02-01 11:34:07 +13:00
$utopia->get('/v1/projects/:projectId/tasks')
->desc('List Tasks')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listTasks')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->action(
function ($projectId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Project not found', 404);
}
$tasks = $project->getAttribute('tasks', []);
foreach ($tasks as $task) { /* @var $task Document */
$httpPass = json_decode($task->getAttribute('httpPass', '{}'), true);
if (empty($httpPass) || !isset($httpPass['version'])) {
continue;
}
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$task->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, hex2bin($httpPass['iv']), hex2bin($httpPass['tag'])));
}
$response->json($tasks);
}
);
$utopia->get('/v1/projects/:projectId/tasks/:taskId')
->desc('Get Task')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('taskId', null, function () { return new UID(); }, 'Task unique ID.')
->action(
function ($projectId, $taskId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$task = $project->search('$id', $taskId, $project->getAttribute('tasks', []));
2020-02-01 11:34:07 +13:00
if (empty($task) || !$task instanceof Document) {
2020-02-01 11:34:07 +13:00
throw new Exception('Task not found', 404);
}
$httpPass = json_decode($task->getAttribute('httpPass', '{}'), true);
if (!empty($httpPass) && isset($httpPass['version'])) {
$key = $request->getServer('_APP_OPENSSL_KEY_V'.$httpPass['version']);
$task->setAttribute('httpPass', OpenSSL::decrypt($httpPass['data'], $httpPass['method'], $key, 0, hex2bin($httpPass['iv']), hex2bin($httpPass['tag'])));
}
$response->json($task->getArrayCopy());
}
);
2019-12-18 23:24:54 +13:00
$utopia->put('/v1/projects/:projectId/tasks/:taskId')
->desc('Update Task')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('taskId', null, function () { return new UID(); }, 'Task unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(256); }, 'Task name.')
->param('status', null, function () { return new WhiteList(['play', 'pause']); }, 'Task status.')
->param('schedule', null, function () { return new Cron(); }, 'Task schedule CRON syntax.')
->param('security', null, function () { return new Range(0, 1); }, 'Certificate verification, 0 for disabled or 1 for enabled.')
->param('httpMethod', '', function () { return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']); }, 'Task HTTP method.')
->param('httpUrl', '', function () { return new URL(); }, 'Task HTTP URL.')
->param('httpHeaders', null, function () { return new ArrayList(new Text(256)); }, 'Task HTTP headers list.', true)
->param('httpUser', '', function () { return new Text(256); }, 'Task HTTP user.', true)
->param('httpPass', '', function () { return new Text(256); }, 'Task HTTP password.', true)
2019-12-18 23:24:54 +13:00
->action(
function ($projectId, $taskId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$task = $project->search('$id', $taskId, $project->getAttribute('tasks', []));
2019-12-18 23:24:54 +13:00
if (empty($task) || !$task instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Task not found', 404);
}
$cron = CronExpression::factory($schedule);
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$tag = null;
$httpPass = json_encode([
'data' => OpenSSL::encrypt($httpPass, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
'method' => OpenSSL::CIPHER_AES_128_GCM,
'iv' => bin2hex($iv),
'tag' => bin2hex($tag),
'version' => '1',
]);
$task
->setAttribute('name', $name)
->setAttribute('status', $status)
->setAttribute('schedule', $schedule)
->setAttribute('updated', time())
->setAttribute('next', $next)
->setAttribute('security', (int) $security)
->setAttribute('httpMethod', $httpMethod)
->setAttribute('httpUrl', $httpUrl)
->setAttribute('httpHeaders', $httpHeaders)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
;
if (false === $consoleDB->updateDocument($task->getArrayCopy())) {
throw new Exception('Failed saving tasks to DB', 500);
}
if ($next) {
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy());
}
$response->json($task->getArrayCopy());
}
);
$utopia->delete('/v1/projects/:projectId/tasks/:taskId')
->desc('Delete Task')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteTask')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('taskId', null, function () { return new UID(); }, 'Task unique ID.')
->action(
function ($projectId, $taskId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$task = $project->search('$id', $taskId, $project->getAttribute('tasks', []));
2019-12-18 23:24:54 +13:00
if (empty($task) || !$task instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Task not found', 404);
}
2020-02-17 20:16:11 +13:00
if (!$consoleDB->deleteDocument($task->getId())) {
2019-12-18 23:24:54 +13:00
throw new Exception('Failed to remove tasks from DB', 500);
}
$response->noContent();
}
);
// Platforms
$utopia->post('/v1/projects/:projectId/platforms')
->desc('Create Platform')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createPlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
2020-02-10 18:54:26 +13:00
->param('type', null, function () { return new WhiteList(['web', 'ios', 'android', 'unity']); }, 'Platform type.')
->param('name', null, function () { return new Text(256); }, 'Platform name.')
->param('key', '', function () { return new Text(256); }, 'Package name for android or bundle ID for iOS.', true)
->param('store', '', function () { return new Text(256); }, 'App store or Google Play store ID.', true)
->param('url', '', function () { return new URL(); }, 'Platform client URL.', true)
2019-12-18 23:24:54 +13:00
->action(
function ($projectId, $type, $name, $key, $store, $url) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
$platform = $consoleDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
'$permissions' => [
'read' => ['team:'.$project->getAttribute('teamId', null)],
'write' => ['team:'.$project->getAttribute('teamId', null).'/owner', 'team:'.$project->getAttribute('teamId', null).'/developer'],
],
'type' => $type,
'name' => $name,
'key' => $key,
'store' => $store,
'url' => $url,
'dateCreated' => time(),
'dateUpdated' => time(),
]);
if (false === $platform) {
throw new Exception('Failed saving platform to DB', 500);
}
$project->setAttribute('platforms', $platform, Document::SET_TYPE_APPEND);
$project = $consoleDB->updateDocument($project->getArrayCopy());
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($platform->getArrayCopy())
;
}
);
2020-02-01 11:34:07 +13:00
$utopia->get('/v1/projects/:projectId/platforms')
->desc('List Platforms')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listPlatforms')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->action(
function ($projectId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Project not found', 404);
}
$platforms = $project->getAttribute('platforms', []);
$response->json($platforms);
}
);
$utopia->get('/v1/projects/:projectId/platforms/:platformId')
->desc('Get Platform')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getPlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('platformId', null, function () { return new UID(); }, 'Platform unique ID.')
->action(
function ($projectId, $platformId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2020-02-01 11:34:07 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$platform = $project->search('$id', $platformId, $project->getAttribute('platforms', []));
2020-02-01 11:34:07 +13:00
if (empty($platform) || !$platform instanceof Document) {
2020-02-01 11:34:07 +13:00
throw new Exception('Platform not found', 404);
}
$response->json($platform->getArrayCopy());
}
);
2019-12-18 23:24:54 +13:00
$utopia->put('/v1/projects/:projectId/platforms/:platformId')
->desc('Update Platform')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updatePlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('platformId', null, function () { return new UID(); }, 'Platform unique ID.')
2020-02-10 18:54:26 +13:00
->param('name', null, function () { return new Text(256); }, 'Platform name.')
->param('key', '', function () { return new Text(256); }, 'Package name for android or bundle ID for iOS.', true)
->param('store', '', function () { return new Text(256); }, 'App store or Google Play store ID.', true)
->param('url', '', function () { return new URL(); }, 'Platform client URL.', true)
2019-12-18 23:24:54 +13:00
->action(
function ($projectId, $platformId, $name, $key, $store, $url) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$platform = $project->search('$id', $platformId, $project->getAttribute('platforms', []));
2019-12-18 23:24:54 +13:00
if (empty($platform) || !$platform instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Platform not found', 404);
}
$platform
->setAttribute('name', $name)
->setAttribute('dateUpdated', time())
->setAttribute('key', $key)
->setAttribute('store', $store)
->setAttribute('url', $url)
;
if (false === $consoleDB->updateDocument($platform->getArrayCopy())) {
throw new Exception('Failed saving platform to DB', 500);
}
$response->json($platform->getArrayCopy());
}
);
$utopia->delete('/v1/projects/:projectId/platforms/:platformId')
->desc('Delete Platform')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deletePlatform')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('platformId', null, function () { return new UID(); }, 'Platform unique ID.')
->action(
function ($projectId, $platformId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
2020-02-17 20:16:11 +13:00
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
2019-12-18 23:24:54 +13:00
throw new Exception('Project not found', 404);
}
2020-02-17 20:16:11 +13:00
$platform = $project->search('$id', $platformId, $project->getAttribute('platforms', []));
2019-12-18 23:24:54 +13:00
if (empty($platform) || !$platform instanceof Document) {
2019-12-18 23:24:54 +13:00
throw new Exception('Platform not found', 404);
}
2020-02-17 20:16:11 +13:00
if (!$consoleDB->deleteDocument($platform->getId())) {
2019-12-18 23:24:54 +13:00
throw new Exception('Failed to remove platform from DB', 500);
}
2019-12-15 08:33:29 +13:00
$response->noContent();
}
2020-02-22 21:10:30 +13:00
);
// Domains
// $utopia->post('/v1/projects/:projectId/domains')
$utopia->get('/v1/projects/:projectId/xxx')
2020-02-22 21:10:30 +13:00
->desc('Create Domain')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createDomain')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domain', null, function () { return new DomainValidator(); }, 'Domain name.')
2020-02-22 21:10:30 +13:00
->action(
function ($projectId, $domain) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
throw new Exception('Project not found', 404);
}
$document = $project->search('domain', $domain, $project->getAttribute('domains', []));
if (!empty($document)) {
throw new Exception('Domain already exists', 409);
}
$domain = new Domain($domain);
2020-02-22 21:10:30 +13:00
$domain = $consoleDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_DOMAINS,
2020-02-22 21:10:30 +13:00
'$permissions' => [
'read' => ['team:'.$project->getAttribute('teamId', null)],
'write' => ['team:'.$project->getAttribute('teamId', null).'/owner', 'team:'.$project->getAttribute('teamId', null).'/developer'],
],
'updated' => time(),
'domain' => $domain->get(),
'tld' => $domain->getSuffix(),
'registerable' => $domain->getRegisterable(),
2020-02-22 21:10:30 +13:00
'verification' => false,
'certificateId' => null,
]);
if (false === $domain) {
throw new Exception('Failed saving domain to DB', 500);
2020-02-22 21:10:30 +13:00
}
$project->setAttribute('domains', $domain, Document::SET_TYPE_APPEND);
$project = $consoleDB->updateDocument($project->getArrayCopy());
if (false === $project) {
throw new Exception('Failed saving project to DB', 500);
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($domain->getArrayCopy())
;
}
);
$utopia->get('/v1/projects/:projectId/domains')
->desc('List Domains')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listDomains')
->param('projectId', '', function () { return new UID(); }, 'Project unique ID.')
->action(
function ($projectId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
throw new Exception('Project not found', 404);
}
$domains = $project->getAttribute('domains', []);
$response->json($domains);
}
);
$utopia->get('/v1/projects/:projectId/domains/:domainId')
->desc('Get Domain')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getDomain')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domainId', null, function () { return new UID(); }, 'Domain unique ID.')
->action(
function ($projectId, $domainId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
throw new Exception('Project not found', 404);
}
$domain = $project->search('$id', $domainId, $project->getAttribute('domains', []));
if (empty($domain) || !$domain instanceof Document) {
2020-02-22 21:10:30 +13:00
throw new Exception('Domain not found', 404);
}
$response->json($domain->getArrayCopy());
}
);
//$utopia->patch('/v1/projects/:projectId/domains/:domainId/verification')
$utopia->get('/v1/projects/:projectId/domains/:domainId/verification')
2020-02-22 21:10:30 +13:00
->desc('Update Domain Verification Status')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateDomainVerification')
2020-02-22 21:10:30 +13:00
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domainId', null, function () { return new UID(); }, 'Domain unique ID.')
->action(
function ($projectId, $domainId) use ($request, $response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
throw new Exception('Project not found', 404);
}
$domain = $project->search('$id', $domainId, $project->getAttribute('domains', []));
if (empty($domain) || !$domain instanceof Document) {
2020-02-22 21:10:30 +13:00
throw new Exception('Domain not found', 404);
}
$target = new Domain($request->getServer('_APP_DOMAINS_TARGET', ''));
if(!$target->isKnown() || $target->isTest()) {
throw new Exception('Unreachable CNAME target ('.$target->get().'), plesse use a domain with a public suffix.', 500);
}
2020-02-23 22:10:32 +13:00
if($domain->getAttribute('verification') === true) {
return $response->json($domain->getArrayCopy());
}
2020-02-22 21:10:30 +13:00
// Verify Domain with DNS records
$validator = new CNAME($target->get());
2020-02-22 21:10:30 +13:00
if(!$validator->isValid($domain->getAttribute('domain', ''))) {
2020-02-23 22:10:32 +13:00
throw new Exception('Failed to verify domain', 401);
2020-02-22 21:10:30 +13:00
}
$domain
->setAttribute('verification', true)
;
if (false === $consoleDB->updateDocument($domain->getArrayCopy())) {
throw new Exception('Failed saving domains to DB', 500);
}
// Issue a TLS certificate when domain is verified
Resque::enqueue('v1-certificates', 'CertificatesV1', ['document' => $domain->getArrayCopy()]);
2020-02-22 21:10:30 +13:00
$response->json($domain->getArrayCopy());
}
);
$utopia->delete('/v1/projects/:projectId/domains/:domainId')
->desc('Delete Domain')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteDomain')
->param('projectId', null, function () { return new UID(); }, 'Project unique ID.')
->param('domainId', null, function () { return new UID(); }, 'Domain unique ID.')
->action(
function ($projectId, $domainId) use ($response, $consoleDB) {
$project = $consoleDB->getDocument($projectId);
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS != $project->getCollection()) {
throw new Exception('Project not found', 404);
}
$domain = $project->search('$id', $domainId, $project->getAttribute('domains', []));
if (empty($domain) || !$domain instanceof Document) {
2020-02-22 21:10:30 +13:00
throw new Exception('Domain not found', 404);
}
if (!$consoleDB->deleteDocument($domain->getId())) {
throw new Exception('Failed to remove domains from DB', 500);
}
$response->noContent();
}
);
2020-02-23 22:10:32 +13:00
// $utopia->get('/v1/projects/x/certs')
// ->desc('List Domains')
// ->label('scope', 'public')
// ->action(
// function () use ($response, $consoleDB) {
// \Database\Validator\Authorization::disable();
// $results = $consoleDB->getCollection([
// 'limit' => 50,
// 'offset' => 0,
// 'filters' => [
// '$collection='.Database::SYSTEM_COLLECTION_CERTIFICATES,
// ],
// ]);
// \Database\Validator\Authorization::reset();
// $response->json($results);
// }
// );