199 lines
8.1 KiB
PHP
199 lines
8.1 KiB
PHP
<?php
|
|
|
|
use Appwrite\Extend\Exception;
|
|
use Appwrite\Utopia\Response;
|
|
use Utopia\App;
|
|
use Utopia\Database\Database;
|
|
use Utopia\Database\Document;
|
|
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
|
use Utopia\Database\DateTime;
|
|
use Utopia\Database\Query;
|
|
use Utopia\Database\Validator\Authorization;
|
|
use Utopia\Database\Validator\UID;
|
|
use Utopia\Validator\Text;
|
|
use Utopia\Validator\WhiteList;
|
|
|
|
App::get('/v1/project/usage')
|
|
->desc('Get usage stats for a project')
|
|
->groups(['api'])
|
|
->label('scope', 'projects.read')
|
|
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
|
->label('sdk.namespace', 'project')
|
|
->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)
|
|
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true)
|
|
->inject('response')
|
|
->inject('dbForProject')
|
|
->action(function (string $range, Response $response, Database $dbForProject) {
|
|
$usage = [];
|
|
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
|
$periods = [
|
|
'24h' => [
|
|
'period' => '1h',
|
|
'limit' => 24,
|
|
],
|
|
'7d' => [
|
|
'period' => '1d',
|
|
'limit' => 7,
|
|
],
|
|
'30d' => [
|
|
'period' => '1d',
|
|
'limit' => 30,
|
|
],
|
|
'90d' => [
|
|
'period' => '1d',
|
|
'limit' => 90,
|
|
],
|
|
];
|
|
|
|
$metrics = [
|
|
'project.$all.network.requests',
|
|
'project.$all.network.bandwidth',
|
|
'project.$all.storage.size',
|
|
'users.$all.count.total',
|
|
'databases.$all.count.total',
|
|
'documents.$all.count.total',
|
|
'executions.$all.compute.total',
|
|
'buckets.$all.count.total'
|
|
];
|
|
|
|
$stats = [];
|
|
|
|
Authorization::skip(function () use ($dbForProject, $periods, $range, $metrics, &$stats) {
|
|
foreach ($metrics as $metric) {
|
|
$limit = $periods[$range]['limit'];
|
|
$period = $periods[$range]['period'];
|
|
|
|
$requestDocs = $dbForProject->find('stats', [
|
|
Query::equal('period', [$period]),
|
|
Query::equal('metric', [$metric]),
|
|
Query::limit($limit),
|
|
Query::orderDesc('time'),
|
|
]);
|
|
|
|
$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
|
|
$diff = match ($period) { // convert period to seconds for unix timestamp math
|
|
'1h' => 3600,
|
|
'1d' => 86400,
|
|
};
|
|
$stats[$metric][] = [
|
|
'value' => 0,
|
|
'date' => DateTime::formatTz(DateTime::addSeconds(new \DateTime($stats[$metric][$last]['date'] ?? null), -1 * $diff)),
|
|
];
|
|
$backfill--;
|
|
}
|
|
$stats[$metric] = array_reverse($stats[$metric]);
|
|
}
|
|
});
|
|
|
|
$usage = new Document([
|
|
'range' => $range,
|
|
'requests' => $stats[$metrics[0]] ?? [],
|
|
'network' => $stats[$metrics[1]] ?? [],
|
|
'storage' => $stats[$metrics[2]] ?? [],
|
|
'users' => $stats[$metrics[3]] ?? [],
|
|
'databases' => $stats[$metrics[4]] ?? [],
|
|
'documents' => $stats[$metrics[5]] ?? [],
|
|
'executions' => $stats[$metrics[6]] ?? [],
|
|
'buckets' => $stats[$metrics[7]] ?? [],
|
|
]);
|
|
}
|
|
|
|
$response->dynamic($usage, Response::MODEL_USAGE_PROJECT);
|
|
});
|
|
|
|
App::put('/v1/project/variables/:variableId')
|
|
->desc('Update Variable')
|
|
->groups(['api'])
|
|
->label('scope', 'projects.write')
|
|
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
|
->label('sdk.namespace', 'project')
|
|
->label('sdk.method', 'updateVariable')
|
|
->label('sdk.description', '/docs/references/project/update-variable.md')
|
|
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
|
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
|
->label('sdk.response.model', Response::MODEL_VARIABLE)
|
|
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
|
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
|
|
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true)
|
|
->inject('project')
|
|
->inject('response')
|
|
->inject('dbForProject')
|
|
->inject('dbForConsole')
|
|
->action(function (string $variableId, string $key, ?string $value, Document $project, Response $response, Database $dbForProject, Database $dbForConsole) {
|
|
$variable = $dbForProject->getDocument('variables', $variableId);
|
|
if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') {
|
|
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
|
}
|
|
|
|
$variable
|
|
->setAttribute('key', $key)
|
|
->setAttribute('value', $value ?? $variable->getAttribute('value'))
|
|
->setAttribute('search', implode(' ', [$variableId, $key, 'project']));
|
|
|
|
try {
|
|
$dbForProject->updateDocument('variables', $variable->getId(), $variable);
|
|
} catch (DuplicateException $th) {
|
|
throw new Exception(Exception::VARIABLE_ALREADY_EXISTS);
|
|
}
|
|
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
|
|
|
$functions = $dbForProject->find('functions', [
|
|
Query::limit(APP_LIMIT_SUBQUERY)
|
|
]);
|
|
|
|
foreach ($functions as $function) {
|
|
$dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false));
|
|
}
|
|
|
|
$dbForProject->deleteCachedDocument('projects', $project->getId());
|
|
|
|
$response->dynamic($variable, Response::MODEL_VARIABLE);
|
|
});
|
|
|
|
App::delete('/v1/project/variables/:variableId')
|
|
->desc('Delete Variable')
|
|
->groups(['api'])
|
|
->label('scope', 'projects.write')
|
|
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
|
->label('sdk.namespace', 'project')
|
|
->label('sdk.method', 'deleteVariable')
|
|
->label('sdk.description', '/docs/references/project/delete-variable.md')
|
|
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
|
->label('sdk.response.model', Response::MODEL_NONE)
|
|
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
|
->inject('project')
|
|
->inject('response')
|
|
->inject('dbForProject')
|
|
->action(function (string $variableId, Document $project, Response $response, Database $dbForProject) {
|
|
$variable = $dbForProject->getDocument('variables', $variableId);
|
|
if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') {
|
|
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
|
}
|
|
|
|
$functions = $dbForProject->find('functions', [
|
|
Query::limit(APP_LIMIT_SUBQUERY)
|
|
]);
|
|
|
|
foreach ($functions as $function) {
|
|
$dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false));
|
|
}
|
|
|
|
$dbForProject->deleteDocument('variables', $variable->getId());
|
|
$dbForProject->deleteCachedDocument('projects', $project->getId());
|
|
|
|
$response->noContent();
|
|
});
|