diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index bd8d9d5f7..d992b759c 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -18,7 +18,7 @@ use Utopia\Database\DateTime; App::get('/v1/project/usage') ->desc('Get usage stats for a project') - ->groups(['api']) + ->groups(['api', 'usage']) ->label('scope', 'projects.read') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.namespace', 'project') @@ -30,94 +30,76 @@ App::get('/v1/project/usage') ->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' - ]; + $periods = Config::getParam('usage', []); + $stats = $usage = []; + $days = $periods[$range]; + $metrics = [ + METRIC_NETWORK_REQUESTS, + METRIC_NETWORK_INBOUND, + METRIC_NETWORK_OUTBOUND, + METRIC_EXECUTIONS, + METRIC_DOCUMENTS, + METRIC_DATABASES, + METRIC_USERS, + METRIC_BUCKETS, + METRIC_FILES_STORAGE + ]; - $stats = []; + Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { + foreach ($metrics as $metric) { + $limit = $days['limit']; + $period = $days['period']; + $results = $dbForProject->find('stats', [ + Query::equal('period', [$period]), + Query::equal('metric', [$metric]), + Query::limit($limit), + Query::orderDesc('time'), + ]); - 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]); + $stats[$metric] = []; + foreach ($results as $result) { + $stats[$metric][$result->getAttribute('time')] = [ + 'value' => $result->getAttribute('value'), + ]; } - }); + } + }); - $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]] ?? [], - ]); + + $format = match ($days['period']) { + '1h' => 'Y-m-d\TH:00:00.000P', + '1d' => 'Y-m-d\T00:00:00.000P', + }; + + foreach ($metrics as $metric) { + $usage[$metric] = []; + $leap = time() - ($days['limit'] * $days['factor']); + while ($leap < time()) { + $leap += $days['factor']; + $formatDate = date($format, $leap); + $usage[$metric][] = [ + 'value' => $stats[$metric][$formatDate]['value'] ?? 0, + 'date' => $formatDate, + ]; + } } - $response->dynamic($usage, Response::MODEL_USAGE_PROJECT); + + $response->dynamic(new Document([ + 'range' => $range, + 'requestsTotal' => ($usage[$metrics[0]]), + 'network' => ($usage[$metrics[1]] + $usage[$metrics[2]]), + 'executionsTotal' => $usage[$metrics[3]], + 'documentsTotal' => $usage[$metrics[4]], + 'databasesTotal' => $usage[$metrics[5]], + 'usersTotal' => $usage[$metrics[6]], + 'bucketsTotal' => $usage[$metrics[7]], + 'filesStorage' => $usage[$metrics[8]], + ]), Response::MODEL_USAGE_PROJECT); }); + // Variables App::post('/v1/project/variables') diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index b8637b582..ddcc19f4c 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -721,11 +721,6 @@ App::delete('/v1/projects/:projectId') ->inject('dbForConsole') ->inject('queueForDeletes') ->action(function (string $projectId, Response $response, Document $user, Database $dbForConsole, Delete $queueForDeletes) { - - if (!Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password - throw new Exception(Exception::USER_INVALID_CREDENTIALS); - } - $project = $dbForConsole->getDocument('projects', $projectId); if ($project->isEmpty()) { @@ -997,6 +992,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') $response->noContent(); }); +// Keys App::post('/v1/projects/:projectId/keys') ->desc('Create Key') ->groups(['api', 'projects']) diff --git a/app/init.php b/app/init.php index f22fe089a..46d90cf12 100644 --- a/app/init.php +++ b/app/init.php @@ -54,7 +54,6 @@ use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; use Utopia\Messaging\Adapters\SMS\Twilio; use Utopia\Messaging\Adapters\SMS\Vonage; -use Utopia\Queue\Server; use Utopia\Registry\Registry; use Utopia\Storage\Device; use Utopia\Storage\Device\Backblaze; @@ -70,7 +69,6 @@ use Utopia\Pools\Group; use Utopia\Pools\Pool; use Ahc\Jwt\JWT; use Ahc\Jwt\JWTException; -use Appwrite\Auth\OAuth2\Github; use Appwrite\Event\Build; use Appwrite\Event\Certificate; use Appwrite\Event\Func; @@ -240,6 +238,7 @@ Config::load('providers', __DIR__ . '/config/providers.php'); Config::load('platforms', __DIR__ . '/config/platforms.php'); Config::load('collections', __DIR__ . '/config/collections.php'); Config::load('runtimes', __DIR__ . '/config/runtimes.php'); +Config::load('runtimes-v2', __DIR__ . '/config/runtimes-v2.php'); Config::load('usage', __DIR__ . '/config/usage.php'); Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index a78e56bed..7ca1e8564 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -136,6 +136,10 @@ class Deletes extends Action case DELETE_TYPE_SESSIONS: $this->deleteExpiredSessions($dbForConsole, $getProjectDB); break; + case DELETE_TYPE_CERTIFICATES: + $document = new Document($this->args['document']); + $this->deleteCertificates($document); + break; case DELETE_TYPE_USAGE: $this->deleteUsageStats($dbForConsole, $getProjectDB, $hourlyUsageRetentionDatetime); break;