diff --git a/Dockerfile b/Dockerfile index c464885054..7f5df76148 100755 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \ --no-plugins --no-scripts --prefer-dist \ `if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi` -FROM node:16.13.2-alpine3.15 as node +FROM node:16.14.2-alpine3.15 as node WORKDIR /usr/local/src/ @@ -30,8 +30,8 @@ ARG DEBUG=false ENV DEBUG=$DEBUG ENV PHP_REDIS_VERSION=5.3.7 \ - PHP_MONGODB_VERSION=1.9.1 \ - PHP_SWOOLE_VERSION=v4.8.7 \ + PHP_MONGODB_VERSION=1.13.0 \ + PHP_SWOOLE_VERSION=v4.8.9 \ PHP_IMAGICK_VERSION=3.7.0 \ PHP_YAML_VERSION=2.2.2 \ PHP_MAXMINDDB_VERSION=v1.11.0 diff --git a/app/config/collections.php b/app/config/collections.php index 3e3de4c7bd..e01b4d36b1 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -2425,7 +2425,7 @@ $collections = [ '$id' => 'value', 'type' => Database::VAR_INTEGER, 'format' => '', - 'size' => 0, + 'size' => 8, 'signed' => false, 'required' => true, 'default' => null, diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 200b845987..4b7db25b7b 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -838,6 +838,7 @@ App::put('/v1/account/sessions/magic-url') } $user + ->setAttribute('emailVerification', true) ->setAttribute('sessions', $session, Document::SET_TYPE_APPEND) ->setAttribute('tokens', $tokens); @@ -868,9 +869,7 @@ App::put('/v1/account/sessions/magic-url') ->setStatusCode(Response::STATUS_CODE_CREATED) ; - $countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))])) - ? $countries[strtoupper($session->getAttribute('countryCode'))] - : $locale->getText('locale.country.unknown'); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) @@ -1013,9 +1012,7 @@ App::post('/v1/account/sessions/anonymous') ->setStatusCode(Response::STATUS_CODE_CREATED) ; - $countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))])) - ? $countries[strtoupper($session->getAttribute('countryCode'))] - : $locale->getText('locale.country.unknown'); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', true) @@ -1280,15 +1277,13 @@ App::get('/v1/account/sessions/:sessionId') $sessions = $user->getAttribute('sessions', []); $sessionId = ($sessionId === 'current') - ? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret) - : $sessionId; + ? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret) + : $sessionId; foreach ($sessions as $session) {/** @var Document $session */ if ($sessionId == $session->getId()) { - $countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))])) - ? $countries[strtoupper($session->getAttribute('countryCode'))] - : $locale->getText('locale.country.unknown'); + $countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')); $session ->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret))) @@ -1622,7 +1617,7 @@ App::delete('/v1/account/sessions/:sessionId') if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too $session ->setAttribute('current', true) - ->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))])) ? $countries[strtoupper($session->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown')) + ->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))) ; if (!Config::getParam('domainVerification')) { @@ -1806,7 +1801,7 @@ App::delete('/v1/account/sessions') $session ->setAttribute('current', false) - ->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))])) ? $countries[strtoupper($session->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown')) + ->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'))) ; if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index bc57aa8ccb..dcb506faeb 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -214,24 +214,6 @@ App::get('/v1/health/queue/logs') $response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); }, ['response']); -App::get('/v1/health/queue/usage') - ->desc('Get Usage Queue') - ->groups(['api', 'health']) - ->label('scope', 'health.read') - ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) - ->label('sdk.namespace', 'health') - ->label('sdk.method', 'getQueueUsage') - ->label('sdk.description', '/docs/references/health/get-queue-usage.md') - ->label('sdk.response.code', Response::STATUS_CODE_OK) - ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE) - ->inject('response') - ->action(function ($response) { - /** @var Appwrite\Utopia\Response $response */ - - $response->dynamic(new Document([ 'size' => Resque::size(Event::USAGE_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE); - }, ['response']); - App::get('/v1/health/queue/certificates') ->desc('Get Certificates Queue') ->groups(['api', 'health']) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index f7100a88a2..8074736638 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -77,6 +77,9 @@ App::post('/v1/projects') } $projectId = ($projectId == 'unique()') ? $dbForConsole->getId() : $projectId; + if($projectId === 'console') { + throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT); + } $project = $dbForConsole->createDocument('projects', new Document([ '$id' => $projectId == 'unique()' ? $dbForConsole->getId() : $projectId, '$read' => ['team:' . $teamId], diff --git a/app/db/SQL/all.sql b/app/db/SQL/all.sql deleted file mode 100644 index 63ec92f42b..0000000000 --- a/app/db/SQL/all.sql +++ /dev/null @@ -1,90 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `appwrite` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; - -USE `appwrite`; - -CREATE TABLE IF NOT EXISTS `template.abuse.abuse` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `_key` varchar(255) NOT NULL, - `_time` int(11) NOT NULL, - `_count` int(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`id`), - UNIQUE KEY `unique1` (`_key`,`_time`), - KEY `index1` (`_key`,`_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -CREATE TABLE IF NOT EXISTS `template.audit.audit` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `userId` varchar(45) NOT NULL, - `event` varchar(45) NOT NULL, - `resource` varchar(45) DEFAULT NULL, - `userAgent` text NOT NULL, - `ip` varchar(45) NOT NULL, - `location` varchar(45) DEFAULT NULL, - `time` datetime NOT NULL, - `data` longtext DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `id_UNIQUE` (`id`), - KEY `index_1` (`userId`), - KEY `index_2` (`event`), - KEY `index_3` (`resource`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -CREATE TABLE IF NOT EXISTS `template.database.documents` ( - `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Unique ID for each node', - `uid` varchar(45) DEFAULT NULL, - `status` int(11) NOT NULL DEFAULT 0, - `createdAt` datetime DEFAULT NULL, - `updatedAt` datetime DEFAULT NULL, - `signature` varchar(32) NOT NULL, - `revision` varchar(45) NOT NULL, - `permissions` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `id_UNIQUE` (`id`), - UNIQUE KEY `index2` (`uid`), - KEY `index3` (`signature`,`uid`,`revision`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -CREATE TABLE IF NOT EXISTS `template.database.properties` ( - `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', - `documentUid` varchar(45) NOT NULL COMMENT 'Unique UID foreign key', - `documentRevision` varchar(45) NOT NULL, - `key` varchar(32) NOT NULL COMMENT 'Property key name', - `value` text NOT NULL COMMENT 'Value of property', - `primitive` varchar(32) NOT NULL COMMENT 'Primitive type of property value', - `array` tinyint(4) NOT NULL DEFAULT 0, - `order` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `index1` (`documentUid`), - KEY `index2` (`key`,`value`(5)), - FULLTEXT KEY `index3` (`value`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -CREATE TABLE IF NOT EXISTS `template.database.relationships` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `revision` varchar(45) NOT NULL, - `start` varchar(45) NOT NULL COMMENT 'Unique UID foreign key', - `end` varchar(45) NOT NULL COMMENT 'Unique UID foreign key', - `key` varchar(256) NOT NULL, - `path` int(11) NOT NULL DEFAULT 0, - `array` tinyint(4) NOT NULL DEFAULT 0, - `order` int(11) NOT NULL DEFAULT 0, - PRIMARY KEY (`id`), - KEY `relationships_start_nodes_id_idx` (`start`), - KEY `relationships_end_nodes_id_idx` (`end`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -CREATE TABLE IF NOT EXISTS `template.database.unique` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `key` varchar(128) DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `index1` (`key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -/* Default App */ - -CREATE TABLE IF NOT EXISTS `app_console.database.documents` LIKE `template.database.documents`; -CREATE TABLE IF NOT EXISTS `app_console.database.properties` LIKE `template.database.properties`; -CREATE TABLE IF NOT EXISTS `app_console.database.relationships` LIKE `template.database.relationships`; -CREATE TABLE IF NOT EXISTS `app_console.database.unique` LIKE `template.database.unique`; -CREATE TABLE IF NOT EXISTS `app_console.audit.audit` LIKE `template.audit.audit`; -CREATE TABLE IF NOT EXISTS `app_console.abuse.abuse` LIKE `template.abuse.abuse`; \ No newline at end of file diff --git a/app/executor.php b/app/executor.php index e9f4c21391..5183b49e96 100644 --- a/app/executor.php +++ b/app/executor.php @@ -408,7 +408,7 @@ App::post('/v1/execution') ->desc('Create an execution') ->param('runtimeId', '', new Text(64), 'The runtimeID to execute') ->param('vars', [], new Assoc(), 'Environment variables required for the build') - ->param('data', '{}', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true) + ->param('data', '', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true) ->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.') ->inject('activeRuntimes') ->inject('response') diff --git a/app/init.php b/app/init.php index fd509297f6..d4bb38c5b4 100644 --- a/app/init.php +++ b/app/init.php @@ -181,7 +181,7 @@ if(!empty($user) || !empty($pass)) { */ Database::addFilter('casting', function($value) { - return json_encode(['value' => $value]); + return json_encode(['value' => $value], JSON_PRESERVE_ZERO_FRACTION); }, function($value) { if (is_null($value)) { diff --git a/app/realtime.php b/app/realtime.php index 8d36069edb..76b9af5a78 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -163,28 +163,6 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume * Save current connections to the Database every 5 seconds. */ Timer::tick(5000, function () use ($register, $stats, &$statsDocument, $logError) { - /** @var Document $statsDocument */ - foreach ($stats as $projectId => $value) { - $connections = $stats->get($projectId, 'connections') ?? 0; - $messages = $stats->get($projectId, 'messages' ?? 0); - - $usage = new Event('v1-usage', 'UsageV1'); - $usage - ->setParam('projectId', $projectId) - ->setParam('realtimeConnections', $connections) - ->setParam('realtimeMessages', $messages) - ->setParam('networkRequestSize', 0) - ->setParam('networkResponseSize', 0); - - $stats->set($projectId, [ - 'messages' => 0, - 'connections' => 0 - ]); - - if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { - $usage->trigger(); - } - } $payload = []; foreach ($stats as $projectId => $value) { $payload[$projectId] = $stats->get($projectId, 'connectionsTotal'); diff --git a/app/tasks/usage.php b/app/tasks/usage.php index aa8dd2371c..829914a706 100644 --- a/app/tasks/usage.php +++ b/app/tasks/usage.php @@ -418,7 +418,7 @@ $cli // Get total storage $dbForProject->setNamespace('_' . $projectId); - $storageTotal = $dbForProject->sum('deployments', 'size'); + $deploymentsTotal = $dbForProject->sum('deployments', 'size'); $time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes $id = \md5($time . '_30m_storage.deployments.total'); //Construct unique id for each metric using time, period and metric @@ -431,14 +431,14 @@ $cli 'period' => '30m', 'time' => $time, 'metric' => 'storage.deployments.total', - 'value' => $storageTotal, + 'value' => $deploymentsTotal, 'type' => 1, ])); } else { $dbForProject->updateDocument( 'stats', $document->getId(), - $document->setAttribute('value', $storageTotal) + $document->setAttribute('value', $deploymentsTotal) ); } $time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day @@ -450,14 +450,14 @@ $cli 'period' => '1d', 'time' => $time, 'metric' => 'storage.deployments.total', - 'value' => $storageTotal, + 'value' => $deploymentsTotal, 'type' => 1, ])); } else { $dbForProject->updateDocument( 'stats', $document->getId(), - $document->setAttribute('value', $storageTotal) + $document->setAttribute('value', $deploymentsTotal) ); } } catch(\Exception $e) { @@ -714,7 +714,7 @@ $cli } /** - * Inserting project level sums for sub collections like storage.total + * Inserting project level sums for sub collections like storage.files.total */ foreach ($subCollectionTotals as $subCollection => $count) { $dbForProject->setNamespace("_{$projectId}"); @@ -754,6 +754,44 @@ $cli $dbForProject->updateDocument('stats', $document->getId(), $document->setAttribute('value', $count)); } + + // aggregate storage.total = storage.files.total + storage.deployments.total + if($metricPrefix === 'storage' && $subCollection === 'files') { + $metric = 'storage.total'; + $time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes + $id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric + $document = $dbForProject->getDocument('stats', $id); + if ($document->isEmpty()) { + $dbForProject->createDocument('stats', new Document([ + '$id' => $id, + 'time' => $time, + 'period' => '30m', + 'metric' => $metric, + 'value' => $count + $deploymentsTotal, + 'type' => 1, + ])); + } else { + $dbForProject->updateDocument('stats', $document->getId(), + $document->setAttribute('value', $count + $deploymentsTotal)); + } + + $time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day + $id = \md5($time . '_1d_' . $metric); //Construct unique id for each metric using time, period and metric + $document = $dbForProject->getDocument('stats', $id); + if ($document->isEmpty()) { + $dbForProject->createDocument('stats', new Document([ + '$id' => $id, + 'time' => $time, + 'period' => '1d', + 'metric' => $metric, + 'value' => $count + $deploymentsTotal, + 'type' => 1, + ])); + } else { + $dbForProject->updateDocument('stats', $document->getId(), + $document->setAttribute('value', $count + $deploymentsTotal)); + } + } } } catch (\Exception$e) { Console::warning("Failed to save database counters data for project {$collection}: {$e->getMessage()}"); diff --git a/app/views/console/database/collection.phtml b/app/views/console/database/collection.phtml index 1bdef71d18..eb045c9f2c 100644 --- a/app/views/console/database/collection.phtml +++ b/app/views/console/database/collection.phtml @@ -621,7 +621,7 @@ $logs = $this->getParam('logs', null); data-failure-param-alert-text="Failed to create attribute" data-failure-param-alert-classname="error" @reset="array = required = false" - x-data="{ array: false, required: false }"> + x-data="{ array: false, required: false, size: null }"> @@ -631,7 +631,7 @@ $logs = $this->getParam('logs', null);
Allowed Characters A-Z, a-z, 0-9, and non-leading underscore, hyphen and dot
- +
  Required @@ -643,7 +643,7 @@ $logs = $this->getParam('logs', null); @@ -197,6 +202,8 @@ $logs = $this->getParam('logs', null); :placeholder="attr.default" :name="attr.key" :required="attr.required" + :min="attr.min" + :max="attr.max" x-model="doc[attr.key][index]" data-cast-to="integer" /> @@ -207,6 +214,8 @@ $logs = $this->getParam('logs', null); :placeholder="attr.default" :name="attr.key" :required="attr.required" + :min="attr.min" + :max="attr.max" x-model="doc[attr.key][index]" data-cast-to="float" /> @@ -226,6 +235,7 @@ $logs = $this->getParam('logs', null); :placeholder="attr.default" :name="attr.key" :required="attr.required" + :maxlength="attr.size" x-model="doc[attr.key][index]" data-cast-to="string"> @@ -267,9 +277,9 @@ $logs = $this->getParam('logs', null); :required="attr.required" :name="attr.key" data-cast-to="string"> -