From 038aeb01fb39d41b3886c81452174f83f4c0f788 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Fri, 27 Aug 2021 01:01:37 +0530 Subject: [PATCH] feat(usage): added response models for projects API --- app/controllers/api/projects.php | 85 +++++++---------- src/Appwrite/Utopia/Response.php | 3 + .../Utopia/Response/Model/ProjectUsage.php | 91 +++++++++++++++++++ 3 files changed, 125 insertions(+), 54 deletions(-) create mode 100644 src/Appwrite/Utopia/Response/Model/ProjectUsage.php diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index d4a8f86846..e8551c29ce 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -223,6 +223,9 @@ App::get('/v1/projects/:projectId/usage') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'projects') ->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_PROJECT_USAGE) ->param('projectId', '', new UID(), 'Project unique ID.') ->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d'], true), 'Date range.', true) ->inject('response') @@ -241,11 +244,11 @@ App::get('/v1/projects/:projectId/usage') throw new Exception('Project not found', 404); } - $stats = []; + $usage = []; if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { $period = [ '24h' => [ - 'period' => '30m', + 'period' => '15m', 'limit' => 48, ], '7d' => [ @@ -266,7 +269,17 @@ App::get('/v1/projects/:projectId/usage') Authorization::disable(); - $metrics = ['requests', 'network', 'executions']; + $metrics = [ + 'requests', + 'network', + 'executions', + 'users.count', + 'database.documents.count', + 'database.collections.count', + 'storage.total' + ]; + + $stats = []; foreach ($metrics as $metric) { $requestDocs = $dbForInternal->find('stats', [ new Query('period', Query::TYPE_EQUAL, [$period[$range]['period']]), @@ -282,59 +295,23 @@ App::get('/v1/projects/:projectId/usage') } $stats[$metric] = array_reverse($stats[$metric]); - } + } + + Authorization::reset(); + + $usage = new Document([ + 'range' => $range, + 'requests' => $stats['requests'], + 'network' => $stats['network'], + 'functions' => $stats['executions'], + 'documents' => $stats['database.documents.count'], + 'collections' => $stats['database.collections.count'], + 'users' => $stats['users.count'], + 'storage' => $stats['storage.total'] + ]); } - $usersCount = $dbForInternal->findOne('stats', [new Query('metric', Query::TYPE_EQUAL, ['users.count'])], 0, ['time'], [Database::ORDER_DESC]); - $usersTotal = $usersCount ? $usersCount->getAttribute('value', 0) : 0; - - $documentsCount = $dbForInternal->findOne('stats', [new Query('metric', Query::TYPE_EQUAL, ['database.documents.count'])], 0, ['time'], [Database::ORDER_DESC]); - $documentsTotal = $documentsCount ? $documentsCount->getAttribute('value', 0) : 0; - - $collectionsCount = $dbForInternal->findOne('stats', [new Query('metric', Query::TYPE_EQUAL, ['database.collections.count'])], 0, ['time'], [Database::ORDER_DESC]); - $collectionsTotal = $collectionsCount ? $collectionsCount->getAttribute('value', 0) : 0; - - $storageTotal = $dbForInternal->findOne('stats', [new Query('metric', Query::TYPE_EQUAL, ['storage.total'])], 0, ['time'], [Database::ORDER_DESC]); - $storage = $storageTotal ? $storageTotal->getAttribute('value', 0) : 0; - - Authorization::reset(); - - $response->json([ - 'range' => $range, - 'requests' => [ - 'data' => $stats['requests'] ?? [], - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $stats['requests'] ?? [])), - ], - 'network' => [ - 'data' => \array_map(function ($value) {return ['value' => \round($value['value'] / 1000000, 2), 'date' => $value['date']];}, $stats['network'] ?? []), // convert bytes to mb - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $stats['network'] ?? [])), - ], - 'functions' => [ - 'data' => $stats['executions'] ?? [], - 'total' => \array_sum(\array_map(function ($item) { - return $item['value']; - }, $stats['executions'] ?? [])), - ], - 'documents' => [ - 'data' => [], - 'total' => $documentsTotal, - ], - 'collections' => [ - 'data' => [], - 'total' => $collectionsTotal, - ], - 'users' => [ - 'data' => [], - 'total' => $usersTotal, - ], - 'storage' => [ - 'total' => $storage, - ], - ]); + $response->dynamic($usage, Response::MODEL_PROJECT_USAGE); }); App::patch('/v1/projects/:projectId') diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index a1d0d404ed..c87c924807 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -47,6 +47,7 @@ use Appwrite\Utopia\Response\Model\Token; use Appwrite\Utopia\Response\Model\Webhook; use Appwrite\Utopia\Response\Model\Preferences; use Appwrite\Utopia\Response\Model\Mock; // Keep last +use Appwrite\Utopia\Response\Model\ProjectUsage; use Appwrite\Utopia\Response\Model\StorageUsage; use Appwrite\Utopia\Response\Model\UsersUsage; use stdClass; @@ -127,6 +128,7 @@ class Response extends SwooleResponse // Project const MODEL_PROJECT = 'project'; const MODEL_PROJECT_LIST = 'projectList'; + const MODEL_PROJECT_USAGE = 'projectUsage'; const MODEL_WEBHOOK = 'webhook'; const MODEL_WEBHOOK_LIST = 'webhookList'; const MODEL_KEY = 'key'; @@ -216,6 +218,7 @@ class Response extends SwooleResponse ->setModel(new Tag()) ->setModel(new Execution()) ->setModel(new Project()) + ->setModel(new ProjectUsage()) ->setModel(new Webhook()) ->setModel(new Key()) ->setModel(new Domain()) diff --git a/src/Appwrite/Utopia/Response/Model/ProjectUsage.php b/src/Appwrite/Utopia/Response/Model/ProjectUsage.php new file mode 100644 index 0000000000..deee3b78b1 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/ProjectUsage.php @@ -0,0 +1,91 @@ +addRule('range', [ + 'type' => self::TYPE_STRING, + 'description' => 'The time range of the usage stats.', + 'default' => '', + 'example' => '30d', + ]) + ->addRule('requests', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for number of requests.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('network', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for consumed bandwidth.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('functions', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for function executions.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('documents', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for number of documents.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('collections', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for number of collections.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('users', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for number of users.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ->addRule('functions', [ + 'type' => Response::MODEL_METRIC_LIST, + 'description' => 'Aggregated stats for the occupied storage size.', + 'default' => [], + 'example' => new stdClass, + 'array' => true + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'ProjectUsage'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_PROJECT_USAGE; + } +} \ No newline at end of file