diff --git a/CHANGES.md b/CHANGES.md index 0dd92eeff6..0f24324eeb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,7 +8,10 @@ - Renamed *Devices* to *Sessions* - Add Provider Icon to each Session - Add Anonymous Account Placeholder -- Upgraded telegraf docker image version to v1.1.0 +- Upgraded telegraf docker image version to v1.2.0 +- Added new environment variables to the `telegraf` service: + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT ## Bugs diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl index 561ce73855..c9b730f46e 100644 --- a/app/config/locale/templates/email-base.tpl +++ b/app/config/locale/templates/email-base.tpl @@ -56,13 +56,13 @@ .main { background: {{bg-content}}; - border-radius: 3px; + border-radius: 10px; width: 100%; } .wrapper { box-sizing: border-box; - padding: 20px; + padding: 30px 30px 15px 30px; } .content-block { @@ -97,16 +97,15 @@ .btn table td { background-color: {{bg-content}}; - border-radius: 5px; + border-radius: 20px; text-align: center; } .btn a { background-color: {{bg-content}}; - border: solid 1px {{bg-cta}}; - border-radius: 5px; + border-radius: 20px; box-sizing: border-box; - color: #3498db; + color: #577590; cursor: pointer; display: inline-block; font-size: 14px; @@ -123,45 +122,17 @@ .btn-primary a { background-color: {{bg-cta}}; - border-color: {{bg-cta}}; color: {{text-cta}}; } @media only screen and (max-width: 620px) { - table[class=body] h1 { - font-size: 28px !important; - margin-bottom: 10px !important; + .container { + padding: 0; + width: 100%; } - table[class=body] p { - font-size: 16px !important; - } - - table[class=body] .wrapper { - padding: 10px !important; - } - - table[class=body] .content { - padding: 0 !important; - } - - table[class=body] .container { - padding: 0 !important; - width: 100% !important; - } - - table[class=body] .main { - border-left-width: 0 !important; - border-radius: 0 !important; - border-right-width: 0 !important; - } - - table[class=body] .btn table { - width: 100% !important; - } - - table[class=body] .btn a { - width: 100% !important; + .btn-primary a { + font-size: 13px; } } @@ -198,12 +169,11 @@ } .btn-primary table td:hover { - background-color: {{bg-cta-hover}} !important; + opacity: 0.7 !important; } .btn-primary a:hover { - background-color: {{bg-cta-hover}} !important; - border-color: {{bg-cta-hover}} !important; + opacity: 0.7 !important; } } @@ -220,15 +190,17 @@ - +
- {{content}} - {{content}}
+ +   diff --git a/app/config/platforms.php b/app/config/platforms.php index deec77d98e..9f83e63028 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -109,19 +109,20 @@ return [ 'gitUserName' => 'appwrite', ], [ - 'key' => 'kotlin', - 'name' => 'Kotlin', - 'url' => '', - 'package' => '', - 'enabled' => false, - 'beta' => false, + 'key' => 'android', + 'name' => 'Android', + 'version' => '0.0.0-SNAPSHOT', + 'url' => 'https://github.com/appwrite/sdk-for-android', + 'package' => 'https://repo1.maven.org/maven2/io/appwrite/sdk-for-android/', + 'enabled' => true, + 'beta' => true, 'dev' => false, 'hidden' => false, 'family' => APP_PLATFORM_CLIENT, 'prism' => 'kotlin', - 'source' => false, - 'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git', - 'gitRepoName' => 'sdk-for-kotlin', + 'source' => \realpath(__DIR__ . '/../sdks/client-android'), + 'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git', + 'gitRepoName' => 'sdk-for-android', 'gitUserName' => 'appwrite', ], // [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 13639c9125..1801a26e39 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1466,17 +1466,16 @@ App::post('/v1/account/recovery') $cta = new Template(__DIR__.'/../../config/locale/templates/email-cta.tpl'); $body - ->setParam('{{content}}', $content->render()) + ->setParam('{{content}}', $content->render(false)) ->setParam('{{cta}}', $cta->render()) ->setParam('{{title}}', $locale->getText('account.emails.recovery.title')) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]'])) ->setParam('{{name}}', $profile->getAttribute('name')) ->setParam('{{redirect}}', $url) - ->setParam('{{bg-body}}', '#f6f6f6') + ->setParam('{{bg-body}}', '#f7f7f7') ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{bg-cta}}', '#3498db') - ->setParam('{{bg-cta-hover}}', '#34495e') + ->setParam('{{bg-cta}}', '#073b4c') ->setParam('{{text-content}}', '#000000') ->setParam('{{text-cta}}', '#ffffff') ; @@ -1669,17 +1668,16 @@ App::post('/v1/account/verification') $cta = new Template(__DIR__.'/../../config/locale/templates/email-cta.tpl'); $body - ->setParam('{{content}}', $content->render()) + ->setParam('{{content}}', $content->render(false)) ->setParam('{{cta}}', $cta->render()) ->setParam('{{title}}', $locale->getText('account.emails.verification.title')) ->setParam('{{direction}}', $locale->getText('settings.direction')) ->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]'])) ->setParam('{{name}}', $user->getAttribute('name')) ->setParam('{{redirect}}', $url) - ->setParam('{{bg-body}}', '#f6f6f6') + ->setParam('{{bg-body}}', '#f7f7f7') ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{bg-cta}}', '#3498db') - ->setParam('{{bg-cta-hover}}', '#34495e') + ->setParam('{{bg-cta}}', '#073b4c') ->setParam('{{text-content}}', '#000000') ->setParam('{{text-cta}}', '#ffffff') ; diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index dd1d4a0d69..dbbd59f8c3 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -267,7 +267,7 @@ App::get('/v1/health/anti-virus') 'status' => (@$antiVirus->ping()) ? 'online' : 'offline', 'version' => @$antiVirus->version(), ]); - } catch( RuntimeException $e) { + } catch( \Exception $e) { $response->json([ 'status' => 'offline', 'version' => '', diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index b3060eaf4b..c4fe8c8494 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -242,6 +242,7 @@ App::get('/v1/storage/files/:fileId/preview') ->param('fileId', '', new UID(), 'File unique ID') ->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true) ->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true) + ->param('gravity', Image::GRAVITY_CENTER, new WhiteList([Image::GRAVITY_CENTER, Image::GRAVITY_NORTH, Image::GRAVITY_NORTHWEST, Image::GRAVITY_NORTHEAST, Image::GRAVITY_WEST, Image::GRAVITY_EAST, Image::GRAVITY_SOUTHWEST, Image::GRAVITY_SOUTH, Image::GRAVITY_SOUTHEAST]), 'Image crop gravity', true) ->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true) ->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true) ->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true) @@ -254,7 +255,7 @@ App::get('/v1/storage/files/:fileId/preview') ->inject('response') ->inject('project') ->inject('projectDB') - ->action(function ($fileId, $width, $height, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $projectDB) { + ->action(function ($fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $projectDB) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $project */ @@ -342,7 +343,7 @@ App::get('/v1/storage/files/:fileId/preview') $image = new Image($source); - $image->crop((int) $width, (int) $height); + $image->crop((int) $width, (int) $height, $gravity); if (!empty($opacity) || $opacity==0) { $image->setOpacity($opacity); diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 598783128e..3b3039a0fd 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -434,7 +434,7 @@ App::post('/v1/teams/:teamId/memberships') $title = \sprintf($locale->getText('account.emails.invitation.title'), $team->getAttribute('name', '[TEAM-NAME]'), $project->getAttribute('name', ['[APP-NAME]'])); $body - ->setParam('{{content}}', $content->render()) + ->setParam('{{content}}', $content->render(false)) ->setParam('{{cta}}', $cta->render()) ->setParam('{{title}}', $title) ->setParam('{{direction}}', $locale->getText('settings.direction')) @@ -442,10 +442,9 @@ App::post('/v1/teams/:teamId/memberships') ->setParam('{{team}}', $team->getAttribute('name', '[TEAM-NAME]')) ->setParam('{{owner}}', $user->getAttribute('name', '')) ->setParam('{{redirect}}', $url) - ->setParam('{{bg-body}}', '#f6f6f6') + ->setParam('{{bg-body}}', '#f7f7f7') ->setParam('{{bg-content}}', '#ffffff') - ->setParam('{{bg-cta}}', '#3498db') - ->setParam('{{bg-cta-hover}}', '#34495e') + ->setParam('{{bg-cta}}', '#073b4c') ->setParam('{{text-content}}', '#000000') ->setParam('{{text-cta}}', '#ffffff') ; diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 49e201e1d7..9dd13e34e8 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -8,6 +8,7 @@ use Utopia\Validator\WhiteList; use Appwrite\Network\Validator\Email; use Utopia\Validator\Text; use Utopia\Validator\Range; +use Utopia\Validator\Boolean; use Utopia\Audit\Audit; use Utopia\Audit\Adapters\MySQL as AuditAdapter; use Appwrite\Auth\Auth; @@ -369,6 +370,43 @@ App::patch('/v1/users/:userId/status') $response->dynamic($user, Response::MODEL_USER); }); +App::patch('/v1/users/:userId/verification') + ->desc('Update Email Verification') + ->groups(['api', 'users']) + ->label('event', 'users.update.verification') + ->label('scope', 'users.write') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'users') + ->label('sdk.method', 'updateVerification') + ->label('sdk.description', '/docs/references/users/update-user-verification.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_USER) + ->param('userId', '', new UID(), 'User unique ID.') + ->param('emailVerification', false, new Boolean(), 'User Email Verification Status.') + ->inject('response') + ->inject('projectDB') + ->action(function ($userId, $emailVerification, $response, $projectDB) { + /** @var Appwrite\Utopia\Response $response */ + /** @var Appwrite\Database\Database $projectDB */ + + $user = $projectDB->getDocument($userId); + + if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + throw new Exception('User not found', 404); + } + + $user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [ + 'emailVerification' => $emailVerification, + ])); + + if (false === $user) { + throw new Exception('Failed saving user to DB', 500); + } + + $response->dynamic($user, Response::MODEL_USER); + }); + App::patch('/v1/users/:userId/prefs') ->desc('Update User Preferences') ->groups(['api', 'users']) diff --git a/app/http.php b/app/http.php index 154b88e5a1..7d56a9046b 100644 --- a/app/http.php +++ b/app/http.php @@ -12,26 +12,6 @@ use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; use Utopia\App; use Utopia\CLI\Console; -use Utopia\Config\Config; -use Utopia\Domains\Domain; - -// xdebug_start_trace('/tmp/trace'); - -Files::load(__DIR__ . '/../public'); - -include __DIR__ . '/controllers/general.php'; - -$domain = App::getEnv('_APP_DOMAIN', ''); - -Console::info('Issuing a TLS certificate for the master domain ('.$domain.') in 30 seconds. - Make sure your domain points to your server IP or restart your Appwrite server to try again.'); // TODO move this to installation script - -ResqueScheduler::enqueueAt(\time() + 30, 'v1-certificates', 'CertificatesV1', [ - 'document' => [], - 'domain' => $domain, - 'validateTarget' => false, - 'validateCNAME' => false, -]); $http = new Server("0.0.0.0", App::getEnv('PORT', 80)); @@ -101,8 +81,8 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $register->set('db', function () use (&$db) { return $db; }); - - $register->set('cache', function () use (&$redis) { // Register cache connection + + $register->set('cache', function () use (&$redis) { return $redis; }); diff --git a/app/init.php b/app/init.php index ab505d60f6..cb87697a83 100644 --- a/app/init.php +++ b/app/init.php @@ -161,19 +161,21 @@ $register->set('dbPool', function () { // Register DB connection return $pool; }); - $register->set('redisPool', function () { - $user = App::getEnv('_APP_REDIS_USER', ''); - $pass = App::getEnv('_APP_REDIS_PASS', ''); - $auth = []; - if ($user) { - $auth[] = $user; + $redisHost = App::getEnv('_APP_REDIS_HOST', ''); + $redisPort = App::getEnv('_APP_REDIS_PORT', ''); + $redisUser = App::getEnv('_APP_REDIS_USER', ''); + $redisPass = App::getEnv('_APP_REDIS_PASS', ''); + $redisAuth = []; + + if ($redisUser) { + $redisAuth[] = $redisUser; } - if ($pass) { - $auth[] = $pass; + if ($redisPass) { + $redisAuth[] = $redisPass; } - $pool = new RedisPool(10, App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''), $auth); + $pool = new RedisPool(10, $redisHost, $redisPort, $redisAuth); return $pool; }); diff --git a/app/realtime.php b/app/realtime.php index a125118654..6d94b2cc4a 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -1,336 +1,13 @@ set([ +$config = [ 'package_max_length' => 64000 // Default maximum Package Size (64kb) -]); +]; -$subscriptions = []; -$connections = []; - -$stats = new Table(4096, 1); -$stats->column('projectId', Table::TYPE_STRING, 64); -$stats->column('connections', Table::TYPE_INT); -$stats->column('connectionsTotal', Table::TYPE_INT); -$stats->column('messages', Table::TYPE_INT); -$stats->create(); - -/** - * Sends usage stats every 10 seconds. - */ -Timer::tick(10000, function () use (&$stats) { - /** @var Table $stats */ - foreach ($stats as $projectId => $value) { - if (empty($value['connections']) && empty($value['messages'])) { - continue; - } - - $connections = $value['connections']; - $messages = $value['messages']; - - $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, [ - 'projectId' => $projectId, - 'messages' => 0, - 'connections' => 0 - ]); - - if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { - $usage->trigger(); - } - } -}); - -$server->on('workerStart', function ($server, $workerId) use (&$subscriptions, &$register, &$stats) { - Console::success('Worker ' . $workerId . ' started succefully'); - - $attempts = 0; - $start = time(); - $redisPool = $register->get('redisPool'); - - /** - * Sending current connections to project channels on the console project every 5 seconds. - */ - $server->tick(5000, function () use (&$server, &$subscriptions, &$stats) { - if ( - array_key_exists('console', $subscriptions) - && array_key_exists('role:member', $subscriptions['console']) - && array_key_exists('project', $subscriptions['console']['role:member']) - ) { - $payload = []; - foreach ($stats as $projectId => $value) { - $payload[$projectId] = $value['connectionsTotal']; - } - foreach ($subscriptions['console']['role:member']['project'] as $connection => $value) { - $server->push( - $connection, - json_encode([ - 'event' => 'stats.connections', - 'channels' => ['project'], - 'timestamp' => time(), - 'payload' => $payload - ]), - SWOOLE_WEBSOCKET_OPCODE_TEXT, - SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS - ); - } - } - }); - - while ($attempts < 300) { - try { - if ($attempts > 0) { - Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . '). - Attempting restart in 5 seconds (attempt #' . $attempts . ')'); - sleep(5); // 5 sec delay between connection attempts - } - - /** @var Swoole\Coroutine\Redis $redis */ - $redis = $redisPool->get(); - - if ($redis->ping(true)) { - $attempts = 0; - Console::success('Pub/sub connection established (worker: ' . $workerId . ')'); - } else { - Console::error('Pub/sub failed (worker: ' . $workerId . ')'); - } - - $redis->subscribe(['realtime'], function ($redis, $channel, $payload) use ($server, $workerId, &$subscriptions, &$stats) { - /** - * Supported Resources: - * - Collection - * - Document - * - File - * - Account - * - Session - * - Team? (not implemented yet) - * - Membership? (not implemented yet) - * - Function - * - Execution - */ - $event = json_decode($payload, true); - - $receivers = Realtime::identifyReceivers($event, $subscriptions); - - - // Temporarily print debug logs by default for Alpha testing. - // if (App::isDevelopment() && !empty($receivers)) { - if (!empty($receivers)) { - Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers)); - Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers)); - Console::log("[Debug][Worker {$workerId}] Event: " . $payload); - } - - foreach ($receivers as $receiver) { - if ($server->exist($receiver) && $server->isEstablished($receiver)) { - $server->push( - $receiver, - json_encode($event['data']), - SWOOLE_WEBSOCKET_OPCODE_TEXT, - SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS - ); - } else { - $server->close($receiver); - } - } - if (($num = count($receivers)) > 0) { - $stats->incr($event['project'], 'messages', $num); - } - }); - } catch (\Throwable $th) { - Console::error('Pub/sub error: ' . $th->getMessage()); - $redisPool->put($redis); - $attempts++; - continue; - } - - $attempts++; - } - - Console::error('Failed to restart pub/sub...'); -}); - -$server->on('start', function (Server $server) { - Console::success('Server started succefully'); - - Console::info("Master pid {$server->master_pid}, manager pid {$server->manager_pid}"); - - // listen ctrl + c - Process::signal(2, function () use ($server) { - Console::log('Stop by Ctrl+C'); - $server->shutdown(); - }); -}); - -$server->on('open', function (Server $server, Request $request) use (&$connections, &$subscriptions, &$register, &$stats) { - $app = new App('UTC'); - $connection = $request->fd; - $request = new SwooleRequest($request); - - $db = $register->get('dbPool')->get(); - $redis = $register->get('redisPool')->get(); - - $register->set('db', function () use (&$db) { - return $db; - }); - - $register->set('cache', function () use (&$redis) { // Register cache connection - return $redis; - }); - - Console::info("Connection open (user: {$connection}, worker: {$server->getWorkerId()})"); - - App::setResource('request', function () use ($request) { - return $request; - }); - - App::setResource('response', function () { - return new Response(new SwooleResponse()); - }); - - try { - /** @var Appwrite\Database\Document $user */ - $user = $app->getResource('user'); - - /** @var Appwrite\Database\Document $project */ - $project = $app->getResource('project'); - - /** @var Appwrite\Database\Document $console */ - $console = $app->getResource('console'); - - /* - * Project Check - */ - if (empty($project->getId())) { - throw new Exception('Missing or unknown project ID', 1008); - } - - /* - * Abuse Check - * - * Abuse limits are connecting 128 times per minute and ip address. - */ - $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, function () use ($db) { - return $db; - }); - $timeLimit - ->setNamespace('app_' . $project->getId()) - ->setParam('{ip}', $request->getIP()) - ->setParam('{url}', $request->getURI()); - - $abuse = new Abuse($timeLimit); - - if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') { - throw new Exception('Too many requests', 1013); - } - - /* - * Validate Client Domain - Check to avoid CSRF attack. - * Adding Appwrite API domains to allow XDOMAIN communication. - * Skip this check for non-web platforms which are not required to send an origin header. - */ - $origin = $request->getOrigin(); - $originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', []))); - - if (!$originValidator->isValid($origin) && $project->getId() !== 'console') { - throw new Exception($originValidator->getDescription(), 1008); - } - - Realtime::setUser($user); - - $roles = Realtime::getRoles(); - $channels = Realtime::parseChannels($request->getQuery('channels', [])); - - /** - * Channels Check - */ - if (empty($channels)) { - throw new Exception('Missing channels', 1008); - } - - Realtime::subscribe($project->getId(), $connection, $roles, $subscriptions, $connections, $channels); - - $server->push($connection, json_encode($channels)); - - $stats->incr($project->getId(), 'connections'); - $stats->incr($project->getId(), 'connectionsTotal'); - } catch (\Throwable $th) { - $response = [ - 'code' => $th->getCode(), - 'message' => $th->getMessage() - ]; - // Temporarily print debug logs by default for Alpha testing. - //if (App::isDevelopment()) { - Console::error("[Error] Connection Error"); - Console::error("[Error] Code: " . $response['code']); - Console::error("[Error] Message: " . $response['message']); - //} - $server->push($connection, json_encode($response)); - $server->close($connection); - } - /** - * Put used PDO and Redis Connections back into their pools. - */ - /** @var PDOPool $dbPool */ - $dbPool = $register->get('dbPool'); - $dbPool->put($db); - - /** @var RedisPool $redisPool */ - $redisPool = $register->get('redisPool'); - $redisPool->put($redis); -}); - -$server->on('message', function (Server $server, Frame $frame) { - $server->push($frame->fd, 'Sending messages is not allowed.'); - $server->close($frame->fd); -}); - -$server->on('close', function (Server $server, int $connection) use (&$connections, &$subscriptions, &$stats) { - if (array_key_exists($connection, $connections)) { - $stats->decr($connections[$connection]['projectId'], 'connectionsTotal'); - } - Realtime::unsubscribe($connection, $subscriptions, $connections); - Console::info('Connection close: ' . $connection); -}); - -$server->start(); +$realtimeServer = new Server($register, config: $config); diff --git a/app/tasks/sdks.php b/app/tasks/sdks.php index 96d9dbf563..d5f858a7be 100644 --- a/app/tasks/sdks.php +++ b/app/tasks/sdks.php @@ -15,7 +15,7 @@ use Appwrite\SDK\Language\Deno; use Appwrite\SDK\Language\DotNet; use Appwrite\SDK\Language\Flutter; use Appwrite\SDK\Language\Go; -use Appwrite\SDK\Language\Java; +use Appwrite\SDK\Language\Kotlin; use Appwrite\SDK\Language\Swift; $cli @@ -134,9 +134,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND case 'go': $config = new Go(); break; - case 'java': - $config = new Java(); - break; case 'swift': $config = new Swift(); break; @@ -144,6 +141,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $cover = ''; $config = new DotNet(); break; + case 'android': + $config = new Kotlin(); + break; default: throw new Exception('Language "'.$language['key'].'" not supported'); break; @@ -155,9 +155,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $sdk ->setName($language['name']) - ->setDescription("Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. - Use the {$language['name']} SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. - For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)") + ->setNamespace('io appwrite') + ->setDescription("Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the {$language['name']} SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)") ->setShortDescription('Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API') ->setLicense($license) ->setLicenseContent($licenseContent) diff --git a/app/views/console/home/index.phtml b/app/views/console/home/index.phtml index db1b9c32fc..021cf89928 100644 --- a/app/views/console/home/index.phtml +++ b/app/views/console/home/index.phtml @@ -240,11 +240,11 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
  • -
  • - +
  • +
  • - +
  • @@ -329,6 +329,42 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true); + +