diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index ef63c28f08..805fc6f53e 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -6,6 +6,7 @@ use Utopia\App; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Datetime as DateTimeValidator; use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Helpers\ID; use Utopia\Database\Helpers\Permission; @@ -26,14 +27,16 @@ App::get('/v1/project/usage') ->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', '30d', '90d'], true), 'Date range.', true) + ->param('startDate', '', new DateTimeValidator(), 'Starting date for the usage') + ->param('endDate', '', new DateTimeValidator(), 'End date for the usage') + ->param('period', '1d', new WhiteList(['1h', '1d']), 'Period used', true) ->inject('response') ->inject('dbForProject') - ->action(function (string $range, Response $response, Database $dbForProject) { - - $periods = Config::getParam('usage', []); + ->action(function (string $startDate, string $endDate, string $period, Response $response, Database $dbForProject) { $stats = $total = $usage = []; - $days = $periods[$range]; + $format = 'Y-m-d 00:00:00'; + $firstDay = (new DateTime($startDate))->format($format); + $lastDay = (new DateTime($endDate))->format($format); $metrics = [ 'total' => [ @@ -51,7 +54,22 @@ App::get('/v1/project/usage') ] ]; - Authorization::skip(function () use ($dbForProject, $days, $metrics, &$total, &$stats) { + $factor = match ($period) { + '1h' => 3600, + '1d' => 86400, + }; + + $limit = match ($period) { + '1h' => (new DateTime($endDate))->diff(new DateTime($startDate))->h, + '1d' => (new DateTime($endDate))->diff(new DateTime($startDate))->days + }; + + $format = match ($period) { + '1h' => 'Y-m-d\TH:00:00.000P', + '1d' => 'Y-m-d\T00:00:00.000P', + }; + + Authorization::skip(function () use ($dbForProject, $firstDay, $lastDay, $period, $metrics, &$total, &$stats) { foreach ($metrics['total'] as $metric) { $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), @@ -61,12 +79,11 @@ App::get('/v1/project/usage') } foreach ($metrics['period'] as $metric) { - $limit = $days['limit']; - $period = $days['period']; $results = $dbForProject->find('stats', [ Query::equal('metric', [$metric]), Query::equal('period', [$period]), - Query::limit($limit), + Query::greaterThanEqual('time', $firstDay), + Query::lessThan('time', $lastDay), Query::orderDesc('time'), ]); @@ -79,25 +96,20 @@ App::get('/v1/project/usage') } }); - $format = match ($days['period']) { - '1h' => 'Y-m-d\TH:00:00.000P', - '1d' => 'Y-m-d\T00:00:00.000P', - }; - - foreach ($metrics['period'] as $metric) { - $usage[$metric] = []; - $leap = time() - ($days['limit'] * $days['factor']); - while ($leap < time()) { - $leap += $days['factor']; - $formatDate = date($format, $leap); - $usage[$metric][] = [ + foreach ($metrics['period'] as $metric) { + $usage[$metric] = []; + $leap = time() - ($limit * $factor); + while ($leap < time()) { + $leap += $factor; + $formatDate = date($format, $leap); + $usage[$metric][] = [ 'value' => $stats[$metric][$formatDate]['value'] ?? 0, 'date' => $formatDate, - ]; + ]; + } } - } + $response->dynamic(new Document([ - 'range' => $range, 'requests' => ($usage[METRIC_NETWORK_REQUESTS]), 'network' => ($usage[METRIC_NETWORK_INBOUND] + $usage[METRIC_NETWORK_OUTBOUND]), 'executionsTotal' => $total[METRIC_EXECUTIONS], @@ -111,7 +123,6 @@ App::get('/v1/project/usage') // Variables - App::post('/v1/project/variables') ->desc('Create Variable') ->groups(['api']) diff --git a/src/Appwrite/Utopia/Response/Model/UsageProject.php b/src/Appwrite/Utopia/Response/Model/UsageProject.php index de16dcc114..35c9296a04 100644 --- a/src/Appwrite/Utopia/Response/Model/UsageProject.php +++ b/src/Appwrite/Utopia/Response/Model/UsageProject.php @@ -10,12 +10,6 @@ class UsageProject extends Model public function __construct() { $this - ->addRule('range', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'The time range of the usage stats.', - 'default' => '', - 'example' => '30d', - ]) ->addRule('executionsTotal', [ 'type' => self::TYPE_INTEGER, 'description' => 'Total aggregated number of function executions.', diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 77426a3830..694f0a61b0 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -7,10 +7,10 @@ use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideServer; use CURLFile; +use DateTime; use Tests\E2E\Services\Functions\FunctionsBase; use Utopia\Database\Helpers\Permission; use Utopia\Database\Helpers\Role; -use Utopia\Database\Validator\Datetime as DatetimeValidator; class UsageTest extends Scope { @@ -37,6 +37,19 @@ class UsageTest extends Scope } } + public static function getToday(): string + { + $date = new DateTime(); + return $date->format(self::$formatTz); + } + + public static function getTomorrow(): string + { + $date = new DateTime(); + $date->modify('+1 day'); + return $date->format(self::$formatTz); + } + public function testPrepareUsersStats(): array { $project = $this->getProject(true); @@ -107,8 +120,13 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_GET, - '/project/usage?range=24h', - $consoleHeaders + '/project/usage', + $consoleHeaders, + [ + 'period' => '1h', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] ); $res = $res['body']; @@ -265,11 +283,16 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_GET, - '/project/usage?range=30d', + '/project/usage', array_merge( $data['headers'], $data['consoleHeaders'] - ) + ), + [ + 'period' => '1d', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] ); $res = $res['body']; @@ -470,8 +493,13 @@ class UsageTest extends Scope $res = $this->client->call( Client::METHOD_GET, - '/project/usage?range=30d', - $data['consoleHeaders'] + '/project/usage', + $data['consoleHeaders'], + [ + 'period' => '1d', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] ); $res = $res['body']; diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 91fe2d97dc..8a24b220e1 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -8,6 +8,7 @@ use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\ProjectConsole; use Tests\E2E\Scopes\SideClient; use Tests\E2E\Client; +use Tests\E2E\General\UsageTest; use Utopia\Database\DateTime; use Utopia\Database\Helpers\ID; @@ -440,20 +441,20 @@ class ProjectsConsoleClientTest extends Scope */ public function testGetProjectUsage($data): array { - $id = $data['projectId'] ?? ''; - /** * Test for SUCCESS */ $response = $this->client->call(Client::METHOD_GET, '/project/usage', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + ], $this->getHeaders()), [ + 'startDate' => UsageTest::getToday(), + 'endDate' => UsageTest::getTomorrow(), + ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(9, count($response['body'])); + $this->assertEquals(8, count($response['body'])); $this->assertNotEmpty($response['body']); - $this->assertEquals('30d', $response['body']['range']); $this->assertIsArray($response['body']['requests']); $this->assertIsArray($response['body']['network']); $this->assertIsNumeric($response['body']['executionsTotal']);