diff --git a/.gitignore b/.gitignore index f64ffdbba3..0494e8fba0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ /storage/uploads/ /tests/resources/storage/ /.idea/ -.DS_Store \ No newline at end of file +.DS_Store +.php_cs.cache \ No newline at end of file diff --git a/CHANGES b/CHANGES deleted file mode 100644 index d4a938244b..0000000000 --- a/CHANGES +++ /dev/null @@ -1,5 +0,0 @@ -Version 1.0.0 (NOT-RELEASED) -------------- - -Version 0.1.0 (PRE-RELEASE) -------------- diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000000..aee5e0ebab --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,23 @@ +# Version 0.2.0 (PRE-RELEASE) + +## Features + +* Added option to limit access to the Appwrite console +* Added option to disable abuse check and rate limits +* Added input field with the server API endpoint for easy access +* Added new OAuth providers for Google and Gitlab +* Added 8 new locales for locale service and email templates (no, pt-br, es, ua, ru, id, fi, cat) +* Improved test coverage for the project and synced DEV & CI environments settings + +## Bug Fixes + +* Fixed bug not allowing to update OAuth providers settings +* Fixed some broken API examples in docs +* Fixed bug that caused the Appwrite container to change DB directory file permissions. + +## Breaking Changes + +* Changed auth service 'redirect' param to 'confirm' for better clarity +* Updated all SDKs to sync with API changes + +# Version 0.1.15 (NOT-RELEASED) \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1ac1ca497..f3685f9f57 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,7 +36,7 @@ Appwrite uses PHPs Composer for managing dependencies on the server-side and JS Appwrite is following the PHP-FIG standards. Currently, we are using both PSR-0 and PSR-4 for coding standards and autoloading standards. Soon we will also review the project for support with PSR-12 (Extended Coding Style). -We use prettier for our JS coding standards and for auto-formmating our code. +We use prettier for our JS coding standards and for auto-formatting our code. ## Scalability, Speed and Performance @@ -83,9 +83,9 @@ Adding a new dependency should have vital value on the product with minimum poss ## Introducing New Features -We whould 💖 you to contribute to Appwrite, but we whould also like to make sure Appwrite is as great as possible and loyal to its vision and mission statement 🙏. +We would 💖 you to contribute to Appwrite, but we would also like to make sure Appwrite is as great as possible and loyal to its vision and mission statement 🙏. -For us to find the right balance, please open an issue explaining your ideas before intoducing a new pull requests. +For us to find the right balance, please open an issue explaining your ideas before introducing a new pull requests. This will allow the Appwrite community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision. @@ -121,6 +121,6 @@ Before running the command make sure you have proper write permissions to Appwri ## Tutorials -From time to time our team will add tutorials that will help contributers find there way in the Appwrite source code. Below is a list of currently available tutorials: +From time to time our team will add tutorials that will help contributors find there way in the Appwrite source code. Below is a list of currently available tutorials: * [Adding Support for a New OAuth Provider](./docs/AddOAuthProvider.md) \ No newline at end of file diff --git a/README.md b/README.md index fe1614912f..965f46c5a2 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Appwrite is a simple self-hosted backend server for web and mobile developers with a shiny dashboard and a very easy to use REST API. -Appwrite API services aims to make developers life a lot easier by hiding the complexity of common and repetitve software development tasks. +Appwrite API services aims to make developers life a lot easier by hiding the complexity of common and repetitive software development tasks. Using Appwrite you can easily manage user authentication with multiple sign-in methods, database for storing and querying user and teams data, storage and file management, image manipulation and cropping, scheduled cron tasks and many other features to help you get more results in faster times and with a lot less code. @@ -39,7 +39,7 @@ docker-compose up -d --remove-orphans Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please notice that on non-linux native hosts the server might take a few minutes to start after installation completes. -For advanced, production and custon installation check out our Docker [enviornemnt variables](/docs/EnviornementVariables.md) docs. +For advanced, production and custom installation check out our Docker [environment variables](/docs/EnviornementVariables.md) docs. ### Changing Port Number @@ -98,6 +98,15 @@ We really ❤️ pull requests! If you wish to help, you can learn more about ho Created by [Eldad Fux](https://twitter.com/eldadfux) with the amazing help of our **amazing contributors:** -* 🇺🇸Justin Dorfman ([Github](https://github.com/@jdorfman), [Twitter](https://twitter.com/jdorfman)) -* 🇺🇳0xflotus ([Github](https://github.com/0xflotus)) -* 🇳🇴Chaaarles ([Github](https://github.com/Chaaarles)) \ No newline at end of file +* 🇺🇸 Justin Dorfman ([Github](https://github.com/jdorfman), [Twitter](https://twitter.com/jdorfman)) +* 🇺🇳 0xflotus ([Github](https://github.com/0xflotus)) +* 🇳🇴 Petter Charles Redfern ([Github](https://github.com/Chaaarles)) +* 🇧🇷 Jessé Souza ([Github](https://github.com/jessescn)) +* 🇪🇸 Esther Álvarez Feijoo ([Github](https://github.com/EstherAF)) +* 🇮🇳 Christy Jacob ([Github](https://github.com/christyjacob4), [Linkedin](https://www.linkedin.com/in/christyjacob4/)) +* 🇺🇦 Dmitriy Danilov ([Github](https://github.com/daniloff200), [Twitter](https://twitter.com/daniloff200)) +* 🇮🇩 Zeet ([Github](https://github.com/Kiy4h)) +* 🇫🇮 Pessi Päivärinne ([Github](https://github.com/pessip)) +* 🇺🇳 Sergi Vos ([Github](https://github.com/sergivb01), [Twitter](https://twitter.com/sergivb01), [Linkedin](https://www.linkedin.com/in/sergivb01/)) +* 🇮🇱 Tomer Cohen ([Github](https://github.com/tomer), [Twitter](https://twitter.com/tomer)) +* 🇬🇷 Panagiotis Skarlas ([Github](https://github.com/1qk1), [Twitter](https://twitter.com/qktweets)) \ No newline at end of file diff --git a/app/app.php b/app/app.php index d4233dd224..24895732a7 100644 --- a/app/app.php +++ b/app/app.php @@ -31,26 +31,25 @@ $webhook = new Event('v1-webhooks', 'WebhooksV1'); $audit = new Event('v1-audits', 'AuditsV1'); $usage = new Event('v1-usage', 'UsageV1'); -$clientsConsole = array_map(function($node) { +$clientsConsole = array_map(function ($node) { return $node['url']; -}, array_filter($console->getAttribute('platforms', []), function($node) { - if(isset($node['type']) && $node['type'] === 'web' && isset($node['url']) && !empty($node['url'])) { +}, array_filter($console->getAttribute('platforms', []), function ($node) { + if (isset($node['type']) && $node['type'] === 'web' && isset($node['url']) && !empty($node['url'])) { return true; } return false; })); -$clients = array_merge($clientsConsole, array_map(function($node) { +$clients = array_merge($clientsConsole, array_map(function ($node) { return $node['url']; -}, array_filter($project->getAttribute('platforms', []), function($node) { - if(isset($node['type']) && $node['type'] === 'web' && isset($node['url']) && !empty($node['url'])) { +}, array_filter($project->getAttribute('platforms', []), function ($node) { + if (isset($node['type']) && $node['type'] === 'web' && isset($node['url']) && !empty($node['url'])) { return true; } return false; }))); -$utopia->init(function() use ($utopia, $request, $response, $register, &$user, $project, $roles, $webhook, $audit, $usage, $domain, $clients) { - +$utopia->init(function () use ($utopia, $request, $response, $register, &$user, $project, $roles, $webhook, $audit, $usage, $domain, $clients) { $route = $utopia->match($request); $referrer = $request->getServer('HTTP_REFERER', ''); @@ -82,7 +81,7 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ */ $hostValidator = new Host($clients); - if(!$hostValidator->isValid($request->getServer('HTTP_ORIGIN', $request->getServer('HTTP_REFERER', ''))) + if (!$hostValidator->isValid($request->getServer('HTTP_ORIGIN', $request->getServer('HTTP_REFERER', ''))) && in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE]) && empty($request->getHeader('X-Appwrite-Key', ''))) { throw new Exception('Access from this client host is forbidden. ' . $hostValidator->getDescription(), 403); @@ -96,7 +95,7 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ // Add user roles $membership = $user->search('teamId', $project->getAttribute('teamId', null), $user->getAttribute('memberships', [])); - if($membership) { + if ($membership) { foreach ($membership->getAttribute('roles', []) as $memberRole) { switch ($memberRole) { case 'owner': @@ -122,7 +121,7 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ * Try app auth when we have project key and no user * Mock user to app and grant API key scopes in addition to default app scopes */ - if(null !== $key && $user->isEmpty()) { + if (null !== $key && $user->isEmpty()) { $user = new Document([ '$uid' => 0, 'status' => Auth::USER_STATUS_ACTIVATED, @@ -141,7 +140,7 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ Authorization::setRole('role:' . $role); array_map(function ($node) { - if(isset($node['teamId']) && isset($node['roles'])) { + if (isset($node['teamId']) && isset($node['roles'])) { Authorization::setRole('team:' . $node['teamId']); foreach ($node['roles'] as $nodeRole) { // Set all team roles @@ -150,15 +149,15 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ } }, $user->getAttribute('memberships', [])); - if(!in_array($scope, $scopes)) { + if (!in_array($scope, $scopes)) { throw new Exception($user->getAttribute('email', 'Guest') . ' (role: ' . strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')', 401); } - if(Auth::USER_STATUS_BLOCKED == $user->getAttribute('status')) { // Account has not been activated + if (Auth::USER_STATUS_BLOCKED == $user->getAttribute('status')) { // Account has not been activated throw new Exception('Invalid credentials. User is blocked', 401); // User is in status blocked } - if($user->getAttribute('reset')) { + if ($user->getAttribute('reset')) { throw new Exception('Password reset is required', 412); } @@ -193,7 +192,9 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ /** * Abuse Check */ - $timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), function () use ($register) {return $register->get('db');}); + $timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), function () use ($register) { + return $register->get('db'); + }); $timeLimit->setNamespace('app_' . $project->getUid()); $timeLimit ->setParam('{userId}', $user->getUid()) @@ -204,13 +205,13 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ //TODO make sure we get array here - foreach($request->getParams() as $key => $value) { // Set request params as potential abuse keys + foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys $timeLimit->setParam('{param-' . $key . '}', (is_array($value)) ? json_encode($value) : $value); } $abuse = new Abuse($timeLimit); - if($timeLimit->limit()) { + if ($timeLimit->limit()) { $response ->addHeader('X-RateLimit-Limit', $timeLimit->limit()) ->addHeader('X-RateLimit-Remaining', $timeLimit->remaining()) @@ -218,7 +219,7 @@ $utopia->init(function() use ($utopia, $request, $response, $register, &$user, $ ; } - if($abuse->check() && $request->getServer('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') { + if ($abuse->check() && $request->getServer('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') { throw new Exception('Too many requests', 429); } }); @@ -228,11 +229,11 @@ $utopia->shutdown(function () use ($response, $request, $webhook, $audit, $usage /** * Trigger Events for background jobs */ - if(!empty($webhook->getParam('event'))) { + if (!empty($webhook->getParam('event'))) { $webhook->trigger(); } - if(!empty($audit->getParam('event'))) { + if (!empty($audit->getParam('event'))) { $audit->trigger(); } @@ -243,7 +244,7 @@ $utopia->shutdown(function () use ($response, $request, $webhook, $audit, $usage ; }); -$utopia->options(function() use ($request, $response, $domain, $project) { +$utopia->options(function () use ($request, $response, $domain, $project) { $origin = $request->getServer('HTTP_ORIGIN'); $response @@ -255,8 +256,8 @@ $utopia->options(function() use ($request, $response, $domain, $project) { ; }); -$utopia->error(function($error /* @var $error Exception */) use ($request, $response, $utopia, $project, $env, $version, $sentry, $user) { - switch($error->getCode()) { +$utopia->error(function ($error /* @var $error Exception */) use ($request, $response, $utopia, $project, $env, $version, $sentry, $user) { + switch ($error->getCode()) { case 400: // Error allowed publicly case 401: // Error allowed publicly case 402: // Error allowed publicly @@ -297,7 +298,7 @@ $utopia->error(function($error /* @var $error Exception */) use ($request, $resp $route = $utopia->match($request); $template = ($route) ? $route->getLabel('error', null): null; - if($template) { + if ($template) { $layout = new View(__DIR__ . '/views/layouts/default.phtml'); $comp = new View($template); @@ -329,8 +330,7 @@ $utopia->get('/manifest.json') ->label('scope', 'public') ->label('docs', false) ->action( - function() use ($response) { - + function () use ($response) { $response->json([ 'name' => APP_NAME, 'short_name' => APP_NAME, @@ -356,8 +356,7 @@ $utopia->get('/robots.txt') ->label('scope', 'public') ->label('docs', false) ->action( - function() use ($response) { - + function () use ($response) { $response->text("# robotstxt.org/ User-agent: * @@ -370,8 +369,7 @@ $utopia->get('/humans.txt') ->label('scope', 'public') ->label('docs', false) ->action( - function() use ($response) { - + function () use ($response) { $response->text("# humanstxt.org/ # The humans responsible & technology colophon @@ -387,7 +385,7 @@ $utopia->get('/v1/info') // This is only visible to gods ->label('scope', 'god') ->label('docs', false) ->action( - function() use ($response, $user, $project, $version, $env) { //TODO CONSIDER BLOCKING THIS ACTION TO ROLE GOD + function () use ($response, $user, $project, $version, $env) { //TODO CONSIDER BLOCKING THIS ACTION TO ROLE GOD $response->json([ 'name' => 'API', 'version' => $version, @@ -410,7 +408,7 @@ $utopia->get('/v1/xss') ->label('scope', 'public') ->label('docs', false) ->action( - function() { + function () { throw new Exception('XSS detected and reported by a browser client', 500); } ); @@ -419,7 +417,7 @@ $utopia->get('/v1/proxy') ->label('scope', 'public') ->label('docs', false) ->action( - function() use ($response, $console, $clients) { + function () use ($response, $console, $clients) { $view = new View(__DIR__ . '/views/proxy.phtml'); $view ->setParam('routes', '') @@ -436,12 +434,16 @@ $utopia->get('/v1/proxy') $utopia->get('/v1/open-api-2.json') ->label('scope', 'public') ->label('docs', false) - ->param('platform', 'client' , function () {return new WhiteList(['client', 'server']);}, 'Choose target platform.', true) - ->param('extensions', 0 , function () {return new Range(0, 1);}, 'Show extra data.', true) + ->param('platform', 'client', function () { + return new WhiteList(['client', 'server']); + }, 'Choose target platform.', true) + ->param('extensions', 0, function () { + return new Range(0, 1); + }, 'Show extra data.', true) ->action( - function($platform, $extensions) use ($response, $request, $utopia, $domain, $version, $services) { - - function fromCamelCase($input) { + function ($platform, $extensions) use ($response, $request, $utopia, $domain, $version, $services) { + function fromCamelCase($input) + { preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches); $ret = $matches[0]; foreach ($ret as &$match) { @@ -450,12 +452,13 @@ $utopia->get('/v1/open-api-2.json') return implode('_', $ret); } - function fromCamelCaseToDash($input) { + function fromCamelCaseToDash($input) + { return str_replace([' ', '_'], '-', strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $input))); } foreach ($services as $service) { /** @noinspection PhpIncludeInspection */ - if(!$service['sdk']) { + if (!$service['sdk']) { continue; } @@ -538,29 +541,29 @@ $utopia->get('/v1/open-api-2.json') ], ], 'Pets' => - array ( + array( 'type' => 'array', 'items' => - array ( + array( '$ref' => '#/definitions/Pet', ), ), 'Error' => - array ( + array( 'required' => - array ( + array( 0 => 'code', 1 => 'message', ), 'properties' => - array ( + array( 'code' => - array ( + array( 'type' => 'integer', 'format' => 'int32', ), 'message' => - array ( + array( 'type' => 'string', ), ), @@ -574,11 +577,11 @@ $utopia->get('/v1/open-api-2.json') foreach ($utopia->getRoutes() as $key => $method) { foreach ($method as $route) { /* @var $route \Utopia\Route */ - if(!$route->getLabel('docs', true)) { + if (!$route->getLabel('docs', true)) { continue; } - if(empty($route->getLabel('sdk.namespace', null))) { + if (empty($route->getLabel('sdk.namespace', null))) { continue; } @@ -587,7 +590,7 @@ $utopia->get('/v1/open-api-2.json') $hide = $route->getLabel('sdk.hide', false); $consumes = []; - if($hide) { + if ($hide) { continue; } @@ -607,15 +610,16 @@ $utopia->get('/v1/open-api-2.json') ], ]; - if($extensions) { + if ($extensions) { $temp['extensions'] = [ 'weight' => $route->getOrder(), 'cookies' => $route->getLabel('sdk.cookies', false), + 'location' => $route->getLabel('sdk.location', false), 'demo' => 'docs/examples/' . fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')) . '/' . fromCamelCaseToDash($temp['operationId']) . '.md', ]; } - if((!empty($scope) && 'public' != $scope)) { + if ((!empty($scope) && 'public' != $scope)) { $temp['security'][] = $route->getLabel('sdk.security', $security[$platform]); } @@ -708,24 +712,22 @@ $utopia->get('/v1/open-api-2.json') break; } - if($param['optional'] && !is_null($param['default'])) { // Param has default value + if ($param['optional'] && !is_null($param['default'])) { // Param has default value $node['default'] = $param['default']; } if (false !== strpos($url, ':' . $name)) { // Param is in URL path $node['in'] = 'path'; $temp['parameters'][] = $node; - } - elseif ($key == 'GET') { // Param is in query + } elseif ($key == 'GET') { // Param is in query $node['in'] = 'query'; $temp['parameters'][] = $node; - } - else { // Param is in payload + } else { // Param is in payload $node['in'] = 'formData'; $temp['parameters'][] = $node; $requestBody['content']['application/x-www-form-urlencoded']['schema']['properties'][] = $node; - if(!$param['optional']) { + if (!$param['optional']) { $requestBody['content']['application/x-www-form-urlencoded']['required'][] = $name; } } @@ -751,11 +753,10 @@ $utopia->get('/v1/open-api-2.json') $name = APP_NAME; -if(array_key_exists($service, $services)) { /** @noinspection PhpIncludeInspection */ +if (array_key_exists($service, $services)) { /** @noinspection PhpIncludeInspection */ include_once $services[$service]['controller']; $name = APP_NAME . ' ' . ucfirst($services[$service]['name']); -} -else { +} else { /** @noinspection PhpIncludeInspection */ include_once $services['/']['controller']; } @@ -768,4 +769,4 @@ if (extension_loaded('newrelic')) { newrelic_name_transaction($request->getServer('REQUEST_METHOD', 'UNKNOWN') . ': ' . $url); } -$utopia->run($request, $response); \ No newline at end of file +$utopia->run($request, $response); diff --git a/app/config/collections.php b/app/config/collections.php index 64bb0a61cb..ac62c18827 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1076,7 +1076,7 @@ foreach ($providers as $key => $provider) { $collections[Database::SYSTEM_COLLECTION_PROJECTS]['rules'][] = [ '$collection' => Database::SYSTEM_COLLECTION_RULES, 'label' => 'OAuth '.ucfirst($key).' ID', - 'key' => 'oauth'.ucfirst($key), + 'key' => 'usersOauth'.ucfirst($key) . 'Appid', 'type' => 'text', 'default' => '', 'required' => false, @@ -1085,8 +1085,8 @@ foreach ($providers as $key => $provider) { $collections[Database::SYSTEM_COLLECTION_PROJECTS]['rules'][] = [ '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OAuth '.ucfirst($key).' Access Token', - 'key' => 'oauth'.ucfirst($key).'AccessToken', + 'label' => 'OAuth '.ucfirst($key).' Secret', + 'key' => 'usersOauth'.ucfirst($key).'Secret', 'type' => 'text', 'default' => '', 'required' => false, diff --git a/app/config/locale/es.continents.php b/app/config/locale/es.continents.php new file mode 100644 index 0000000000..8822e9aab9 --- /dev/null +++ b/app/config/locale/es.continents.php @@ -0,0 +1,11 @@ + 'África', + 'AN' => 'Antártica', + 'AS' => 'Asia', + 'EU' => 'Europa', + 'NA' => 'América del Norte', + 'OC' => 'Oceanía', + 'SA' => 'América del Sur', +]; diff --git a/app/config/locale/es.countries.php b/app/config/locale/es.countries.php new file mode 100644 index 0000000000..f975e007da --- /dev/null +++ b/app/config/locale/es.countries.php @@ -0,0 +1,197 @@ + 'Afganistán', + 'AO' => 'Angola', + 'AL' => 'Albania', + 'AD' => 'Andorra', + 'AE' => 'Emiratos Árabes Unidos', + 'AR' => 'Argentina', + 'AM' => 'Armenia', + 'AG' => 'Antigua y Barbuda', + 'AU' => 'Australia', + 'AT' => 'Austria', + 'AZ' => 'Azerbaiyán', + 'BI' => 'Burundi', + 'BE' => 'Bélgica', + 'BJ' => 'Benin', + 'BF' => 'Burkina Faso', + 'BD' => 'Bangladesh', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrein', + 'BS' => 'Bahamas', + 'BA' => 'Bosnia y Herzegovina', + 'BY' => 'Bielorrusia', + 'BZ' => 'Belice', + 'BO' => 'Bolivia', + 'BR' => 'Brasil', + 'BB' => 'Barbados', + 'BN' => 'Brunei', + 'BT' => 'Bután', + 'BW' => 'Botsuana', + 'CF' => 'República Centroafricana', + 'CA' => 'Canadá', + 'CH' => 'Suiza', + 'CL' => 'Chile', + 'CN' => 'China', + 'CI' => 'Costa de Marfil', + 'CM' => 'Camerún', + 'CD' => 'República Democrática del Congo', + 'CG' => 'República del congo', + 'CO' => 'Colombia', + 'KM' => 'Comoras', + 'CV' => 'Cabo Verde', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CY' => 'Chipre', + 'CZ' => 'Chequia', + 'DE' => 'Alemania', + 'DJ' => 'Yibuti', + 'DM' => 'Dominica', + 'DK' => 'Dinamarca', + 'DO' => 'República Dominicana', + 'DZ' => 'Argelia', + 'EC' => 'Ecuador', + 'EG' => 'Egipto', + 'ER' => 'Eritrea', + 'ES' => 'España', + 'EE' => 'Estonia', + 'ET' => 'Etiopía', + 'FI' => 'Finlandia', + 'FJ' => 'Fiyi', + 'FR' => 'Francia', + 'FM' => 'Micronesia', + 'GA' => 'Gabón', + 'GB' => 'Reino Unido', + 'GE' => 'Georgia', + 'GH' => 'Ghana', + 'GN' => 'Guinea', + 'GM' => 'Gambia', + 'GW' => 'Guinea-Bissau', + 'GQ' => 'Guinea Ecuatorial', + 'GR' => 'Grecia', + 'GD' => 'Granada', + 'GT' => 'Guatemala', + 'GY' => 'Guayana', + 'HN' => 'Honduras', + 'HR' => 'Croacia', + 'HT' => 'Haití', + 'HU' => 'Hungría', + 'ID' => 'Indonesia', + 'IN' => 'India', + 'IE' => 'Irlanda', + 'IR' => 'Iran', + 'IQ' => 'Irak', + 'IS' => 'Islandia', + 'IL' => 'Israel', + 'IT' => 'Italia', + 'JM' => 'Jamaica', + 'JO' => 'Jordán', + 'JP' => 'Japón', + 'KZ' => 'Kazajstán', + 'KE' => 'Kenia', + 'KG' => 'Kirguistán', + 'KH' => 'Camboya', + 'KI' => 'Kiribati', + 'KN' => 'San Cristóbal y Nieves', + 'KR' => 'Corea del Sur', + 'KW' => 'Kuwait', + 'LA' => 'Laos', + 'LB' => 'Líbano', + 'LR' => 'Liberia', + 'LY' => 'Libia', + 'LC' => 'Santa Lucía', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LS' => 'Lesoto', + 'LT' => 'Lituania', + 'LU' => 'Luxemburgo', + 'LV' => 'Letonia', + 'MA' => 'Marruecos', + 'MC' => 'Mónaco', + 'MD' => 'Moldavia', + 'MG' => 'Madagascar', + 'MV' => 'Maldivas', + 'MX' => 'Mexico', + 'MH' => 'Islas Marshall', + 'MK' => 'Macedonia', + 'ML' => 'Mali', + 'MT' => 'Malta', + 'MM' => 'Myanmar', + 'ME' => 'Montenegro', + 'MN' => 'Mongolia', + 'MZ' => 'Mozambique', + 'MR' => 'Mauritania', + 'MU' => 'Mauricio', + 'MW' => 'Malawi', + 'MY' => 'Malasia', + 'NA' => 'Namibia', + 'NE' => 'Níger', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Países Bajos', + 'NO' => 'Noruega', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NZ' => 'Nueva Zelanda', + 'OM' => 'Omán', + 'PK' => 'Pakistán', + 'PA' => 'Panamá', + 'PE' => 'Perú', + 'PH' => 'Filipinas', + 'PW' => 'Palaos', + 'PG' => 'Papúa Nueva Guinea', + 'PL' => 'Polonia', + 'KP' => 'Corea del Norte', + 'PT' => 'Portugal', + 'PY' => 'Paraguay', + 'QA' => 'Katar', + 'RO' => 'Rumania', + 'RU' => 'Rusia', + 'RW' => 'Ruanda', + 'SA' => 'Arabia Saudita', + 'SD' => 'Sudán', + 'SN' => 'Senegal', + 'SG' => 'Singapur', + 'SB' => 'Islas Salomón', + 'SL' => 'Sierra Leona', + 'SV' => 'El Salvador', + 'SM' => 'San Marino', + 'SO' => 'Somalia', + 'RS' => 'Serbia', + 'SS' => 'Sudán del Sur', + 'ST' => 'Santo Tomé y Príncipe', + 'SR' => 'Surinam', + 'SK' => 'Eslovaquia', + 'SI' => 'Eslovenia', + 'SE' => 'Suecia', + 'SZ' => 'Suazilandia', + 'SC' => 'Seychelles', + 'SY' => 'Siria', + 'TD' => 'Chad', + 'TG' => 'Togo', + 'TH' => 'Tailandia', + 'TJ' => 'Tayikistán', + 'TM' => 'Turkmenistán', + 'TL' => 'Timor Oriental', + 'TO' => 'Tonga', + 'TT' => 'Trinidad y Tobago', + 'TN' => 'Túnez', + 'TR' => 'Turquía', + 'TV' => 'Tuvalu', + 'TZ' => 'Tanzania', + 'UG' => 'Uganda', + 'UA' => 'Ucrania', + 'UY' => 'Uruguay', + 'US' => 'Estados Unidos', + 'UZ' => 'Uzbekistán', + 'VA' => 'Ciudad del Vaticano', + 'VC' => 'San Vicente y las Granadinas', + 'VE' => 'Venezuela', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'ZA' => 'Sudáfrica', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabue', +]; diff --git a/app/config/locale/es.php b/app/config/locale/es.php new file mode 100644 index 0000000000..0a56743689 --- /dev/null +++ b/app/config/locale/es.php @@ -0,0 +1,21 @@ + '"El arte de ser sabio es el arte de saber qué pasar por alto"', // This is the line printed in the homepage and console 'view-source' + 'settings.locale' => 'es', + 'settings.direction' => 'ltr', + + // Service - Users + 'auth.emails.team' => '%s Equipo', + 'auth.emails.confirm.title' => 'Confirmación de la cuenta', + 'auth.emails.confirm.body' => 'es.email.auth.confirm.tpl', + 'auth.emails.recovery.title' => 'Reestablecer contraseña', + 'auth.emails.recovery.body' => 'es.email.auth.recovery.tpl', + 'auth.emails.invitation.title' => 'Invitación al Equipo %s en %s', + 'auth.emails.invitation.body' => 'es.email.auth.invitation.tpl', + + 'locale.country.unknown' => 'Desconocido', + + 'countries' => include 'es.countries.php', + 'continents' => include 'es.continents.php', +]; diff --git a/app/config/locale/gr.continents.php b/app/config/locale/gr.continents.php new file mode 100644 index 0000000000..4655baca9f --- /dev/null +++ b/app/config/locale/gr.continents.php @@ -0,0 +1,11 @@ + 'Αφρική', + 'AN' => 'Ανταρκτική', + 'AS' => 'Ασία', + 'EU' => 'Ευρώπη', + 'NA' => 'Βόρεια Αμερική', + 'OC' => 'Ωκεανία', + 'SA' => 'Νότια Αμερική', +]; diff --git a/app/config/locale/gr.countries.php b/app/config/locale/gr.countries.php new file mode 100644 index 0000000000..68a3aa7652 --- /dev/null +++ b/app/config/locale/gr.countries.php @@ -0,0 +1,198 @@ + 'Αφγανιστάν', + 'AO' => 'Ανγκόλα', + 'AL' => 'Αλβανία', + 'AD' => 'Ανδόρα', + 'AE' => 'Ηνωμένα Αραβικά Εμιράτα', + 'AR' => 'Αργεντινή', + 'AM' => 'Αρμενία', + 'AG' => 'Αντίγκουα και Μπαρμπούντα', + 'AU' => 'Αυστραλία', + 'AT' => 'Αυστρία', + 'AZ' => 'Αζερμπαϊτζάν', + 'BI' => 'Μπουρούντι', + 'BE' => 'Βέλγιο', + 'BJ' => 'Μπενίν', + 'BF' => 'Μπουρκίνα Φάσο', + 'BD' => 'Μπανγκλαντές', + 'BG' => 'Βουλγαρία', + 'BH' => 'Μπαχρέιν', + 'BS' => 'Μπαχάμες', + 'BA' => 'Βοσνία και Ερζεγοβίνη', + 'BY' => 'Λευκορωσία', + 'BZ' => 'Μπελίζε', + 'BO' => 'Βολιβία', + 'BR' => 'Βραζιλία', + 'BB' => 'Μπαρμπάντος', + 'BN' => 'Μπρουνέι', + 'BT' => 'Μπουτάν', + 'BW' => 'Μποτσουάνα', + 'CF' => 'Κεντροαφρικανική Δημοκρατία', + 'CA' => 'Καναδάς', + 'CH' => 'Ελβετία', + 'CL' => 'Χιλή', + 'CN' => 'Κίνα', + 'CI' => 'Ακτή Ελεφαντοστού', + 'CM' => 'Καμερούν', + 'CD' => 'Λαϊκή Δημοκρατία του Κονγκό', + 'CG' => 'Δημοκρατία του Κονγκό', + 'CO' => 'Κολομβία', + 'KM' => 'Κομόρες', + 'CV' => 'Πράσινο Ακρωτήρι', + 'CR' => 'Κόστα Ρίκα', + 'CU' => 'Κούβα', + 'CY' => 'Κύπρος', + 'CZ' => 'Τσεχία', + 'DE' => 'Γερμανία', + 'DJ' => 'Τζιμπουτί', + 'DM' => 'Ντομίνικα', + 'DK' => 'Δανία', + 'DO' => 'Δομινικανή Δημοκρατία', + 'DZ' => 'Αλγερία', + 'EC' => 'Εκουαδόρ', + 'EG' => 'Αίγυπτος', + 'ER' => 'Ερυθραία', + 'ES' => 'Ισπανία', + 'EE' => 'Εσθονία', + 'ET' => 'Αιθιοπία', + 'FI' => 'Φινλανδία', + 'FJ' => 'Φίτζι', + 'FR' => 'Γαλλία', + 'FM' => 'Μικρονησία', + 'GA' => 'Γκαμπόν', + 'GB' => 'Ηνωμένο Βασίλειο', + 'GE' => 'Γεωργία', + 'GH' => 'Γκάνα', + 'GN' => 'Γουινέα', + 'GM' => 'Γκάμπια', + 'GW' => 'Γουινέα-Μπισσάου', + 'GQ' => 'Ισημερινή Γουινέα', + 'GR' => 'Ελλάδα', + 'GD' => 'Γρενάδα', + 'GT' => 'Γουατεμάλα', + 'GY' => 'Γουιάνα', + 'HN' => 'Ονδούρα', + 'HR' => 'Κροατία', + 'HT' => 'Αϊτή', + 'HU' => 'Ουγγαρία', + 'ID' => 'Ινδονησία', + 'IN' => 'Ινδία', + 'IE' => 'Ιρλανδία', + 'IR' => 'Ιράν', + 'IQ' => 'Ιράκ', + 'IS' => 'Ισλανδία', + 'IL' => 'Ισραήλ', + 'IT' => 'Ιταλία', + 'JM' => 'Τζαμάικα', + 'JO' => 'Ιορδανία', + 'JP' => 'Ιαπωνία', + 'KZ' => 'Καζακστάν', + 'KE' => 'Κένυα', + 'KG' => 'Κιργιζιστάν', + 'KH' => 'Καμπότζη', + 'KI' => 'Κιριμπάτι', + 'KN' => 'Άγιος Χριστόφορος και Νέβις', + 'KR' => 'Νότια Κορέα', + 'KW' => 'Κουβέιτ', + 'LA' => 'Λάος', + 'LB' => 'Λίβανος', + 'LR' => 'Λιβερία', + 'LY' => 'Λιβύη', + 'LC' => 'Αγία Λουδία', + 'LI' => 'Λιχτενστάιν', + 'LK' => 'Σρι Λάνκα', + 'LS' => 'Λεσότο', + 'LT' => 'Λιθουανία', + 'LU' => 'Λουξεμβούργο', + 'LV' => 'Λετονία', + 'MA' => 'Μαρόκο', + 'MC' => 'Μονακό', + 'MD' => 'Μολδαβία', + 'MG' => 'Μαδαγασκάρη', + 'MV' => 'Μαλδίβες', + 'MX' => 'Μεξικό', + 'MH' => 'Νήσοι Μάρσαλ', + 'MK' => 'Μακεδονία', + 'ML' => 'Μάλι', + 'MT' => 'Μάλτα', + 'MM' => 'Μυανμάρ', + 'ME' => 'Μαυροβούνιο', + 'MN' => 'Μογγολία', + 'MZ' => 'Μοζαμβίκη', + 'MR' => 'Μαυριτανία', + 'MU' => 'Μαυρίκιος', + 'MW' => 'Μαλάουι', + 'MY' => 'Μαλαισία', + 'NA' => 'Ναμίμπια', + 'NE' => 'Νίγηρα', + 'NG' => 'Νιγηρία', + 'NI' => 'Νικαράγουα', + 'NL' => 'Ολλανδία', + 'NO' => 'Νορβηγία', + 'NP' => 'Νεπάλ', + 'NR' => 'Ναουρού', + 'NZ' => 'Νέα Ζηλανδία', + 'OM' => 'Ομάν', + 'PK' => 'Πακιστάν', + 'PA' => 'Παναμάς', + 'PE' => 'Περού', + 'PH' => 'Φιλιππίνες', + 'PW' => 'Palau', + 'PG' => 'Παπούα Νέα Γουινέα', + 'PL' => 'Πολωνία', + 'KP' => 'Βόρεια Κορέα', + 'PT' => 'Πορτογαλία', + 'PY' => 'Παραγουάη', + 'QA' => 'Κατάρ', + 'RO' => 'Ρουμανία', + 'RU' => 'Ρωσία', + 'RW' => 'Ρουάντα', + 'SA' => 'Σαουδική Αραβία', + 'SD' => 'Σουδάν', + 'SN' => 'Σενεγάλη', + 'SG' => 'Σιγκαπούρη', + 'SB' => 'Νησιά Σολομώντα', + 'SL' => 'Σιέρα Λεόνε', + 'SV' => 'Ελ Σαλβαδόρ', + 'SM' => 'Σαν Μαρίνο', + 'SO' => 'Σομαλία', + 'RS' => 'Σερβία', + 'SS' => 'Νότια Σουδάν', + 'ST' => 'Σάο Τομέ και Πρινσίπε', + 'SR' => 'Σουρινάμ', + 'SK' => 'Σλοβακία', + 'SI' => 'Σλοβενία', + 'SE' => 'Σουηδία', + 'SZ' => 'Σουαζιλάνδη', + 'SC' => 'Σεϋχέλλες', + 'SY' => 'Συρία', + 'TD' => 'Τσαντ', + 'TG' => 'Τόγκο', + 'TH' => 'Ταϊλάνδη', + 'TJ' => 'Τατζικιστάν', + 'TM' => 'Τουρκμενιστάν', + 'TL' => 'Ανατολικό Τιμόρ', + 'TO' => 'Τόνγκα', + 'TT' => 'Τρινιντάντ και Τομπάγκο', + 'TN' => 'Τυνησία', + 'TR' => 'Τουρκία', + 'TV' => 'Τουβαλού', + 'TZ' => 'Τανζανία', + 'UG' => 'Ουγκάντα', + 'UA' => 'Ουκρανία', + 'UY' => 'Ουρουγουάη', + 'US' => 'Ηνωμένες Πολιτείες', + 'UZ' => 'Ουζμπεκιστάν', + 'VA' => 'Βατικανό', + 'VC' => 'Άγιος Βικέντιος και Γρεναδίνες', + 'VE' => 'Βενεζουέλα', + 'VN' => 'Βιετνάμ', + 'VU' => 'Βανουάτου', + 'WS' => 'Σαμόα', + 'YE' => 'Υεμένη', + 'ZA' => 'Νότια Αφρική', + 'ZM' => 'Ζάμπια', + 'ZW' => 'Ζιμπάμπουε', +]; diff --git a/app/config/locale/gr.php b/app/config/locale/gr.php new file mode 100644 index 0000000000..95f24f938b --- /dev/null +++ b/app/config/locale/gr.php @@ -0,0 +1,21 @@ + '"The art of being wise is the art of knowing what to overlook."', // This is the line printed in the homepage and console 'view-source' + 'settings.locale' => 'gr', + 'settings.direction' => 'ltr', + + // Service - Users + 'auth.emails.team' => 'Ομάδα %s', + 'auth.emails.confirm.title' => 'Επιβεβαίωση Λογαριασμού', + 'auth.emails.confirm.body' => 'gr.email.auth.confirm.tpl', + 'auth.emails.recovery.title' => 'Επαναφορά Κωδικού Πρόσβασης', + 'auth.emails.recovery.body' => 'gr.email.auth.recovery.tpl', + 'auth.emails.invitation.title' => 'Πρόσκληση στην ομάδα %s στο %s', + 'auth.emails.invitation.body' => 'gr.email.auth.invitation.tpl', + + 'locale.country.unknown' => 'Άγνωστο', + + 'countries' => include 'gr.countries.php', + 'continents' => include 'gr.continents.php', +]; diff --git a/app/config/locale/he.countries.php b/app/config/locale/he.countries.php index 370dfcd17b..3d0d29f4a6 100644 --- a/app/config/locale/he.countries.php +++ b/app/config/locale/he.countries.php @@ -7,7 +7,7 @@ return [ 'AU' => 'אוסטרליה', 'UA' => 'אוקראינה', 'UY' => 'אורוגוואי', - 'AZ' => 'אזרבייג\'ן', + 'AZ' => 'אזרבייג׳ן', 'AE' => 'איחוד האמירויות הערביות', 'IT' => 'איטליה', 'BS' => 'איי בהאמה', diff --git a/app/config/locale/he.php b/app/config/locale/he.php index 41ce63ea79..14a3e2cc2a 100644 --- a/app/config/locale/he.php +++ b/app/config/locale/he.php @@ -11,7 +11,7 @@ return [ 'auth.emails.confirm.body' => 'he.email.auth.confirm.tpl', 'auth.emails.recovery.title' => 'איפוס סיסמא', 'auth.emails.recovery.body' => 'he.email.auth.recovery.tpl', - 'auth.emails.invitation.title' => 'הזמנה לצוות של %s ב-%s', + 'auth.emails.invitation.title' => 'הזמנה לצוות של %s ב־%s', 'auth.emails.invitation.body' => 'he.email.auth.invitation.tpl', 'locale.country.unknown' => 'לא ידוע', diff --git a/app/config/locale/it.continents.php b/app/config/locale/it.continents.php new file mode 100644 index 0000000000..22672575ba --- /dev/null +++ b/app/config/locale/it.continents.php @@ -0,0 +1,10 @@ + 'Africa', + 'AN' => 'Antartide', + 'AS' => 'Asia', + 'EU' => 'Europa', + 'NA' => 'Nord America', + 'OC' => 'Oceania', + 'SA' => 'Sud America', +]; \ No newline at end of file diff --git a/app/config/locale/it.countries.php b/app/config/locale/it.countries.php new file mode 100644 index 0000000000..6d539332aa --- /dev/null +++ b/app/config/locale/it.countries.php @@ -0,0 +1,198 @@ + 'Afghanistan', + 'AO' => 'Angola', + 'AL' => 'Albania', + 'AD' => 'Andorra', + 'AE' => 'Emirati Arabi Uniti', + 'AR' => 'Argentina', + 'AM' => 'Armenia', + 'AG' => 'Antigua e Barbuda', + 'AU' => 'Australia', + 'AT' => 'Austria', + 'AZ' => 'Azerbaigian', + 'BI' => 'Burundi', + 'BE' => 'Belgio', + 'BJ' => 'Benin', + 'BF' => 'Burkina Faso', + 'BD' => 'Bangladesh', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrein', + 'BS' => 'Bahamas', + "BA" => "Bosnia ed Erzegovina", + 'BY' => 'Bielorussia', + 'BZ' => 'Belize', + 'BO' => 'Bolivia', + 'BR' => 'Brasile', + 'BB' => 'Barbados', + 'BN' => 'Brunei', + 'BT' => 'Bhutan', + 'BW' => 'Botswana', + "CF" => "Repubblica centrafricana", + 'CA' => 'Canada', + 'CH' => 'Svizzera', + 'CL' => 'Cile', + 'CN' => 'Cina', + 'CI' => 'Costa d\'Avorio', + 'CM' => 'Camerun', + 'CD' => 'DR Congo', + 'CG' => 'Repubblica del Congo', + 'CO' => 'Colombia', + 'KM' => 'Comore', + 'CV' => 'Capo Verde', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CY' => 'Cipro', + 'CZ' => 'Czechia', + 'DE' => 'Germania', + 'DJ' => 'Gibuti', + 'DM' => 'Dominica', + 'DK' => 'Danimarca', + 'DO' => 'Repubblica Dominicana', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EG' => 'Egitto', + 'ER' => 'Eritrea', + 'ES' => 'Spagna', + 'EE' => 'Estonia', + 'ET' => 'Etiopia', + 'FI' => 'Finlandia', + 'FJ' => 'Figi', + 'FR' => 'France', + 'FM' => 'Micronesia', + 'GA' => 'Gabon', + 'GB' => 'Regno Unito', + 'GE' => 'Georgia', + 'GH' => 'Ghana', + 'GN' => 'Guinea', + 'GM' => 'Gambia', + 'GW' => 'Guinea-Bissau', + 'GQ' => 'Guinea equatoriale', + 'GR' => 'Grecia', + 'GD' => 'Grenada', + 'GT' => 'Guatemala', + 'GY' => 'Guyana', + 'HN' => 'Honduras', + 'HR' => 'Croazia', + 'HT' => 'Haiti', + 'HU' => 'Ungheria', + 'ID' => 'Indonesia', + 'IN' => 'India', + 'IE' => 'Irlanda', + 'IR' => 'Iran', + 'IQ' => 'Iraq', + 'IS' => 'Islanda', + 'IL' => 'Israele', + 'IT' => 'Italia', + 'JM' => 'Giamaica', + 'JO' => 'Jordan', + 'JP' => 'Giappone', + 'KZ' => 'Kazakistan', + 'KE' => 'Kenya', + 'KG' => 'Kirghizistan', + 'KH' => 'Cambogia', + 'KI' => 'Kiribati', + 'KN' => 'Saint Kitts e Nevis', + "KR" => "Corea del Sud", + 'KW' => 'Kuwait', + 'LA' => 'Laos', + 'LB' => 'Libano', + 'LR' => 'Liberia', + 'LY' => 'Libia', + 'LC' => 'Santa Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LS' => 'Lesotho', + 'LT' => 'Lituania', + 'LU' => 'Lussemburgo', + 'LV' => 'Lettonia', + 'MA' => 'Marocco', + 'MC' => 'Monaco', + 'MD' => 'Moldavia', + 'MG' => 'Madagascar', + 'MV' => 'Maldive', + 'MX' => 'Messico', + 'MH' => 'Isole Marshall', + 'MK' => 'Macedonia', + 'ML' => 'Mali', + 'MT' => 'Malta', + 'MM' => 'Myanmar', + 'ME' => 'Montenegro', + 'MN' => 'Mongolia', + 'MZ' => 'Mozambico', + 'MR' => 'Mauritania', + 'MU' => 'Mauritius', + 'MW' => 'Malawi', + 'MY' => 'Malaysia', + 'NA' => 'Namibia', + 'NE' => 'Niger', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Paesi Bassi', + 'NO' => 'Norvegia', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NZ' => 'Nuova Zelanda', + 'OM' => 'Oman', + 'PK' => 'Pakistan', + 'PA' => 'Panama', + 'PE' => 'Perù', + 'PH' => 'Filippine', + 'PW' => 'Palau', + 'PG' => 'Papua New Guinea', + 'PL' => 'Polonia', + 'KP' => 'Corea del Nord', + 'PT' => 'Portogallo', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RO' => 'Romania', + 'RU' => 'Russia', + 'RW' => 'Ruanda', + 'SA' => 'Arabia Saudita', + 'SD' => 'Sudan', + 'SN' => 'Senegal', + 'SG' => 'Singapore', + 'SB' => 'Isole Salomone', + 'SL' => 'Sierra Leone', + 'SV' => 'El Salvador', + 'SM' => 'San Marino', + 'SO' => 'Somalia', + 'RS' => 'Serbia', + 'SS' => 'Sudan del Sud', + 'ST' => 'São Tomé and Príncipe', + 'SR' => 'Suriname', + 'SK' => 'Slovacchia', + 'SI' => 'Slovenia', + 'SE' => 'Svezia', + 'SZ' => 'Swaziland', + 'SC' => 'Seychelles', + 'SY' => 'Siria', + 'TD' => 'Chad', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tagikistan', + 'TM' => 'Turkmenistan', + 'TL' => 'Timor Est', + 'TO' => 'Tonga', + 'TT' => 'Trinidad e Tobago', + 'TN' => 'Tunisia', + 'TR' => 'Turchia', + 'TV' => 'Tuvalu', + 'TZ' => 'Tanzania', + 'UG' => 'Uganda', + 'UA' => 'Ucraina', + 'UY' => 'Uruguay', + 'US' => 'Stati Uniti', + 'UZ' => 'Uzbekistan', + 'VA' => 'Città del Vaticano', + 'VC' => 'Saint Vincent e Grenadine', + 'VE' => 'Venezuela', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'ZA' => 'Sudafrica', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; \ No newline at end of file diff --git a/app/config/locale/it.php b/app/config/locale/it.php new file mode 100644 index 0000000000..071a17b8f6 --- /dev/null +++ b/app/config/locale/it.php @@ -0,0 +1,18 @@ + '"L\'arte di essere saggi è l\'arte di sapere cosa trascurare."', // Questa è la riga stampata nella homepage e nella console 'view-source' + 'settings.locale' => 'it', + 'settings.direction' => 'ltr', + // Servizio - Utenti + 'auth.emails.team' => '%s Squadra', + 'auth.emails.confirm.title' => 'Conferma dell\'account', + 'auth.emails.confirm.body' => 'en.email.auth.confirm.tpl', + 'auth.emails.recovery.title' => 'Reimpostazione della password', + 'auth.emails.recovery.body' => 'en.email.auth.recovery.tpl', + 'auth.emails.invitation.title' => 'Invito a %s squadra %s', + 'auth.emails.invitation.body' => 'en.email.auth.invitation.tpl', + 'locale.country.unknown' => 'Sconosciuto', + 'countries' => include 'it.countries.php', + 'continents' => include 'it.continents.php', +]; \ No newline at end of file diff --git a/app/config/locale/pt-br.continents.php b/app/config/locale/pt-br.continents.php new file mode 100644 index 0000000000..9096c20d73 --- /dev/null +++ b/app/config/locale/pt-br.continents.php @@ -0,0 +1,11 @@ + 'África', + 'AN' => 'Antártica', + 'AS' => 'Ásia', + 'EU' => 'Europa', + 'NA' => 'América do Norte', + 'OC' => 'Oceania', + 'SA' => 'América do Sul', +]; diff --git a/app/config/locale/pt-br.countries.php b/app/config/locale/pt-br.countries.php new file mode 100644 index 0000000000..3825ebe8f8 --- /dev/null +++ b/app/config/locale/pt-br.countries.php @@ -0,0 +1,198 @@ + 'Afeganistão', + 'AO' => 'Angola', + 'AL' => 'Albânia', + 'AD' => 'Andorra', + 'AE' => 'Emirados Árabes Unidos', + 'AR' => 'Argentina', + 'AM' => 'Armênia', + 'AG' => 'Antígua e Barbuda', + 'AU' => 'Austrália', + 'AT' => 'Áustria', + 'AZ' => 'Azerbaijão', + 'BI' => 'Burúndi', + 'BE' => 'Bélgica', + 'BJ' => 'Benim', + 'BF' => 'Burkina Faso', + 'BD' => 'Bangladesh', + 'BG' => 'Bulgária', + 'BH' => 'Bahrein', + 'BS' => 'Bahamas', + 'BA' => 'Bósnia and Herzegovina', + 'BY' => 'Bielorússia', + 'BZ' => 'Belize', + 'BO' => 'Bolívia', + 'BR' => 'Brasil', + 'BB' => 'Barbados', + 'BN' => 'Brunei', + 'BT' => 'Butão', + 'BW' => 'Botsuana', + 'CF' => 'República Centro-Africana', + 'CA' => 'Canadá', + 'CH' => 'Suíça', + 'CL' => 'Chile', + 'CN' => 'China', + 'CI' => 'Costa do Marfim', + 'CM' => 'Camarões', + 'CD' => 'República Democrática do Congo', + 'CG' => 'República do Congo', + 'CO' => 'Colombia', + 'KM' => 'Comores', + 'CV' => 'Cabo Verde', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CY' => 'Chipre', + 'CZ' => 'Tchéquia', + 'DE' => 'Alemanha', + 'DJ' => 'Djibouti', + 'DM' => 'Dominica', + 'DK' => 'Dinamarca', + 'DO' => 'República Dominicana', + 'DZ' => 'Argélia', + 'EC' => 'Equador', + 'EG' => 'Egito', + 'ER' => 'Eritrea', + 'ES' => 'Espanha', + 'EE' => 'Estônia', + 'ET' => 'Etiópia', + 'FI' => 'Finlândia', + 'FJ' => 'Fiji', + 'FR' => 'França', + 'FM' => 'Micronésia', + 'GA' => 'Gabão', + 'GB' => 'Reino Unido', + 'GE' => 'Geórgia', + 'GH' => 'Gana', + 'GN' => 'Guiné', + 'GM' => 'Gâmbia', + 'GW' => 'Guiné-Bissau', + 'GQ' => 'Guiné Equatorial', + 'GR' => 'Grécia', + 'GD' => 'Granada', + 'GT' => 'Guatemala', + 'GY' => 'Guiana', + 'HN' => 'Honduras', + 'HR' => 'Croácia', + 'HT' => 'Haiti', + 'HU' => 'Hungria', + 'ID' => 'Indonésia', + 'IN' => 'Índia', + 'IE' => 'Irlanda', + 'IR' => 'Irã', + 'IQ' => 'Iraque', + 'IS' => 'Islândia', + 'IL' => 'Israel', + 'IT' => 'Itália', + 'JM' => 'Jamaica', + 'JO' => 'Jordânia', + 'JP' => 'Japão', + 'KZ' => 'Cazaquistão', + 'KE' => 'Quênia', + 'KG' => 'Quirguistão', + 'KH' => 'Camboja', + 'KI' => 'Quiribati', + 'KN' => 'São Cristóvão e Névis', + 'KR' => 'Coreia do Sul', + 'KW' => 'Kuwait', + 'LA' => 'Laos', + 'LB' => 'Líbano', + 'LR' => 'Libéria', + 'LY' => 'Líbia', + 'LC' => 'Santa Lúcia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LS' => 'Lesoto', + 'LT' => 'Lituânia', + 'LU' => 'Luxemburgo', + 'LV' => 'Letônia', + 'MA' => 'Marrocos', + 'MC' => 'Mônaco', + 'MD' => 'Moldávia', + 'MG' => 'Madagascar', + 'MV' => 'Maldivas', + 'MX' => 'México', + 'MH' => 'Ilhas Marshall', + 'MK' => 'Macedônia', + 'ML' => 'Mali', + 'MT' => 'Malta', + 'MM' => 'Myanmar', + 'ME' => 'Montenegro', + 'MN' => 'Mongólia', + 'MZ' => 'Moçambique', + 'MR' => 'Mauritânia', + 'MU' => 'Ilhas Maurício', + 'MW' => 'Malawi', + 'MY' => 'Malásia', + 'NA' => 'Namíbia', + 'NE' => 'Níger', + 'NG' => 'Nigéria', + 'NI' => 'Nicarágua', + 'NL' => 'Países Baixos', + 'NO' => 'Noruega', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NZ' => 'Nova Zelândia', + 'OM' => 'Omã', + 'PK' => 'Paquistão', + 'PA' => 'Panamá', + 'PE' => 'Peru', + 'PH' => 'Filipinas', + 'PW' => 'Palau', + 'PG' => 'Papua-Nova Guiné', + 'PL' => 'Polônia', + 'KP' => 'Coreia do Norte', + 'PT' => 'Portugal', + 'PY' => 'Paraguai', + 'QA' => 'Catar', + 'RO' => 'Romênia', + 'RU' => 'Rússia', + 'RW' => 'Ruanda', + 'SA' => 'Arábia Saudita', + 'SD' => 'Sudão', + 'SN' => 'Senegal', + 'SG' => 'Singapura', + 'SB' => 'Ilhas Salomão', + 'SL' => 'Serra Leoa', + 'SV' => 'El Salvador', + 'SM' => 'San Marino', + 'SO' => 'Somália', + 'RS' => 'Sérvia', + 'SS' => 'Sudão do Sul', + 'ST' => 'São Tomé e Príncipe', + 'SR' => 'Suriname', + 'SK' => 'Eslováquia', + 'SI' => 'Eslovênia', + 'SE' => 'Suécia', + 'SZ' => 'Suazilândia', + 'SC' => 'Seicheles', + 'SY' => 'Síria', + 'TD' => 'Chade', + 'TG' => 'Togo', + 'TH' => 'Tailândia', + 'TJ' => 'Tajisquistão', + 'TM' => 'Turcomenistão', + 'TL' => 'Timor-Leste', + 'TO' => 'Tonga', + 'TT' => 'Trindade e Tobago', + 'TN' => 'Tunísia', + 'TR' => 'Turquia', + 'TV' => 'Tuvalu', + 'TZ' => 'Tanzânia', + 'UG' => 'Uganda', + 'UA' => 'Ucrânia', + 'UY' => 'Uruguai', + 'US' => 'Estados Unidos', + 'UZ' => 'Uzbequistão', + 'VA' => 'Cidade do Vaticano', + 'VC' => 'São Vincente e Granadinas', + 'VE' => 'Venezuela', + 'VN' => 'Vietnã', + 'VU' => 'Vanuatu', + 'WS' => 'Samoa', + 'YE' => 'Iêmen', + 'ZA' => 'África do Sul', + 'ZM' => 'Zâmbia', + 'ZW' => 'Zimbábue', +]; diff --git a/app/config/locale/pt-br.php b/app/config/locale/pt-br.php new file mode 100644 index 0000000000..cc08622883 --- /dev/null +++ b/app/config/locale/pt-br.php @@ -0,0 +1,21 @@ + '"The art of being wise is the art of knowing what to overlook."', // This is the line printed in the homepage and console 'view-source' + 'settings.locale' => 'pt-br', + 'settings.direction' => 'ltr', + + // Service - Users + 'auth.emails.team' => 'Time %s', + 'auth.emails.confirm.title' => 'Confirmação de Conta', + 'auth.emails.confirm.body' => 'pt-br.email.auth.confirm.tpl', + 'auth.emails.recovery.title' => 'Redefinição de Senha', + 'auth.emails.recovery.body' => 'pt-br.email.auth.recovery.tpl', + 'auth.emails.invitation.title' => 'Convite para a Equipe %s em %s', + 'auth.emails.invitation.body' => 'pt-br.email.auth.invitation.tpl', + + 'locale.country.unknown' => 'Desconhecido', + + 'countries' => include 'pt-br.countries.php', + 'continents' => include 'pt-br.continents.php', +]; diff --git a/app/config/locale/templates/en.email.auth.invitation.tpl b/app/config/locale/templates/en.email.auth.invitation.tpl index a71d72ebb3..fda2bbcce0 100644 --- a/app/config/locale/templates/en.email.auth.invitation.tpl +++ b/app/config/locale/templates/en.email.auth.invitation.tpl @@ -10,7 +10,7 @@ Hello,

- This mail was sent to you because {{owner}} wanted to invite to become a team member at the {{team}} team over at {{project}}. + This mail was sent to you because {{owner}} wanted to invite you to become a team member at the {{team}} team over at {{project}}.

Follow this link to join the {{team}} team: diff --git a/app/config/locale/templates/es.email.auth.confirm.tpl b/app/config/locale/templates/es.email.auth.confirm.tpl new file mode 100644 index 0000000000..3bb7e97b62 --- /dev/null +++ b/app/config/locale/templates/es.email.auth.confirm.tpl @@ -0,0 +1,24 @@ + + +
+ Hola {{name}}, +
+
+ Sigue este enlace para verificar tu dirección de correo: +
+ {{redirect}} +
+
+ Si no has solicitado verificar esta dirección, puedes ignorar este mensaje. +
+
+ Gracias, +
+ Equipo {{project}} +
\ No newline at end of file diff --git a/app/config/locale/templates/es.email.auth.invitation.tpl b/app/config/locale/templates/es.email.auth.invitation.tpl new file mode 100644 index 0000000000..aa0469d9c6 --- /dev/null +++ b/app/config/locale/templates/es.email.auth.invitation.tpl @@ -0,0 +1,27 @@ + + +
+ Hola, +
+
+ Te hemos enviamos este correo porque {{owner}} quiere invitarte a formar parte del equipo {{team}} en {{project}}. +
+
+ Sigue este enlace para unirte al equipo {{team}}: +
+ {{redirect}} +
+
+ Si no ests interesado, puedes ignorar este mensaje. +
+
+ Gracias, +
+ Equipo {{project}} +
diff --git a/app/config/locale/templates/es.email.auth.recovery.tpl b/app/config/locale/templates/es.email.auth.recovery.tpl new file mode 100644 index 0000000000..6f78fffa7c --- /dev/null +++ b/app/config/locale/templates/es.email.auth.recovery.tpl @@ -0,0 +1,24 @@ + + +
+ Hola {{name}}, +
+
+ Sigue este enlace para reestablecer tu contraseña de {{project}}. +
+ {{redirect}} +
+
+ Si no has pedido reestablecer tu contraseña, puedes ignorar este mensaje. +
+
+ Gracias, +
+ Equipo {{project}} +
diff --git a/app/config/locale/templates/gr.email.auth.confirm.tpl b/app/config/locale/templates/gr.email.auth.confirm.tpl new file mode 100644 index 0000000000..a62445476b --- /dev/null +++ b/app/config/locale/templates/gr.email.auth.confirm.tpl @@ -0,0 +1,24 @@ + + +
+ Γεια σου {{name}}, +
+
+ Ακολούθησε αυτό τον σύνδεσμο για να επιβεβαιώσεις τη διεύθυνση email σου. +
+ {{redirect}} +
+
+ Αν δεν ζήτησες να επιβεβαιώσεις αυτή τη διεύθυνση, μπορείς να αγνοήσεις αυτό το μήνυμα. +
+
+ Ευχαριστούμε, +
+ Η ομάδα του {{project}} +
\ No newline at end of file diff --git a/app/config/locale/templates/gr.email.auth.invitation.tpl b/app/config/locale/templates/gr.email.auth.invitation.tpl new file mode 100644 index 0000000000..101a1c673c --- /dev/null +++ b/app/config/locale/templates/gr.email.auth.invitation.tpl @@ -0,0 +1,27 @@ + + +
+ Γεια, +
+
+ Έλαβες αυτό το email επειδή ο {{owner}} σε προσκάλεσε να γίνεις μέλος της ομάδας {{team}} στο {{project}}. +
+
+ Ακολούθησε αυτό τον σύνδεσμο για να γίνεις μέλος της ομάδας {{team}}: +
+ {{redirect}} +
+
+ Άν δεν ενδιαφέρεσαι, μπορείς να αγνοήσεις αυτό το μήνυμα. +
+
+ Ευχαριστούμε, +
+ Η ομάδα του {{project}} +
diff --git a/app/config/locale/templates/gr.email.auth.recovery.tpl b/app/config/locale/templates/gr.email.auth.recovery.tpl new file mode 100644 index 0000000000..cae164df22 --- /dev/null +++ b/app/config/locale/templates/gr.email.auth.recovery.tpl @@ -0,0 +1,24 @@ + + +
+ Γεια σου {{name}}, +
+
+ Ακολούθησε αυτό τον σύνδεσμο για να επαναφέρεις τον κωδικό πρόσβασής σου για το {{project}}. +
+ {{redirect}} +
+
+ Άν δεν ζήτησες αλλαγή κωδικού πρόσβασης, μπορείς να αγνοήσεις αυτο το μήνυμα. +
+
+ Ευχαριστούμε, +
+ Η ομάδα του {{project}} +
diff --git a/app/config/locale/templates/he.email.auth.confirm.tpl b/app/config/locale/templates/he.email.auth.confirm.tpl index ba18e2a064..bc9189a16f 100644 --- a/app/config/locale/templates/he.email.auth.confirm.tpl +++ b/app/config/locale/templates/he.email.auth.confirm.tpl @@ -10,15 +10,15 @@ שלום {{name}},

- לחץ\י על הלינק הבא על מנת לאמת את החשבון שלך. + נא ללחוץ על הקישור שלהלן כדי לאמת את החשבון שלך.
{{redirect}}

- במידה ולא ביקשת לאמת את כתובת המייל הזאת, את\ה יכול\ה להתעלם ממייל זה. + אם לא ביקשת לאמת את כתובת הדוא״ל, ניתן להתעלם מההודעה זו.

- תודה, + בברכה,
צוות {{project}} \ No newline at end of file diff --git a/app/config/locale/templates/he.email.auth.invitation.tpl b/app/config/locale/templates/he.email.auth.invitation.tpl index ca204cb4c3..a7514affda 100644 --- a/app/config/locale/templates/he.email.auth.invitation.tpl +++ b/app/config/locale/templates/he.email.auth.invitation.tpl @@ -10,18 +10,18 @@ שלום,

- מייל זה נשלח אליך בגלל ש-{{owner}} רוצה להזמין אותך להפוך לחבר\ת צוות בצוות {{team}} ב-{{project}}. + הודעת דוא״ל זו נשלחה אליך כי {{owner}} ביקש להזמינך להצטרף לצוות {{team}} ב־{{project}}.

- בכדי להצטרף לצוות {{team}}, לחץ על הלינק: + כדי להצטרף לצוות {{team}}, נא ללחוץ על הקישור:
{{redirect}}

- במידה ואינך מעוניין\ת, אנא התעלם\י ממייל זה. + אם איך לך עניין להצטרף לצוות, ניתן להתעלם מהודעת דוא״ל זו.

- תודה, + בברכה,
צוות {{project}} diff --git a/app/config/locale/templates/he.email.auth.recovery.tpl b/app/config/locale/templates/he.email.auth.recovery.tpl index 71f7015d35..e349365f07 100644 --- a/app/config/locale/templates/he.email.auth.recovery.tpl +++ b/app/config/locale/templates/he.email.auth.recovery.tpl @@ -10,15 +10,15 @@ שלום {{name}},

- לחץ\י על הלינק בכדי לאפס את הסיסמא שלך ב-{{project}}. + נא ללחוץ על הקישור שלהלן כדי לאפס את הסיסמה שלך ב־{{project}}.
{{redirect}}

- במידה ולא ביקשת לאפס את סיסמתך, את\ה יכול\ה להתעלם ממייל זה. + אם לא ביקשת לאפס את סיסמתך, ניתן להתעלם מהודעת דוא״ל זו.

- תודה, + בברכה,
צוות {{project}} diff --git a/app/config/locale/templates/it.email.auth.confirm.tpl b/app/config/locale/templates/it.email.auth.confirm.tpl new file mode 100644 index 0000000000..8106722d8d --- /dev/null +++ b/app/config/locale/templates/it.email.auth.confirm.tpl @@ -0,0 +1,25 @@ + + + +
+ Ciao {{name}}, +
+
+ Segui questo link per verificare il tuo indirizzo email. +
+ {{redirect}} +
+
+ Se non hai chiesto di verificare questo indirizzo, puoi ignorare questo messaggio. +
+
+ Grazie, +
+ {{project}} squadra +
\ No newline at end of file diff --git a/app/config/locale/templates/it.email.auth.invitation.tpl b/app/config/locale/templates/it.email.auth.invitation.tpl new file mode 100644 index 0000000000..be7becac4e --- /dev/null +++ b/app/config/locale/templates/it.email.auth.invitation.tpl @@ -0,0 +1,28 @@ + + + +
+ Ciao, +
+
+ Questa mail ti stata inviata perch {{owner}} volevo invitarti a diventare un membro del team al {{team}} squadra a {{project}}. +
+
+ Segui questo link per unirti a {{team}} squadra: +
+ {{redirect}} +
+
+ Se non sei interessato, puoi ignorare questo messaggio. +
+
+ Grazie, +
+ {{project}} squadra +
\ No newline at end of file diff --git a/app/config/locale/templates/it.email.auth.recovery.tpl b/app/config/locale/templates/it.email.auth.recovery.tpl new file mode 100644 index 0000000000..6a5adb5cbe --- /dev/null +++ b/app/config/locale/templates/it.email.auth.recovery.tpl @@ -0,0 +1,24 @@ + + +
+ Ciao {{name}}, +
+
+ Segui questo link per reimpostare la tua {{project}} password. +
+ {{redirect}} +
+
+ Se non hai chiesto di reimpostare la password, puoi ignorare questo messaggio. +
+
+ Grazie, +
+ {{project}} squadra +
\ No newline at end of file diff --git a/app/config/locale/templates/pt-br.email.auth.confirm.tpl b/app/config/locale/templates/pt-br.email.auth.confirm.tpl new file mode 100644 index 0000000000..aaee0d5ba8 --- /dev/null +++ b/app/config/locale/templates/pt-br.email.auth.confirm.tpl @@ -0,0 +1,24 @@ + + +
+ Olá {{name}}, +
+
+ Por favor, confirme o seu email acessando este link abaixo. +
+ {{redirect}} +
+
+ Se a confirmação de email não foi solicitada por você, ignore esta mensagem. +
+
+ Atenciosamente, +
+ Equipe {{project}} +
\ No newline at end of file diff --git a/app/config/locale/templates/pt-br.email.auth.invitation.tpl b/app/config/locale/templates/pt-br.email.auth.invitation.tpl new file mode 100644 index 0000000000..e7a5645c5b --- /dev/null +++ b/app/config/locale/templates/pt-br.email.auth.invitation.tpl @@ -0,0 +1,27 @@ + + +
+ Olá, +
+
+ Este email foi enviado a você porque
{{owner}} deseja lhe convidar a se tornar membro da equipe {{team}} no {{project}}. +
+
+ Siga este link para se juntar a equipe {{team}}: +
+ {{redirect}} +
+
+ Se não estiver interessado, por favor ignore esta mensagem. +
+
+ Atenciosamente, +
+ Equipe {{project}} +
diff --git a/app/config/locale/templates/pt-br.email.auth.recovery.tpl b/app/config/locale/templates/pt-br.email.auth.recovery.tpl new file mode 100644 index 0000000000..e70a712cbf --- /dev/null +++ b/app/config/locale/templates/pt-br.email.auth.recovery.tpl @@ -0,0 +1,24 @@ + + +
+ Olá {{name}}, +
+
+ Acesse este link para redefinir sua senha do {{project}}. +
+ {{redirect}} +
+
+ Se você não solicitou a redefinição de senha, por favor ignore esta mensagem. +
+
+ Atenciosamente, +
+ Equipe {{project}} +
diff --git a/app/config/providers.php b/app/config/providers.php index 7dc70c92fd..9e5f329ebb 100644 --- a/app/config/providers.php +++ b/app/config/providers.php @@ -19,12 +19,12 @@ return [ 'gitlab' => [ 'developers' => 'https://docs.gitlab.com/ee/api/', 'icon' => 'icon-gitlab', - 'enabled' => false, + 'enabled' => true, ], 'google' => [ 'developers' => 'https://developers.google.com/', 'icon' => 'icon-google', - 'enabled' => false, + 'enabled' => true, ], 'instagram' => [ 'developers' => 'https://www.instagram.com/developer/', diff --git a/app/config/sdks.php b/app/config/sdks.php index 209d5d934c..21c864c5c6 100644 --- a/app/config/sdks.php +++ b/app/config/sdks.php @@ -60,7 +60,7 @@ return [ 'tag' => 'Soon', ], [ - 'label' => '.NET', + 'label' => 'C#', 'versions' => [], 'logo' => 'dotnet.svg', 'link' => 'https://...', diff --git a/app/controllers/account.php b/app/controllers/account.php index a348b0bc66..cb95a0f3e1 100644 --- a/app/controllers/account.php +++ b/app/controllers/account.php @@ -39,7 +39,8 @@ $utopia->get('/v1/account') 'registration', 'confirm', 'name', - ], $oauthKeys + ], + $oauthKeys )), ['roles' => Authorization::getRoles()])); } ); @@ -133,7 +134,6 @@ $utopia->get('/v1/account/security') ->label('sdk.description', 'Get currently logged in user list of latest security activity logs. Each log returns user IP address, location and date and time of log.') ->action( function () use ($response, $register, $project, $user) { - $ad = new \Audit\Adapter\MySQL($register->get('db')); $ad->setNamespace('app_'.$project->getUid()); $au = new \Audit\Audit($ad, $user->getUid(), $user->getAttribute('type'), '', '', ''); @@ -202,7 +202,9 @@ $utopia->patch('/v1/account/name') ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateName') ->label('sdk.description', 'Update currently logged in user account name.') - ->param('name', '', function () {return new Text(100);}, 'User name') + ->param('name', '', function () { + return new Text(100); + }, 'User name') ->action( function ($name) use ($response, $user, $projectDB, $audit) { $user = $projectDB->updateDocument(array_merge($user->getArrayCopy(), [ @@ -226,8 +228,12 @@ $utopia->patch('/v1/account/password') ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePassword') ->label('sdk.description', 'Update currently logged in user password. For validation, user is required to pass the password twice.') - ->param('password', '', function () {return new Password();}, 'New password') - ->param('old-password', '', function () {return new Password();}, 'Old password') + ->param('password', '', function () { + return new Password(); + }, 'New password') + ->param('old-password', '', function () { + return new Password(); + }, 'Old password') ->action( function ($password, $oldPassword) use ($response, $user, $projectDB, $audit) { if (!Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password @@ -255,8 +261,12 @@ $utopia->patch('/v1/account/email') ->label('sdk.namespace', 'account') ->label('sdk.method', 'updateEmail') ->label('sdk.description', 'Update currently logged in user account email address. After changing user address, user confirmation status is being reset and a new confirmation mail is sent. For security measures, user password is required to complete this request.') - ->param('email', '', function () {return new Email();}, 'Email Address') - ->param('password', '', function () {return new Password();}, 'User Password') + ->param('email', '', function () { + return new Email(); + }, 'Email Address') + ->param('password', '', function () { + return new Password(); + }, 'User Password') ->action( function ($email, $password) use ($response, $user, $projectDB, $audit) { if (!Auth::passwordVerify($password, $user->getAttribute('password'))) { // Double check user password @@ -298,7 +308,9 @@ $utopia->patch('/v1/account/prefs') ->label('scope', 'account') ->label('sdk.namespace', 'account') ->label('sdk.method', 'updatePrefs') - ->param('prefs', '', function () {return new \Utopia\Validator\Mock();}, 'Prefs key-value JSON object string.') + ->param('prefs', '', function () { + return new \Utopia\Validator\Mock(); + }, 'Prefs key-value JSON object string.') ->label('sdk.description', 'Update currently logged in user account preferences. You can pass only the specific settings you wish to update.') ->action( function ($prefs) use ($response, $user, $projectDB, $audit) { diff --git a/app/controllers/auth.php b/app/controllers/auth.php index 073abcab00..87c21ec1db 100644 --- a/app/controllers/auth.php +++ b/app/controllers/auth.php @@ -28,28 +28,40 @@ $utopia->post('/v1/auth/register') ->label('sdk.description', "Use this endpoint to allow a new user to register an account in your project. Use the success and failure URL's to redirect users back to your application after signup completes.\n\nIf registration completes successfully user will be sent with a confirmation email in order to confirm he is the owner of the account email address. Use the confirmation parameter to redirect the user from the confirmation email back to your app. When the user is redirected, use the /auth/confirm endpoint to complete the account confirmation.\n\nPlease notice that in order to avoid a [Redirect Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URL's are the once from domains you have set when added your platforms in the console interface.\n\nWhen accessing this route using Javascript from the browser, success and failure parameter URLs are required. Appwrite server will respond with a 301 redirect status code and will set the user session cookie. This behavior is enforced because modern browsers are limiting 3rd party cookies in XHR of fetch requests to protect user privacy.") ->label('sdk.cookies', true) ->label('abuse-limit', 10) - ->param('email', '', function () {return new Email();}, 'Account email') - ->param('password', '', function () {return new Password();}, 'User password') - ->param('confirmation', '', function () use ($clients) {return new Host($clients);}, 'Confirmation URL to redirect user after confirm token has been sent to user email') // TODO add our own built-in confirm page - ->param('success', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration succeed', true) - ->param('failure', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration failed', true) - ->param('name', '', function () {return new Text(100);}, 'User name', true) + ->param('email', '', function () { + return new Email(); + }, 'Account email') + ->param('password', '', function () { + return new Password(); + }, 'User password') + ->param('confirm', '', function () use ($clients) { + return new Host($clients); + }, 'Confirmation URL to redirect user after confirm token has been sent to user email') // TODO add our own built-in confirm page + ->param('success', null, function () use ($clients) { + return new Host($clients); + }, 'Redirect when registration succeed', true) + ->param('failure', null, function () use ($clients) { + return new Host($clients); + }, 'Redirect when registration failed', true) + ->param('name', '', function () { + return new Text(100); + }, 'User name', true) ->action( - function ($email, $password, $confirmation, $success, $failure, $name) use ($request, $response, $register, $audit, $projectDB, $project, $webhook) { - if('console' === $project->getUid()) { + function ($email, $password, $confirm, $success, $failure, $name) use ($request, $response, $register, $audit, $projectDB, $project, $webhook) { + if ('console' === $project->getUid()) { $whitlistEmails = $project->getAttribute('authWhitelistEmails'); $whitlistIPs = $project->getAttribute('authWhitelistIPs'); $whitlistDomains = $project->getAttribute('authWhitelistDomains'); - if(!empty($whitlistEmails) && !in_array($email, $whitlistEmails)) { + if (!empty($whitlistEmails) && !in_array($email, $whitlistEmails)) { throw new Exception('Console registration is restricted to specific emails. Contact your administrator for more information.', 401); } - if(!empty($whitlistIPs) && !in_array($request->getIP(), $whitlistIPs)) { + if (!empty($whitlistIPs) && !in_array($request->getIP(), $whitlistIPs)) { throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401); } - if(!empty($whitlistDomains) && !in_array(substr(strrchr($email, "@"), 1), $whitlistDomains)) { + if (!empty($whitlistDomains) && !in_array(substr(strrchr($email, "@"), 1), $whitlistDomains)) { throw new Exception('Console registration is restricted to specific domains. Contact your administrator for more information.', 401); } } @@ -132,16 +144,16 @@ $utopia->post('/v1/auth/register') // Send email address confirmation email - $confirmation = Template::parseURL($confirmation); - $confirmation['query'] = Template::mergeQuery(((isset($confirmation['query'])) ? $confirmation['query'] : ''), ['userId' => $user->getUid(), 'token' => $confirmSecret]); - $confirmation = Template::unParseURL($confirmation); + $confirm = Template::parseURL($confirm); + $confirm['query'] = Template::mergeQuery(((isset($confirm['query'])) ? $confirm['query'] : ''), ['userId' => $user->getUid(), 'token' => $confirmSecret]); + $confirm = Template::unParseURL($confirm); $body = new Template(__DIR__.'/../config/locale/templates/'.Locale::getText('auth.emails.confirm.body')); $body ->setParam('{{direction}}', Locale::getText('settings.direction')) ->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]'])) ->setParam('{{name}}', $name) - ->setParam('{{redirect}}', $confirmation) + ->setParam('{{redirect}}', $confirm) ; $mail = $register->get('smtp'); /* @var $mail \PHPMailer\PHPMailer\PHPMailer */ @@ -194,8 +206,12 @@ $utopia->post('/v1/auth/register/confirm') ->label('sdk.description', 'Use this endpoint to complete the confirmation of the user account email address. Both the **userId** and **token** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the /auth/register endpoint.') ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},userId:{param-userId}') - ->param('userId', '', function () {return new UID();}, 'User unique ID') - ->param('token', '', function () {return new Text(256);}, 'Confirmation secret token') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID') + ->param('token', '', function () { + return new Text(256); + }, 'Confirmation secret token') ->action( function ($userId, $token) use ($response, $request, $projectDB, $audit) { $profile = $projectDB->getCollection([ // Get user by email address @@ -244,9 +260,11 @@ $utopia->post('/v1/auth/register/confirm/resend') ->label('sdk.description', "This endpoint allows the user to request your app to resend him his email confirmation message. The redirect arguments acts the same way as in /auth/register endpoint.\n\nPlease notice that in order to avoid a [Redirect Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URL's are the once from domains you have set when added your platforms in the console interface.") ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},userId:{param-userId}') - ->param('confirmation', '', function () use ($clients) {return new Host($clients);}, 'Confirmation URL to redirect user to your app after confirm token has been sent to user email.') + ->param('confirm', '', function () use ($clients) { + return new Host($clients); + }, 'Confirmation URL to redirect user to your app after confirm token has been sent to user email.') ->action( - function ($confirmation) use ($response, $request, $projectDB, $user, $register, $project) { + function ($confirm) use ($response, $request, $projectDB, $user, $register, $project) { if ($user->getAttribute('confirm', false)) { throw new Exception('Email address is already confirmed', 400); } @@ -269,16 +287,16 @@ $utopia->post('/v1/auth/register/confirm/resend') throw new Exception('Failed saving user to DB', 500); } - $confirmation = Template::parseURL($confirmation); - $confirmation['query'] = Template::mergeQuery(((isset($confirmation['query'])) ? $confirmation['query'] : ''), ['userId' => $user->getUid(), 'token' => $secret]); - $confirmation = Template::unParseURL($confirmation); + $confirm = Template::parseURL($confirm); + $confirm['query'] = Template::mergeQuery(((isset($confirm['query'])) ? $confirm['query'] : ''), ['userId' => $user->getUid(), 'token' => $secret]); + $confirm = Template::unParseURL($confirm); $body = new Template(__DIR__.'/../config/locale/templates/'.Locale::getText('auth.emails.confirm.body')); $body ->setParam('{{direction}}', Locale::getText('settings.direction')) ->setParam('{{project}}', $project->getAttribute('name', ['[APP-NAME]'])) ->setParam('{{name}}', $user->getAttribute('name')) - ->setParam('{{redirect}}', $confirmation) + ->setParam('{{redirect}}', $confirm) ; $mail = $register->get('smtp'); /* @var $mail \PHPMailer\PHPMailer\PHPMailer */ @@ -309,10 +327,18 @@ $utopia->post('/v1/auth/login') ->label('sdk.cookies', true) ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},email:{param-email}') - ->param('email', '', function () {return new Email();}, 'User account email address') - ->param('password', '', function () {return new Password();}, 'User account password') - ->param('success', null, function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a successful login attempt.') - ->param('failure', null, function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a failed login attempt.') + ->param('email', '', function () { + return new Email(); + }, 'User account email address') + ->param('password', '', function () { + return new Password(); + }, 'User account password') + ->param('success', null, function () use ($clients) { + return new Host($clients); + }, 'URL to redirect back to your app after a successful login attempt.') + ->param('failure', null, function () use ($clients) { + return new Host($clients); + }, 'URL to redirect back to your app after a failed login attempt.') ->action( function ($email, $password, $success, $failure) use ($response, $request, $projectDB, $audit, $webhook) { $profile = $projectDB->getCollection([ // Get user by email address @@ -423,7 +449,9 @@ $utopia->delete('/v1/auth/logout/:id') ->label('sdk.method', 'logoutBySession') ->label('sdk.description', 'Use this endpoint to log out the currently logged in user from all his account sessions across all his different devices. When using the option id argument, only the session unique ID provider will be deleted.') ->label('abuse-limit', 100) - ->param('id', null, function () {return new UID();}, 'User specific session unique ID number. if 0 delete all sessions.') + ->param('id', null, function () { + return new UID(); + }, 'User specific session unique ID number. if 0 delete all sessions.') ->action( function ($id) use ($response, $request, $user, $projectDB, $audit) { $tokens = $user->getAttribute('tokens', []); @@ -457,8 +485,12 @@ $utopia->post('/v1/auth/recovery') ->label('sdk.description', 'Sends the user an email with a temporary secret token for password reset. When the user clicks the confirmation link he is redirected back to your app password reset redirect URL with a secret token and email address values attached to the URL query string. Use the query string params to submit a request to the /auth/password/reset endpoint to complete the process.') ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},email:{param-email}') - ->param('email', '', function () {return new Email();}, 'User account email address.') - ->param('reset', '', function () use ($clients) {return new Host($clients);}, 'Reset URL in your app to redirect the user after the reset token has been sent to the user email.') + ->param('email', '', function () { + return new Email(); + }, 'User account email address.') + ->param('reset', '', function () use ($clients) { + return new Host($clients); + }, 'Reset URL in your app to redirect the user after the reset token has been sent to the user email.') ->action( function ($email, $reset) use ($request, $response, $projectDB, $register, $audit, $project) { $profile = $projectDB->getCollection([ // Get user by email address @@ -537,10 +569,18 @@ $utopia->put('/v1/auth/recovery/reset') ->label('sdk.description', "Use this endpoint to complete the user account password reset. Both the **userId** and **token** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the /auth/recovery endpoint.\n\nPlease notice that in order to avoid a [Redirect Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URL's are the once from domains you have set when added your platforms in the console interface.") ->label('abuse-limit', 10) ->label('abuse-key', 'url:{url},userId:{param-userId}') - ->param('userId', '', function () {return new UID();}, 'User account email address.') - ->param('token', '', function () {return new Text(256);}, 'Valid reset token.') - ->param('password-a', '', function () {return new Password();}, 'New password.') - ->param('password-b', '', function () {return new Password();}, 'New password again.') + ->param('userId', '', function () { + return new UID(); + }, 'User account email address.') + ->param('token', '', function () { + return new Text(256); + }, 'Valid reset token.') + ->param('password-a', '', function () { + return new Password(); + }, 'New password.') + ->param('password-b', '', function () { + return new Password(); + }, 'New password again.') ->action( function ($userId, $token, $passwordA, $passwordB) use ($response, $projectDB, $audit) { if ($passwordA !== $passwordB) { @@ -597,11 +637,18 @@ $utopia->get('/v1/auth/oauth/:provider') ->label('scope', 'auth') ->label('sdk.namespace', 'auth') ->label('sdk.method', 'oauth') + ->label('sdk.location', true) ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('provider', '', function () use ($providers) {return new WhiteList(array_keys($providers));}, 'OAuth Provider') - ->param('success', '', function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a successful login attempt.', true) - ->param('failure', '', function () use ($clients) {return new Host($clients);}, 'URL to redirect back to your app after a failed login attempt.', true) + ->param('provider', '', function () use ($providers) { + return new WhiteList(array_keys($providers)); + }, 'OAuth Provider') + ->param('success', '', function () use ($clients) { + return new Host($clients); + }, 'URL to redirect back to your app after a successful login attempt.', true) + ->param('failure', '', function () use ($clients) { + return new Host($clients); + }, 'URL to redirect back to your app after a failed login attempt.', true) ->action( function ($provider, $success, $failure) use ($response, $request, $project) { $callback = $request->getServer('REQUEST_SCHEME', 'https').'://'.$request->getServer('HTTP_HOST').'/v1/auth/oauth/callback/'.$provider.'/'.$project->getUid(); @@ -635,14 +682,23 @@ $utopia->get('/v1/auth/oauth/callback/:provider/:projectId') ->desc('OAuth Callback') ->label('error', __DIR__.'/../views/general/error.phtml') ->label('scope', 'auth') - ->label('sdk.namespace', 'auth') - ->label('sdk.method', 'oauthCallback') + //->label('sdk.namespace', 'auth') + //->label('sdk.method', 'oauthCallback') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') - ->param('projectId', '', function () {return new Text(1024);}, 'Project unique ID') - ->param('provider', '', function () use ($providers) {return new WhiteList(array_keys($providers));}, 'OAuth provider') - ->param('code', '', function () {return new Text(1024);}, 'OAuth code') - ->param('state', '', function () {return new Text(2048);}, 'Login state params', true) + ->label('docs', false) + ->param('projectId', '', function () { + return new Text(1024); + }, 'Project unique ID') + ->param('provider', '', function () use ($providers) { + return new WhiteList(array_keys($providers)); + }, 'OAuth provider') + ->param('code', '', function () { + return new Text(1024); + }, 'OAuth code') + ->param('state', '', function () { + return new Text(2048); + }, 'Login state params', true) ->action( function ($projectId, $provider, $code, $state) use ($response, $request, $domain) { $response->redirect($request->getServer('REQUEST_SCHEME', 'https').'://'.$domain.'/v1/auth/oauth/'.$provider.'/redirect?' @@ -655,14 +711,20 @@ $utopia->get('/v1/auth/oauth/:provider/redirect') ->label('error', __DIR__.'/../views/general/error.phtml') ->label('webhook', 'auth.oauth') ->label('scope', 'auth') - ->label('sdk.namespace', 'auth') - ->label('sdk.method', 'oauthRedirect') + //->label('sdk.namespace', 'auth') + //->label('sdk.method', 'oauthRedirect') ->label('abuse-limit', 50) ->label('abuse-key', 'ip:{ip}') ->label('docs', false) - ->param('provider', '', function () use ($providers) {return new WhiteList(array_keys($providers));}, 'OAuth provider') - ->param('code', '', function () {return new Text(1024);}, 'OAuth code') - ->param('state', '', function () {return new Text(2048);}, 'OAuth state params', true) + ->param('provider', '', function () use ($providers) { + return new WhiteList(array_keys($providers)); + }, 'OAuth provider') + ->param('code', '', function () { + return new Text(1024); + }, 'OAuth code') + ->param('state', '', function () { + return new Text(2048); + }, 'OAuth state params', true) ->action( function ($provider, $code, $state) use ($response, $request, $user, $projectDB, $project, $audit) { $callback = $request->getServer('REQUEST_SCHEME', 'https').'://'.$request->getServer('HTTP_HOST').'/v1/auth/oauth/callback/'.$provider.'/'.$project->getUid(); @@ -716,7 +778,7 @@ $utopia->get('/v1/auth/oauth/:provider/redirect') } $oauthID = $oauth->getUserID($accessToken); - + if (empty($oauthID)) { if (!empty($state['failure'])) { $response->redirect($state['failure'], 301, 0); @@ -726,7 +788,7 @@ $utopia->get('/v1/auth/oauth/:provider/redirect') } $current = Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_LOGIN, Auth::$secret); - + if ($current) { $projectDB->deleteDocument($current); //throw new Exception('User already logged in', 401); } @@ -740,6 +802,7 @@ $utopia->get('/v1/auth/oauth/:provider/redirect') ], ]) : $user; + if (empty($user)) { // No user logged in or with oauth provider ID, create new one or connect with account with same email $name = $oauth->getUserName($accessToken); $email = $oauth->getUserEmail($accessToken); @@ -753,7 +816,7 @@ $utopia->get('/v1/auth/oauth/:provider/redirect') ], ]); - if (empty($user->getUid())) { // Last option -> create user alone, generate random password + if (!$user || empty($user->getUid())) { // Last option -> create user alone, generate random password Authorization::disable(); $user = $projectDB->createDocument([ diff --git a/app/controllers/avatars.php b/app/controllers/avatars.php index 039fb430de..77580a59b4 100644 --- a/app/controllers/avatars.php +++ b/app/controllers/avatars.php @@ -87,45 +87,81 @@ $avatarCallback = function ($type, $code, $width, $height, $quality) use ($types $utopia->get('/v1/avatars/credit-cards/:code') ->desc('Get Credit Card Icon') - ->param('code', '', function () use ($types) {return new WhiteList(array_keys($types['credit-cards'])); }, 'Credit Card Code. Possible values: '.implode(', ', array_keys($types['credit-cards'])).'.') - ->param('width', 100, function () {return new Range(0, 2000);}, 'Image width. Pass an integer between 0 to 2000. Defaults to 100', true) - ->param('height', 100, function () {return new Range(0, 2000);}, 'Image height. Pass an integer between 0 to 2000. Defaults to 100', true) - ->param('quality', 100, function () {return new Range(0, 100);}, 'Image quality. Pass an integer between 0 to 100. Defaults to 100', true) + ->param('code', '', function () use ($types) { + return new WhiteList(array_keys($types['credit-cards'])); + }, 'Credit Card Code. Possible values: '.implode(', ', array_keys($types['credit-cards'])).'.') + ->param('width', 100, function () { + return new Range(0, 2000); + }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100', true) + ->param('height', 100, function () { + return new Range(0, 2000); + }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100', true) + ->param('quality', 100, function () { + return new Range(0, 100); + }, 'Image quality. Pass an integer between 0 to 100. Defaults to 100', true) ->label('scope', 'avatars.read') ->label('sdk.namespace', 'avatars') ->label('sdk.method', 'getCreditCard') ->label('sdk.description', 'Need to display your users with your billing method or there payment methods? The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.') - ->action(function ($code, $width, $height, $quality) use ($avatarCallback) {return $avatarCallback('credit-cards', $code, $width, $height, $quality);}); + ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { + return $avatarCallback('credit-cards', $code, $width, $height, $quality); + }); $utopia->get('/v1/avatars/browsers/:code') ->desc('Get Browser Icon') - ->param('code', '', function () use ($types) {return new WhiteList(array_keys($types['browsers'])); }, 'Browser Code.') - ->param('width', 100, function () {return new Range(0, 2000);}, 'Image width. Pass an integer between 0 to 2000. Defaults to 100', true) - ->param('height', 100, function () {return new Range(0, 2000);}, 'Image height. Pass an integer between 0 to 2000. Defaults to 100', true) - ->param('quality', 100, function () {return new Range(0, 100);}, 'Image quality. Pass an integer between 0 to 100. Defaults to 100', true) + ->param('code', '', function () use ($types) { + return new WhiteList(array_keys($types['browsers'])); + }, 'Browser Code.') + ->param('width', 100, function () { + return new Range(0, 2000); + }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100', true) + ->param('height', 100, function () { + return new Range(0, 2000); + }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100', true) + ->param('quality', 100, function () { + return new Range(0, 100); + }, 'Image quality. Pass an integer between 0 to 100. Defaults to 100', true) ->label('scope', 'avatars.read') ->label('sdk.namespace', 'avatars') ->label('sdk.method', 'getBrowser') ->label('sdk.description', 'You can use this endpoint to show different browser icons to your users, The code argument receives the browser code as appear in your user /account/sessions endpoint. Use width, height and quality arguments to change the output settings.') - ->action(function ($code, $width, $height, $quality) use ($avatarCallback) {return $avatarCallback('browsers', $code, $width, $height, $quality);}); + ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { + return $avatarCallback('browsers', $code, $width, $height, $quality); + }); $utopia->get('/v1/avatars/flags/:code') ->desc('Get Country Flag') - ->param('code', '', function () use ($types) {return new WhiteList(array_keys($types['flags'])); }, 'Country Code. ISO Alpha-2 country code format.') - ->param('width', 100, function () {return new Range(0, 2000);}, 'Image width. Pass an integer between 0 to 2000. Defaults to 100', true) - ->param('height', 100, function () {return new Range(0, 2000);}, 'Image height. Pass an integer between 0 to 2000. Defaults to 100', true) - ->param('quality', 100, function () {return new Range(0, 100);}, 'Image quality. Pass an integer between 0 to 100. Defaults to 100', true) + ->param('code', '', function () use ($types) { + return new WhiteList(array_keys($types['flags'])); + }, 'Country Code. ISO Alpha-2 country code format.') + ->param('width', 100, function () { + return new Range(0, 2000); + }, 'Image width. Pass an integer between 0 to 2000. Defaults to 100', true) + ->param('height', 100, function () { + return new Range(0, 2000); + }, 'Image height. Pass an integer between 0 to 2000. Defaults to 100', true) + ->param('quality', 100, function () { + return new Range(0, 100); + }, 'Image quality. Pass an integer between 0 to 100. Defaults to 100', true) ->label('scope', 'avatars.read') ->label('sdk.namespace', 'avatars') ->label('sdk.method', 'getFlag') ->label('sdk.description', 'You can use this endpoint to show different country flags icons to your users, The code argument receives the a 2 letter country code. Use width, height and quality arguments to change the output settings.') - ->action(function ($code, $width, $height, $quality) use ($avatarCallback) {return $avatarCallback('flags', $code, $width, $height, $quality);}); + ->action(function ($code, $width, $height, $quality) use ($avatarCallback) { + return $avatarCallback('flags', $code, $width, $height, $quality); + }); $utopia->get('/v1/avatars/image') ->desc('Get Image from URL') - ->param('url', '', function () {return new URL();}, 'Image URL which you want to crop.') - ->param('width', 400, function () {return new Range(0, 2000);}, 'Resize preview image width, Pass an integer between 0 to 4000', true) - ->param('height', 400, function () {return new Range(0, 2000);}, 'Resize preview image height, Pass an integer between 0 to 4000', true) + ->param('url', '', function () { + return new URL(); + }, 'Image URL which you want to crop.') + ->param('width', 400, function () { + return new Range(0, 2000); + }, 'Resize preview image width, Pass an integer between 0 to 4000', true) + ->param('height', 400, function () { + return new Range(0, 2000); + }, 'Resize preview image height, Pass an integer between 0 to 4000', true) ->label('scope', 'avatars.read') ->label('sdk.namespace', 'avatars') ->label('sdk.method', 'getImage') @@ -190,7 +226,9 @@ $utopia->get('/v1/avatars/image') $utopia->get('/v1/avatars/favicon') ->desc('Get Favicon') - ->param('url', '', function () {return new URL();}, 'Website URL which you want to fetch the favicon from.') + ->param('url', '', function () { + return new URL(); + }, 'Website URL which you want to fetch the favicon from.') ->label('scope', 'avatars.read') ->label('sdk.namespace', 'avatars') ->label('sdk.method', 'getFavicon') @@ -339,10 +377,18 @@ $utopia->get('/v1/avatars/favicon') $utopia->get('/v1/avatars/qr') ->desc('Text to QR Generator') - ->param('text', '', function () {return new Text(512);}, 'Plain text to be converted to QR code image') - ->param('size', 400, function () {return new Range(0, 1000);}, 'QR code size. Pass an integer between 0 to 1000. Defaults to 400.', true) - ->param('margin', 1, function () {return new Range(0, 10);}, 'Margin From Edge. Pass an integer between 0 to 10. Defaults to 1.', true) - ->param('download', 0, function () {return new Range(0, 1);}, 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true) + ->param('text', '', function () { + return new Text(512); + }, 'Plain text to be converted to QR code image') + ->param('size', 400, function () { + return new Range(0, 1000); + }, 'QR code size. Pass an integer between 0 to 1000. Defaults to 400.', true) + ->param('margin', 1, function () { + return new Range(0, 10); + }, 'Margin From Edge. Pass an integer between 0 to 10. Defaults to 1.', true) + ->param('download', 0, function () { + return new Range(0, 1); + }, 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true) ->label('scope', 'avatars.read') ->label('sdk.namespace', 'avatars') ->label('sdk.method', 'getQR') @@ -365,7 +411,6 @@ $utopia->get('/v1/avatars/qr') ->setContentType('image/png') ->send('', $writer->writeString($text)) ; - } ); diff --git a/app/controllers/console.php b/app/controllers/console.php index 222ec917c6..2a8caa44cc 100644 --- a/app/controllers/console.php +++ b/app/controllers/console.php @@ -175,7 +175,9 @@ $utopia->get('/console/database/collection') ->desc('Platform console project settings') ->label('permission', 'public') ->label('scope', 'console') - ->param('id', '', function () {return new UID();}, 'Collection unique ID.') + ->param('id', '', function () { + return new UID(); + }, 'Collection unique ID.') ->action(function ($id) use ($layout, $projectDB) { $collection = $projectDB->getDocument($id, false); @@ -216,7 +218,7 @@ $utopia->get('/console/users') $page->setParam('providers', $providers); $layout - ->setParam('title', APP_NAME.' - '.Locale::getText('console.users.title')) + ->setParam('title', APP_NAME.' - Users') ->setParam('body', $page); }); @@ -228,6 +230,6 @@ $utopia->get('/console/users/view') $page = new View(__DIR__.'/../views/console/users/view.phtml'); $layout - ->setParam('title', APP_NAME.' - '.Locale::getText('console.users.title')) + ->setParam('title', APP_NAME.' - View User') ->setParam('body', $page); }); diff --git a/app/controllers/database.php b/app/controllers/database.php index e330bd1171..7e80ecb95f 100644 --- a/app/controllers/database.php +++ b/app/controllers/database.php @@ -27,10 +27,18 @@ $utopia->get('/v1/database') ->label('sdk.namespace', 'database') ->label('sdk.method', 'listCollections') ->label('sdk.description', 'Get a list of all the user collections. You can use the query params to filter your results. On admin mode, this endpoint will return a list of all of the project collections. [Learn more about different API modes](/docs/modes).') - ->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true) - ->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) - ->param('offset', 0, function () {return new Range(0, 40000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true) + ->param('search', '', function () { + return new Text(256); + }, 'Search term to filter your list results.', true) + ->param('limit', 25, function () { + return new Range(0, 100); + }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) + ->param('offset', 0, function () { + return new Range(0, 40000); + }, 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('orderType', 'ASC', function () { + return new WhiteList(['ASC', 'DESC']); + }, 'Order result by ASC or DESC order.', true) ->action( function ($search, $limit, $offset, $orderType) use ($response, $projectDB) { /*$vl = new Structure($projectDB); @@ -74,7 +82,9 @@ $utopia->get('/v1/database/:collectionId') ->label('sdk.namespace', 'database') ->label('sdk.method', 'getCollection') ->label('sdk.description', 'Get collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.') - ->param('collectionId', '', function () {return new UID();}, 'Collection unique ID.') + ->param('collectionId', '', function () { + return new UID(); + }, 'Collection unique ID.') ->action( function ($collectionId) use ($response, $projectDB) { $collection = $projectDB->getDocument($collectionId, false); @@ -94,15 +104,23 @@ $utopia->post('/v1/database') ->label('sdk.namespace', 'database') ->label('sdk.method', 'createCollection') ->label('sdk.description', 'Create a new Collection.') - ->param('name', '', function () {return new Text(256);}, 'Collection name.') - ->param('read', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('rules', [], function () use ($projectDB) {return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES], ['$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => ['read' => [], 'write' => []]]));}, 'Array of [rule objects](/docs/rules). Each rule define a collection field name, data type and validation', true) + ->param('name', '', function () { + return new Text(256); + }, 'Collection name.') + ->param('read', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('write', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('rules', [], function () use ($projectDB) { + return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES], ['$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => ['read' => [], 'write' => []]])); + }, 'Array of [rule objects](/docs/rules). Each rule define a collection field name, data type and validation', true) ->action( function ($name, $read, $write, $rules) use ($response, $projectDB, $webhook, $audit) { $parsedRules = []; - foreach($rules as &$rule) { + foreach ($rules as &$rule) { $parsedRules[] = array_merge([ '$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => [ @@ -161,11 +179,21 @@ $utopia->put('/v1/database/:collectionId') ->label('sdk.namespace', 'database') ->label('sdk.method', 'updateCollection') ->label('sdk.description', 'Update collection by its unique ID.') - ->param('collectionId', '', function () {return new UID();}, 'Collection unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Collection name.') - ->param('read', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('rules', [], function () use ($projectDB) {return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES], ['$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => ['read' => [], 'write' => []]]));}, 'Array of [rule objects](/docs/rules). Each rule define a collection field name, data type and validation', true) + ->param('collectionId', '', function () { + return new UID(); + }, 'Collection unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Collection name.') + ->param('read', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('write', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('rules', [], function () use ($projectDB) { + return new ArrayList(new Collection($projectDB, [Database::SYSTEM_COLLECTION_RULES], ['$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => ['read' => [], 'write' => []]])); + }, 'Array of [rule objects](/docs/rules). Each rule define a collection field name, data type and validation', true) ->action( function ($collectionId, $name, $read, $write, $rules) use ($response, $projectDB) { $collection = $projectDB->getDocument($collectionId, false); @@ -176,7 +204,7 @@ $utopia->put('/v1/database/:collectionId') $parsedRules = []; - foreach($rules as &$rule) { + foreach ($rules as &$rule) { $parsedRules[] = array_merge([ '$collection' => Database::SYSTEM_COLLECTION_RULES, '$permissions' => [ @@ -211,7 +239,9 @@ $utopia->delete('/v1/database/:collectionId') ->label('sdk.namespace', 'database') ->label('sdk.method', 'deleteCollection') ->label('sdk.description', 'Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.') - ->param('collectionId', '', function () {return new UID();}, 'Collection unique ID.') + ->param('collectionId', '', function () { + return new UID(); + }, 'Collection unique ID.') ->action( function ($collectionId) use ($response, $projectDB, $audit) { $collection = $projectDB->getDocument($collectionId, false); @@ -240,16 +270,36 @@ $utopia->get('/v1/database/:collectionId/documents') ->label('sdk.namespace', 'database') ->label('sdk.method', 'listDocuments') ->label('sdk.description', 'Get a list of all the user documents. You can use the query params to filter your results. On admin mode, this endpoint will return a list of all of the project documents. [Learn more about different API modes](/docs/modes).') - ->param('collectionId', null, function () {return new UID();}, 'Collection unique ID.') - ->param('filters', [], function () {return new ArrayList(new Text(128));}, 'Array of filter strings. Each filter is constructed from a key name, comparison operator (=, !=, >, <, <=, >=) and a value. You can also use a dot (.) separator in attribute names to filter by child document attributes. Examples: \'name=John Doe\' or \'category.$uid>=5bed2d152c362\'', true) - ->param('offset', 0, function () {return new Range(0, 900000000);}, 'Offset value. Use this value to manage pagination.', true) - ->param('limit', 50, function () {return new Range(0, 1000);}, 'Maximum number of documents to return in response. Use this value to manage pagination.', true) - ->param('order-field', '$uid', function () {return new Text(128);}, 'Document field that results will be sorted by.', true) - ->param('order-type', 'ASC', function () {return new WhiteList(array('DESC', 'ASC'));}, 'Order direction. Possible values are DESC for descending order, or ASC for ascending order.', true) - ->param('order-cast', 'string', function () {return new WhiteList(array('int', 'string', 'date', 'time', 'datetime'));}, 'Order field type casting. Possible values are int, string, date, time or datetime. The database will attempt to cast the order field to the value you pass here. The default value is a string.', true) - ->param('search', '', function () {return new Text(256);}, 'Search query. Enter any free text search. The database will try to find a match against all document attributes and children.', true) - ->param('first', 0, function () {return new Range(0, 1);}, 'Return only first document. Pass 1 for true or 0 for false. The default value is 0.', true) - ->param('last', 0, function () {return new Range(0, 1);}, 'Return only last document. Pass 1 for true or 0 for false. The default value is 0.', true) + ->param('collectionId', null, function () { + return new UID(); + }, 'Collection unique ID.') + ->param('filters', [], function () { + return new ArrayList(new Text(128)); + }, 'Array of filter strings. Each filter is constructed from a key name, comparison operator (=, !=, >, <, <=, >=) and a value. You can also use a dot (.) separator in attribute names to filter by child document attributes. Examples: \'name=John Doe\' or \'category.$uid>=5bed2d152c362\'', true) + ->param('offset', 0, function () { + return new Range(0, 900000000); + }, 'Offset value. Use this value to manage pagination.', true) + ->param('limit', 50, function () { + return new Range(0, 1000); + }, 'Maximum number of documents to return in response. Use this value to manage pagination.', true) + ->param('order-field', '$uid', function () { + return new Text(128); + }, 'Document field that results will be sorted by.', true) + ->param('order-type', 'ASC', function () { + return new WhiteList(array('DESC', 'ASC')); + }, 'Order direction. Possible values are DESC for descending order, or ASC for ascending order.', true) + ->param('order-cast', 'string', function () { + return new WhiteList(array('int', 'string', 'date', 'time', 'datetime')); + }, 'Order field type casting. Possible values are int, string, date, time or datetime. The database will attempt to cast the order field to the value you pass here. The default value is a string.', true) + ->param('search', '', function () { + return new Text(256); + }, 'Search query. Enter any free text search. The database will try to find a match against all document attributes and children.', true) + ->param('first', 0, function () { + return new Range(0, 1); + }, 'Return only first document. Pass 1 for true or 0 for false. The default value is 0.', true) + ->param('last', 0, function () { + return new Range(0, 1); + }, 'Return only last document. Pass 1 for true or 0 for false. The default value is 0.', true) ->action( function ($collectionId, $filters, $offset, $limit, $orderField, $orderType, $orderCast, $search, $first, $last) use ($response, $projectDB, $isDev) { $collection = $projectDB->getDocument($collectionId, $isDev); @@ -306,8 +356,12 @@ $utopia->get('/v1/database/:collectionId/documents/:documentId') ->label('sdk.namespace', 'database') ->label('sdk.method', 'getDocument') ->label('sdk.description', 'Get document by its unique ID. This endpoint response returns a JSON object with the document data.') - ->param('collectionId', null, function () {return new UID();}, 'Collection unique ID') - ->param('documentId', null, function () {return new UID();}, 'Document unique ID') + ->param('collectionId', null, function () { + return new UID(); + }, 'Collection unique ID') + ->param('documentId', null, function () { + return new UID(); + }, 'Document unique ID') ->action( function ($collectionId, $documentId) use ($response, $request, $projectDB, $isDev) { $document = $projectDB->getDocument($documentId, $isDev); @@ -351,13 +405,27 @@ $utopia->post('/v1/database/:collectionId/documents') ->label('sdk.namespace', 'database') ->label('sdk.method', 'createDocument') ->label('sdk.description', 'Create a new Document.') - ->param('collectionId', null, function () {return new UID();}, 'Collection unique ID.') - ->param('data', [], function () {return new \Utopia\Validator\Mock();}, 'Document data as JSON string.') - ->param('read', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('parentDocument', '', function () {return new UID();}, 'Parent document unique ID. Use when you want your new document to be a child of a parent document.', true) - ->param('parentProperty', '', function () {return new Key();}, 'Parent document property name. Use when you want your new document to be a child of a parent document.', true) - ->param('parentPropertyType', Document::SET_TYPE_ASSIGN, function () {return new WhiteList([Document::SET_TYPE_ASSIGN, Document::SET_TYPE_APPEND, Document::SET_TYPE_PREPEND]);}, 'Parent document property connection type. You can set this value to **assign**, **append** or **prepend**, default value is assign. Use when you want your new document to be a child of a parent document.', true) + ->param('collectionId', null, function () { + return new UID(); + }, 'Collection unique ID.') + ->param('data', [], function () { + return new \Utopia\Validator\Mock(); + }, 'Document data as JSON string.') + ->param('read', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('write', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('parentDocument', '', function () { + return new UID(); + }, 'Parent document unique ID. Use when you want your new document to be a child of a parent document.', true) + ->param('parentProperty', '', function () { + return new Key(); + }, 'Parent document property name. Use when you want your new document to be a child of a parent document.', true) + ->param('parentPropertyType', Document::SET_TYPE_ASSIGN, function () { + return new WhiteList([Document::SET_TYPE_ASSIGN, Document::SET_TYPE_APPEND, Document::SET_TYPE_PREPEND]); + }, 'Parent document property connection type. You can set this value to **assign**, **append** or **prepend**, default value is assign. Use when you want your new document to be a child of a parent document.', true) ->action( function ($collectionId, $data, $read, $write, $parentDocument, $parentProperty, $parentPropertyType) use ($response, $projectDB, $webhook, $audit) { if (empty($data)) { @@ -454,11 +522,21 @@ $utopia->patch('/v1/database/:collectionId/documents/:documentId') ->label('scope', 'documents.write') ->label('sdk.namespace', 'database') ->label('sdk.method', 'updateDocument') - ->param('collectionId', null, function () {return new UID();}, 'Collection unique ID') - ->param('documentId', null, function () {return new UID();}, 'Document unique ID') - ->param('data', [], function () {return new \Utopia\Validator\Mock();}, 'Document data as JSON string') - ->param('read', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('collectionId', null, function () { + return new UID(); + }, 'Collection unique ID') + ->param('documentId', null, function () { + return new UID(); + }, 'Document unique ID') + ->param('data', [], function () { + return new \Utopia\Validator\Mock(); + }, 'Document data as JSON string') + ->param('read', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('write', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) ->action( function ($collectionId, $documentId, $data, $read, $write) use ($response, $projectDB, &$output, $webhook, $audit, $isDev) { $collection = $projectDB->getDocument($collectionId/*, $isDev*/); @@ -531,11 +609,14 @@ $utopia->delete('/v1/database/:collectionId/documents/:documentId') ->label('sdk.namespace', 'database') ->label('sdk.method', 'deleteDocument') ->label('sdk.description', 'Delete document by its unique ID. This endpoint deletes only the parent documents, his attributes and relations to other documents. Child documents **will not** be deleted.') - ->param('collectionId', null, function () {return new UID();}, 'Collection unique ID') - ->param('documentId', null, function () {return new UID();}, 'Document unique ID') + ->param('collectionId', null, function () { + return new UID(); + }, 'Collection unique ID') + ->param('documentId', null, function () { + return new UID(); + }, 'Document unique ID') ->action( function ($collectionId, $documentId) use ($response, $projectDB, $audit, $isDev) { - $collection = $projectDB->getDocument($collectionId, $isDev); $document = $projectDB->getDocument($documentId, $isDev); diff --git a/app/controllers/projects.php b/app/controllers/projects.php index 2a861fcb65..a3d0703ffc 100644 --- a/app/controllers/projects.php +++ b/app/controllers/projects.php @@ -67,7 +67,9 @@ $utopia->get('/v1/projects/:projectId') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getProject') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') ->action( function ($projectId) use ($request, $response, $providers, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -94,7 +96,9 @@ $utopia->get('/v1/projects/:projectId/usage') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getProjectUsage') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') ->action( function ($projectId) use ($response, $consoleDB, $projectDB, $register) { $project = $consoleDB->getDocument($projectId); @@ -182,11 +186,15 @@ $utopia->get('/v1/projects/:projectId/usage') $response->json([ 'requests' => [ 'data' => $requests, - 'total' => array_sum(array_map(function ($item) {return $item['value'];}, $requests)), + 'total' => array_sum(array_map(function ($item) { + return $item['value']; + }, $requests)), ], 'network' => [ 'data' => $network, - 'total' => array_sum(array_map(function ($item) {return $item['value'];}, $network)), + 'total' => array_sum(array_map(function ($item) { + return $item['value']; + }, $network)), ], 'collections' => [ 'data' => $collections, @@ -194,7 +202,9 @@ $utopia->get('/v1/projects/:projectId/usage') ], 'documents' => [ 'data' => $documents, - 'total' => array_sum(array_map(function ($item) {return $item['total'];}, $documents)), + 'total' => array_sum(array_map(function ($item) { + return $item['total']; + }, $documents)), ], 'users' => [ 'data' => [], @@ -205,7 +215,8 @@ $utopia->get('/v1/projects/:projectId/usage') 'total' => $tasksTotal, ], 'storage' => [ - 'total' => $projectDB->getCount([ + 'total' => $projectDB->getCount( + [ 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_FILES, ], @@ -221,17 +232,39 @@ $utopia->post('/v1/projects') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createProject') - ->param('name', null, function () {return new Text(100);}, 'Project name') - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') - ->param('description', '', function () {return new Text(255);}, 'Project description', true) - ->param('logo', '', function () {return new Text(1024);}, 'Project logo', true) - ->param('url', '', function () {return new URL();}, 'Project URL', true) - ->param('legalName', '', function () {return new Text(256);}, 'Project Legal Name', true) - ->param('legalCountry', '', function () {return new Text(256);}, 'Project Legal Country', true) - ->param('legalState', '', function () {return new Text(256);}, 'Project Legal State', true) - ->param('legalCity', '', function () {return new Text(256);}, 'Project Legal City', true) - ->param('legalAddress', '', function () {return new Text(256);}, 'Project Legal Address', true) - ->param('legalTaxId', '', function () {return new Text(256);}, 'Project Legal Tax ID', true) + ->param('name', null, function () { + return new Text(100); + }, 'Project name') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') + ->param('description', '', function () { + return new Text(255); + }, 'Project description', true) + ->param('logo', '', function () { + return new Text(1024); + }, 'Project logo', true) + ->param('url', '', function () { + return new URL(); + }, 'Project URL', true) + ->param('legalName', '', function () { + return new Text(256); + }, 'Project Legal Name', true) + ->param('legalCountry', '', function () { + return new Text(256); + }, 'Project Legal Country', true) + ->param('legalState', '', function () { + return new Text(256); + }, 'Project Legal State', true) + ->param('legalCity', '', function () { + return new Text(256); + }, 'Project Legal City', true) + ->param('legalAddress', '', function () { + return new Text(256); + }, 'Project Legal Address', true) + ->param('legalTaxId', '', function () { + return new Text(256); + }, 'Project Legal Tax ID', true) ->action( function ($name, $teamId, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId) use ($response, $user, $consoleDB, $projectDB) { $team = $projectDB->getDocument($teamId); @@ -260,7 +293,8 @@ $utopia->post('/v1/projects') 'teamId' => $team->getUid(), 'webhooks' => [], 'keys' => [], - ]); + ] + ); if (false === $project) { throw new Exception('Failed saving project to DB', 500); @@ -280,17 +314,39 @@ $utopia->patch('/v1/projects/:projectId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateProject') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') - ->param('name', null, function () {return new Text(100);}, 'Project name') - ->param('description', '', function () {return new Text(255);}, 'Project description', true) - ->param('logo', '', function () {return new Text(1024);}, 'Project logo', true) - ->param('url', '', function () {return new URL();}, 'Project URL', true) - ->param('legalName', '', function () {return new Text(256);}, 'Project Legal Name', true) - ->param('legalCountry', '', function () {return new Text(256);}, 'Project Legal Country', true) - ->param('legalState', '', function () {return new Text(256);}, 'Project Legal State', true) - ->param('legalCity', '', function () {return new Text(256);}, 'Project Legal City', true) - ->param('legalAddress', '', function () {return new Text(256);}, 'Project Legal Address', true) - ->param('legalTaxId', '', function () {return new Text(256);}, 'Project Legal Tax ID', true) + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') + ->param('name', null, function () { + return new Text(100); + }, 'Project name') + ->param('description', '', function () { + return new Text(255); + }, 'Project description', true) + ->param('logo', '', function () { + return new Text(1024); + }, 'Project logo', true) + ->param('url', '', function () { + return new URL(); + }, 'Project URL', true) + ->param('legalName', '', function () { + return new Text(256); + }, 'Project Legal Name', true) + ->param('legalCountry', '', function () { + return new Text(256); + }, 'Project Legal Country', true) + ->param('legalState', '', function () { + return new Text(256); + }, 'Project Legal State', true) + ->param('legalCity', '', function () { + return new Text(256); + }, 'Project Legal City', true) + ->param('legalAddress', '', function () { + return new Text(256); + }, 'Project Legal Address', true) + ->param('legalTaxId', '', function () { + return new Text(256); + }, 'Project Legal Tax ID', true) ->action( function ($projectId, $name, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -325,10 +381,18 @@ $utopia->patch('/v1/projects/:projectId/oauth') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateProjectOAuth') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') - ->param('provider', '', function () use ($providers) {return new WhiteList(array_keys($providers));}, 'Provider Name', false) - ->param('appId', '', function () {return new Text(256);}, 'Provider App ID', true) - ->param('secret', '', function () {return new text(256);}, 'Provider Secret Key', true) + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') + ->param('provider', '', function () use ($providers) { + return new WhiteList(array_keys($providers)); + }, 'Provider Name', false) + ->param('appId', '', function () { + return new Text(256); + }, 'Provider App ID', true) + ->param('secret', '', function () { + return new text(256); + }, 'Provider Secret Key', true) ->action( function ($projectId, $provider, $appId, $secret) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -366,7 +430,9 @@ $utopia->delete('/v1/projects/:projectId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteProject') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') ->action( function ($projectId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -400,7 +466,9 @@ $utopia->get('/v1/projects/:projectId/webhooks') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listWebhooks') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') ->action( function ($projectId) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -432,8 +500,12 @@ $utopia->get('/v1/projects/:projectId/webhooks/:webhookId') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getWebhook') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('webhookId', null, function () {return new UID();}, 'Webhook unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('webhookId', null, function () { + return new UID(); + }, 'Webhook unique ID.') ->action( function ($projectId, $webhookId) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -464,13 +536,27 @@ $utopia->post('/v1/projects/:projectId/webhooks') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createWebhook') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Webhook name') - ->param('events', null, function () {return new ArrayList(new Text(256));}, 'Webhook events list') - ->param('url', null, function () {return new Text(2000);}, 'Webhook URL') - ->param('security', null, function () {return new Range(0, 1);}, 'Certificate verification, 0 for disabled or 1 for enabled') - ->param('httpUser', '', function () {return new Text(256);}, 'Webhook HTTP user', true) - ->param('httpPass', '', function () {return new Text(256);}, 'Webhook HTTP password', true) + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Webhook name') + ->param('events', null, function () { + return new ArrayList(new Text(256)); + }, 'Webhook events list') + ->param('url', null, function () { + return new Text(2000); + }, 'Webhook URL') + ->param('security', null, function () { + return new Range(0, 1); + }, 'Certificate verification, 0 for disabled or 1 for enabled') + ->param('httpUser', '', function () { + return new Text(256); + }, 'Webhook HTTP user', true) + ->param('httpPass', '', function () { + return new Text(256); + }, 'Webhook HTTP password', true) ->action( function ($projectId, $name, $events, $url, $security, $httpUser, $httpPass) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -528,14 +614,30 @@ $utopia->put('/v1/projects/:projectId/webhooks/:webhookId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateWebhook') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('webhookId', null, function () {return new UID();}, 'Webhook unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Webhook name') - ->param('events', null, function () {return new ArrayList(new Text(256));}, 'Webhook events list') - ->param('url', null, function () {return new Text(2000);}, 'Webhook URL') - ->param('security', null, function () {return new Range(0, 1);}, 'Certificate verification, 0 for disabled or 1 for enabled') - ->param('httpUser', '', function () {return new Text(256);}, 'Webhook HTTP user', true) - ->param('httpPass', '', function () {return new Text(256);}, 'Webhook HTTP password', true) + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('webhookId', null, function () { + return new UID(); + }, 'Webhook unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Webhook name') + ->param('events', null, function () { + return new ArrayList(new Text(256)); + }, 'Webhook events list') + ->param('url', null, function () { + return new Text(2000); + }, 'Webhook URL') + ->param('security', null, function () { + return new Range(0, 1); + }, 'Certificate verification, 0 for disabled or 1 for enabled') + ->param('httpUser', '', function () { + return new Text(256); + }, 'Webhook HTTP user', true) + ->param('httpPass', '', function () { + return new Text(256); + }, 'Webhook HTTP password', true) ->action( function ($projectId, $webhookId, $name, $events, $url, $security, $httpUser, $httpPass) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -583,8 +685,12 @@ $utopia->delete('/v1/projects/:projectId/webhooks/:webhookId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteWebhook') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('webhookId', null, function () {return new UID();}, 'Webhook unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('webhookId', null, function () { + return new UID(); + }, 'Webhook unique ID.') ->action( function ($projectId, $webhookId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -614,7 +720,9 @@ $utopia->get('/v1/projects/:projectId/keys') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listKeys') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') ->action( function ($projectId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -632,8 +740,12 @@ $utopia->get('/v1/projects/:projectId/keys/:keyId') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getKey') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('keyId', null, function () {return new UID();}, 'Key unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('keyId', null, function () { + return new UID(); + }, 'Key unique ID.') ->action( function ($projectId, $keyId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -657,9 +769,15 @@ $utopia->post('/v1/projects/:projectId/keys') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createKey') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Key name') - ->param('scopes', null, function () use ($scopes) {return new ArrayList(new WhiteList($scopes));}, 'Key scopes list') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Key name') + ->param('scopes', null, function () use ($scopes) { + return new ArrayList(new WhiteList($scopes)); + }, 'Key scopes list') ->action( function ($projectId, $name, $scopes) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -703,10 +821,18 @@ $utopia->put('/v1/projects/:projectId/keys/:keyId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateKey') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('keyId', null, function () {return new UID();}, 'Key unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Key name') - ->param('scopes', null, function () use ($scopes) {return new ArrayList(new WhiteList($scopes));}, 'Key scopes list') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('keyId', null, function () { + return new UID(); + }, 'Key unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Key name') + ->param('scopes', null, function () use ($scopes) { + return new ArrayList(new WhiteList($scopes)); + }, 'Key scopes list') ->action( function ($projectId, $keyId, $name, $scopes) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -739,8 +865,12 @@ $utopia->delete('/v1/projects/:projectId/keys/:keyId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteKey') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('keyId', null, function () {return new UID();}, 'Key unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('keyId', null, function () { + return new UID(); + }, 'Key unique ID.') ->action( function ($projectId, $keyId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -770,7 +900,9 @@ $utopia->get('/v1/projects/:projectId/tasks') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listTasks') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') ->action( function ($projectId) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -802,8 +934,12 @@ $utopia->get('/v1/projects/:projectId/tasks/:taskId') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getTask') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('taskId', null, function () {return new UID();}, 'Task unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('taskId', null, function () { + return new UID(); + }, 'Task unique ID.') ->action( function ($projectId, $taskId) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -834,16 +970,36 @@ $utopia->post('/v1/projects/:projectId/tasks') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createTask') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Task name') - ->param('status', null, function () {return new WhiteList(['play', 'pause']);}, 'Task status') - ->param('schedule', null, function () {return new Cron();}, 'Task schedule syntax') - ->param('security', null, function () {return new Range(0, 1);}, 'Certificate verification, 0 for disabled or 1 for enabled') - ->param('httpMethod', '', function () {return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']);}, 'Task HTTP method') - ->param('httpUrl', '', function () {return new URL();}, 'Task HTTP URL') - ->param('httpHeaders', null, function () {return new ArrayList(new Text(256));}, 'Task HTTP headers list', true) - ->param('httpUser', '', function () {return new Text(256);}, 'Task HTTP user', true) - ->param('httpPass', '', function () {return new Text(256);}, 'Task HTTP password', true) + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Task name') + ->param('status', null, function () { + return new WhiteList(['play', 'pause']); + }, 'Task status') + ->param('schedule', null, function () { + return new Cron(); + }, 'Task schedule syntax') + ->param('security', null, function () { + return new Range(0, 1); + }, 'Certificate verification, 0 for disabled or 1 for enabled') + ->param('httpMethod', '', function () { + return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']); + }, 'Task HTTP method') + ->param('httpUrl', '', function () { + return new URL(); + }, 'Task HTTP URL') + ->param('httpHeaders', null, function () { + return new ArrayList(new Text(256)); + }, 'Task HTTP headers list', true) + ->param('httpUser', '', function () { + return new Text(256); + }, 'Task HTTP user', true) + ->param('httpPass', '', function () { + return new Text(256); + }, 'Task HTTP password', true) ->action( function ($projectId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -916,17 +1072,39 @@ $utopia->put('/v1/projects/:projectId/tasks/:taskId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updateTask') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('taskId', null, function () {return new UID();}, 'Task unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Task name') - ->param('status', null, function () {return new WhiteList(['play', 'pause']);}, 'Task status') - ->param('schedule', null, function () {return new Cron();}, 'Task schedule syntax') - ->param('security', null, function () {return new Range(0, 1);}, 'Certificate verification, 0 for disabled or 1 for enabled') - ->param('httpMethod', '', function () {return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']);}, 'Task HTTP method') - ->param('httpUrl', '', function () {return new URL();}, 'Task HTTP URL') - ->param('httpHeaders', null, function () {return new ArrayList(new Text(256));}, 'Task HTTP headers list', true) - ->param('httpUser', '', function () {return new Text(256);}, 'Task HTTP user', true) - ->param('httpPass', '', function () {return new Text(256);}, 'Task HTTP password', true) + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('taskId', null, function () { + return new UID(); + }, 'Task unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Task name') + ->param('status', null, function () { + return new WhiteList(['play', 'pause']); + }, 'Task status') + ->param('schedule', null, function () { + return new Cron(); + }, 'Task schedule syntax') + ->param('security', null, function () { + return new Range(0, 1); + }, 'Certificate verification, 0 for disabled or 1 for enabled') + ->param('httpMethod', '', function () { + return new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT']); + }, 'Task HTTP method') + ->param('httpUrl', '', function () { + return new URL(); + }, 'Task HTTP URL') + ->param('httpHeaders', null, function () { + return new ArrayList(new Text(256)); + }, 'Task HTTP headers list', true) + ->param('httpUser', '', function () { + return new Text(256); + }, 'Task HTTP user', true) + ->param('httpPass', '', function () { + return new Text(256); + }, 'Task HTTP password', true) ->action( function ($projectId, $taskId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -986,8 +1164,12 @@ $utopia->delete('/v1/projects/:projectId/tasks/:taskId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deleteTask') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('taskId', null, function () {return new UID();}, 'Task unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('taskId', null, function () { + return new UID(); + }, 'Task unique ID.') ->action( function ($projectId, $taskId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -1017,7 +1199,9 @@ $utopia->get('/v1/projects/:projectId/platforms') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'listPlatforms') - ->param('projectId', '', function () {return new UID();}, 'Project unique ID.') + ->param('projectId', '', function () { + return new UID(); + }, 'Project unique ID.') ->action( function ($projectId) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -1037,8 +1221,12 @@ $utopia->get('/v1/projects/:projectId/platforms/:platformId') ->label('scope', 'projects.read') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'getPlatform') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('platformId', null, function () {return new UID();}, 'Platform unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('platformId', null, function () { + return new UID(); + }, 'Platform unique ID.') ->action( function ($projectId, $platformId) use ($request, $response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -1062,12 +1250,24 @@ $utopia->post('/v1/projects/:projectId/platforms') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'createPlatform') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('type', null, function () {return new WhiteList(['web', 'ios', 'android', 'unity']);}, 'Platform name') - ->param('name', null, function () {return new Text(256);}, 'Platform name') - ->param('key', '', function () {return new Text(256);}, 'Package name for android or bundle ID for iOS', true) - ->param('store', '', function () {return new Text(256);}, 'App store or Google Play store ID', true) - ->param('url', '', function () {return new URL();}, 'Platform client URL', true) + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('type', null, function () { + return new WhiteList(['web', 'ios', 'android', 'unity']); + }, 'Platform name') + ->param('name', null, function () { + return new Text(256); + }, 'Platform name') + ->param('key', '', function () { + return new Text(256); + }, 'Package name for android or bundle ID for iOS', true) + ->param('store', '', function () { + return new Text(256); + }, 'App store or Google Play store ID', true) + ->param('url', '', function () { + return new URL(); + }, 'Platform client URL', true) ->action( function ($projectId, $type, $name, $key, $store, $url) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -1115,12 +1315,24 @@ $utopia->put('/v1/projects/:projectId/platforms/:platformId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'updatePlatform') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('platformId', null, function () {return new UID();}, 'Platform unique ID.') - ->param('name', null, function () {return new Text(256);}, 'Platform name') - ->param('key', '', function () {return new Text(256);}, 'Package name for android or bundle ID for iOS', true) - ->param('store', '', function () {return new Text(256);}, 'App store or Google Play store ID', true) - ->param('url', '', function () {return new URL();}, 'Platform client URL', true) + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('platformId', null, function () { + return new UID(); + }, 'Platform unique ID.') + ->param('name', null, function () { + return new Text(256); + }, 'Platform name') + ->param('key', '', function () { + return new Text(256); + }, 'Package name for android or bundle ID for iOS', true) + ->param('store', '', function () { + return new Text(256); + }, 'App store or Google Play store ID', true) + ->param('url', '', function () { + return new URL(); + }, 'Platform client URL', true) ->action( function ($projectId, $platformId, $name, $key, $store, $url) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); @@ -1156,8 +1368,12 @@ $utopia->delete('/v1/projects/:projectId/platforms/:platformId') ->label('scope', 'projects.write') ->label('sdk.namespace', 'projects') ->label('sdk.method', 'deletePlatform') - ->param('projectId', null, function () {return new UID();}, 'Project unique ID.') - ->param('platformId', null, function () {return new UID();}, 'Platform unique ID.') + ->param('projectId', null, function () { + return new UID(); + }, 'Project unique ID.') + ->param('platformId', null, function () { + return new UID(); + }, 'Platform unique ID.') ->action( function ($projectId, $platformId) use ($response, $consoleDB) { $project = $consoleDB->getDocument($projectId); diff --git a/app/controllers/storage.php b/app/controllers/storage.php index d2068f40ed..c397d69e3f 100644 --- a/app/controllers/storage.php +++ b/app/controllers/storage.php @@ -119,10 +119,18 @@ $utopia->get('/v1/storage/files') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'listFiles') ->label('sdk.description', 'Get a list of all the user files. You can use the query params to filter your results. On admin mode, this endpoint will return a list of all of the project files. [Learn more about different API modes](/docs/modes).') - ->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true) - ->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) - ->param('offset', 0, function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true) + ->param('search', '', function () { + return new Text(256); + }, 'Search term to filter your list results.', true) + ->param('limit', 25, function () { + return new Range(0, 100); + }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) + ->param('offset', 0, function () { + return new Range(0, 2000); + }, 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('orderType', 'ASC', function () { + return new WhiteList(['ASC', 'DESC']); + }, 'Order result by ASC or DESC order.', true) ->action( function ($search, $limit, $offset, $orderType) use ($response, $projectDB) { $results = $projectDB->getCollection([ @@ -151,7 +159,9 @@ $utopia->get('/v1/storage/files/:fileId') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFile') ->label('sdk.description', 'Get file by its unique ID. This endpoint response returns a JSON object with the file metadata.') - ->param('fileId', '', function () {return new UID();}, 'File unique ID.') + ->param('fileId', '', function () { + return new UID(); + }, 'File unique ID.') ->action( function ($fileId) use ($response, $projectDB) { $file = $projectDB->getDocument($fileId); @@ -170,12 +180,24 @@ $utopia->get('/v1/storage/files/:fileId/preview') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFilePreview') ->label('sdk.description', 'Get file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets will return file icon image. You can also pass query string arguments for cutting and resizing your preview image.') - ->param('fileId', '', function () {return new UID();}, 'File unique ID') - ->param('width', 0, function () {return new Range(0, 4000);}, 'Resize preview image width, Pass an integer between 0 to 4000', true) - ->param('height', 0, function () {return new Range(0, 4000);}, 'Resize preview image height, Pass an integer between 0 to 4000', true) - ->param('quality', 100, function () {return new Range(0, 100);}, 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100', true) - ->param('background', '', function () {return new HexColor();}, 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true) - ->param('output', null, function () use ($outputs) {return new WhiteList(array_merge(array_keys($outputs), [null]));}, 'Output format type (jpeg, jpg, png, gif and webp)', true) + ->param('fileId', '', function () { + return new UID(); + }, 'File unique ID') + ->param('width', 0, function () { + return new Range(0, 4000); + }, 'Resize preview image width, Pass an integer between 0 to 4000', true) + ->param('height', 0, function () { + return new Range(0, 4000); + }, 'Resize preview image height, Pass an integer between 0 to 4000', true) + ->param('quality', 100, function () { + return new Range(0, 100); + }, 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100', true) + ->param('background', '', function () { + return new HexColor(); + }, 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true) + ->param('output', null, function () use ($outputs) { + return new WhiteList(array_merge(array_keys($outputs), [null])); + }, 'Output format type (jpeg, jpg, png, gif and webp)', true) //->param('storage', 'local', function () {return new WhiteList(array('local'));}, 'Selected storage device. defaults to local') //->param('token', '', function () {return new Text(128);}, 'Preview token', true) ->action( @@ -282,7 +304,9 @@ $utopia->get('/v1/storage/files/:fileId/download') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFileDownload') ->label('sdk.description', 'Get file content by its unique ID. The endpoint response return with a \'Content-Disposition: attachment\' header that tells the browser to start downloading the file to user downloads directory.') - ->param('fileId', '', function () {return new UID();}, 'File unique ID.') + ->param('fileId', '', function () { + return new UID(); + }, 'File unique ID.') ->action( function ($fileId) use ($response, $request, $projectDB) { $file = $projectDB->getDocument($fileId); @@ -332,8 +356,12 @@ $utopia->get('/v1/storage/files/:fileId/view') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFileView') ->label('sdk.description', 'Get file content by its unique ID. This endpoint is similar to the download method but returns with no \'Content-Disposition: attachment\' header.') - ->param('fileId', '', function () {return new UID();}, 'File unique ID.') - ->param('as', '', function () {return new WhiteList(['pdf', /*'html',*/ 'text']);}, 'Choose a file format to convert your file to. Currently you can only convert word and pdf files to pdf or txt. This option is currently experimental only, use at your own risk.', true) + ->param('fileId', '', function () { + return new UID(); + }, 'File unique ID.') + ->param('as', '', function () { + return new WhiteList(['pdf', /*'html',*/ 'text']); + }, 'Choose a file format to convert your file to. Currently you can only convert word and pdf files to pdf or txt. This option is currently experimental only, use at your own risk.', true) ->action( function ($fileId, $as) use ($response, $request, $projectDB, $mimes) { $file = $projectDB->getDocument($fileId); @@ -400,10 +428,18 @@ $utopia->post('/v1/storage/files') ->label('sdk.method', 'createFile') ->label('sdk.description', 'Create a new file. The user who creates the file will automatically be assigned to read and write access unless he has passed custom values for read and write arguments.') ->label('sdk.consumes', 'multipart/form-data') - ->param('files', [], function () {return new File();}, 'Binary Files.', false) - ->param('read', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('folderId', '', function () {return new UID();}, 'Folder to associate files with.', true) + ->param('files', [], function () { + return new File(); + }, 'Binary Files.', false) + ->param('read', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('write', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('folderId', '', function () { + return new UID(); + }, 'Folder to associate files with.', true) ->action( function ($files, $read, $write, $folderId) use ($request, $response, $user, $projectDB, $audit, $usage) { $files = $request->getFiles('files'); @@ -522,10 +558,18 @@ $utopia->put('/v1/storage/files/:fileId') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'updateFile') ->label('sdk.description', 'Update file by its unique ID. Only users with write permissions have access to update this resource.') - ->param('fileId', '', function () {return new UID();}, 'File unique ID.') - ->param('read', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('write', [], function () {return new ArrayList(new Text(64));}, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) - ->param('folderId', '', function () {return new UID();}, 'Folder to associate files with.', true) + ->param('fileId', '', function () { + return new UID(); + }, 'File unique ID.') + ->param('read', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with read permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('write', [], function () { + return new ArrayList(new Text(64)); + }, 'An array of strings with write permissions. [Learn more about permissions and roles](/docs/permissions).', true) + ->param('folderId', '', function () { + return new UID(); + }, 'Folder to associate files with.', true) ->action( function ($fileId, $read, $write, $folderId) use ($response, $projectDB) { $file = $projectDB->getDocument($fileId); @@ -556,7 +600,9 @@ $utopia->delete('/v1/storage/files/:fileId') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'deleteFile') ->label('sdk.description', 'Delete a file by its unique ID. Only users with write permissions have access to delete this resource.') - ->param('fileId', '', function () {return new UID();}, 'File unique ID.') + ->param('fileId', '', function () { + return new UID(); + }, 'File unique ID.') ->action( function ($fileId) use ($response, $projectDB, $audit, $usage) { $file = $projectDB->getDocument($fileId); @@ -592,8 +638,12 @@ $utopia->get('/v1/storage/files/:fileId/scan') ->label('sdk.namespace', 'storage') ->label('sdk.method', 'getFileScan') ->label('sdk.hide', true) - ->param('fileId', '', function () {return new UID();}, 'File unique ID.') - ->param('storage', 'local', function () {return new WhiteList(['local']);}) + ->param('fileId', '', function () { + return new UID(); + }, 'File unique ID.') + ->param('storage', 'local', function () { + return new WhiteList(['local']); + }) ->action( function ($fileId, $storage) use ($response, $request, $projectDB) { $file = $projectDB->getDocument($fileId); diff --git a/app/controllers/teams.php b/app/controllers/teams.php index 5e09b22429..27a5fbe31a 100644 --- a/app/controllers/teams.php +++ b/app/controllers/teams.php @@ -24,10 +24,18 @@ $utopia->get('/v1/teams') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'listTeams') ->label('sdk.description', 'Get a list of all the current user teams. You can use the query params to filter your results. On admin mode, this endpoint will return a list of all of the project teams. [Learn more about different API modes](/docs/modes).') - ->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true) - ->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) - ->param('offset', 0, function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true) + ->param('search', '', function () { + return new Text(256); + }, 'Search term to filter your list results.', true) + ->param('limit', 25, function () { + return new Range(0, 100); + }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) + ->param('offset', 0, function () { + return new Range(0, 2000); + }, 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('orderType', 'ASC', function () { + return new WhiteList(['ASC', 'DESC']); + }, 'Order result by ASC or DESC order.', true) ->action( function ($search, $limit, $offset, $orderType) use ($response, $projectDB) { $results = $projectDB->getCollection([ @@ -52,7 +60,9 @@ $utopia->get('/v1/teams/:teamId') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'getTeam') ->label('sdk.description', 'Get team by its unique ID. All team members have read access for this resource.') - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') ->action( function ($teamId) use ($response, $projectDB) { $team = $projectDB->getDocument($teamId); @@ -71,7 +81,9 @@ $utopia->get('/v1/teams/:teamId/members') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'getTeamMembers') ->label('sdk.description', 'Get team members by the team unique ID. All team members have read access for this list of resources.') - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') ->action( function ($teamId) use ($response, $projectDB) { $team = $projectDB->getDocument($teamId); @@ -123,8 +135,12 @@ $utopia->post('/v1/teams') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'createTeam') ->label('sdk.description', 'Create a new team. The user who creates the team will automatically be assigned as the owner of the team. The team owner can invite new members, who will be able add new owners and update or delete the team from your project.') - ->param('name', null, function () {return new Text(100);}, 'Team name.') - ->param('roles', ['owner'], function () {return new ArrayList(new Text(128));}, 'User roles array. Use this param to set the roles in the team for the user who created the team. The default role is **owner**, a role can be any string.', true) + ->param('name', null, function () { + return new Text(100); + }, 'Team name.') + ->param('roles', ['owner'], function () { + return new ArrayList(new Text(128)); + }, 'User roles array. Use this param to set the roles in the team for the user who created the team. The default role is **owner**, a role can be any string.', true) ->action( function ($name, $roles) use ($response, $projectDB, $user, $mode) { Authorization::disable(); @@ -185,8 +201,12 @@ $utopia->put('/v1/teams/:teamId') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'updateTeam') ->label('sdk.description', 'Update team by its unique ID. Only team owners have write access for this resource.') - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') - ->param('name', null, function () {return new Text(100);}, 'Team name.') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') + ->param('name', null, function () { + return new Text(100); + }, 'Team name.') ->action( function ($teamId, $name) use ($response, $projectDB) { $team = $projectDB->getDocument($teamId); @@ -213,7 +233,9 @@ $utopia->delete('/v1/teams/:teamId') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'deleteTeam') ->label('sdk.description', 'Delete team by its unique ID. Only team owners have write access for this resource.') - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') ->action( function ($teamId) use ($response, $projectDB) { $team = $projectDB->getDocument($teamId); @@ -253,11 +275,21 @@ $utopia->post('/v1/teams/:teamId/memberships') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'createTeamMembership') ->label('sdk.description', "Use this endpoint to invite a new member to your team. An email with a link to join the team will be sent to the new member email address. If member doesn't exists in the project it will be automatically created.\n\nUse the redirect parameter to redirect the user from the invitation email back to your app. When the user is redirected, use the /teams/{teamId}/memberships/{inviteId}/status endpoint to finally join the user to the team.\n\nPlease notice that in order to avoid a [Redirect Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URL's are the once from domains you have set when added your platforms in the console interface.") - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') - ->param('email', '', function () {return new Email();}, 'New team member email address.') - ->param('name', '', function () {return new Text(100);}, 'New team member name.', true) - ->param('roles', [], function () {return new ArrayList(new Text(128));}, 'Invite roles array. Learn more about [roles and permissions](/docs/permissions).') - ->param('redirect', '', function () use ($clients) {return new Host($clients);}, 'Reset page to redirect user back to your app from the invitation email.') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') + ->param('email', '', function () { + return new Email(); + }, 'New team member email address.') + ->param('name', '', function () { + return new Text(100); + }, 'New team member name.', true) + ->param('roles', [], function () { + return new ArrayList(new Text(128)); + }, 'Invite roles array. Learn more about [roles and permissions](/docs/permissions).') + ->param('redirect', '', function () use ($clients) { + return new Host($clients); + }, 'Reset page to redirect user back to your app from the invitation email.') ->action( function ($teamId, $email, $name, $roles, $redirect) use ($request, $response, $register, $project, $user, $audit, $projectDB) { $name = (empty($name)) ? $email : $name; @@ -396,9 +428,15 @@ $utopia->post('/v1/teams/:teamId/memberships/:inviteId/resend') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'createTeamMembershipResend') ->label('sdk.description', 'Use this endpoint to resend your invitation email for a user to join a team.') - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') - ->param('inviteId', '', function () {return new UID();}, 'Invite unique ID.') - ->param('redirect', '', function () use ($clients) {return new Host($clients);}, 'Reset page to redirect user back to your app from the invitation email.') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') + ->param('inviteId', '', function () { + return new UID(); + }, 'Invite unique ID.') + ->param('redirect', '', function () use ($clients) { + return new Host($clients); + }, 'Reset page to redirect user back to your app from the invitation email.') ->action( function ($teamId, $inviteId, $redirect) use ($response, $register, $project, $user, $audit, $projectDB) { $membership = $projectDB->getDocument($inviteId); @@ -477,12 +515,24 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status') ->label('sdk.method', 'updateTeamMembershipStatus') ->label('sdk.description', "Use this endpoint to let user accept an invitation to join a team after he is being redirect back to your app from the invitation email. Use the success and failure URL's to redirect users back to your application after the request completes.\n\nPlease notice that in order to avoid a [Redirect Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URL's are the once from domains you have set when added your platforms in the console interface.\n\nWhen not using the success or failure redirect arguments this endpoint will result with a 200 status code on success and with 401 status error on failure. This behavior was applied to help the web clients deal with browsers who don't allow to set 3rd party HTTP cookies needed for saving the account session token.") ->label('sdk.cookies', true) - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') - ->param('inviteId', '', function () {return new UID();}, 'Invite unique ID') - ->param('userId', '', function () {return new UID();}, 'User unique ID') - ->param('secret', '', function () {return new Text(256);}, 'Secret Key') - ->param('success', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration succeed', true) - ->param('failure', null, function () use ($clients) {return new Host($clients);}, 'Redirect when registration failed', true) + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') + ->param('inviteId', '', function () { + return new UID(); + }, 'Invite unique ID') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID') + ->param('secret', '', function () { + return new Text(256); + }, 'Secret Key') + ->param('success', null, function () use ($clients) { + return new Host($clients); + }, 'Redirect when registration succeed', true) + ->param('failure', null, function () use ($clients) { + return new Host($clients); + }, 'Redirect when registration failed', true) ->action( function ($teamId, $inviteId, $userId, $secret, $success, $failure) use ($response, $request, $user, $audit, $projectDB) { $invite = $projectDB->getDocument($inviteId); @@ -608,8 +658,12 @@ $utopia->delete('/v1/teams/:teamId/memberships/:inviteId') ->label('sdk.namespace', 'teams') ->label('sdk.method', 'deleteTeamMembership') ->label('sdk.description', 'This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member.') - ->param('teamId', '', function () {return new UID();}, 'Team unique ID.') - ->param('inviteId', '', function () {return new UID();}, 'Invite unique ID') + ->param('teamId', '', function () { + return new UID(); + }, 'Team unique ID.') + ->param('inviteId', '', function () { + return new UID(); + }, 'Invite unique ID') ->action( function ($teamId, $inviteId) use ($response, $projectDB, $audit) { $invite = $projectDB->getDocument($inviteId); diff --git a/app/controllers/users.php b/app/controllers/users.php index f2c01ca51b..522bdfe8e5 100644 --- a/app/controllers/users.php +++ b/app/controllers/users.php @@ -23,10 +23,18 @@ $utopia->get('/v1/users') ->label('sdk.namespace', 'users') ->label('sdk.method', 'listUsers') ->label('sdk.description', 'Get a list of all the project users. You can use the query params to filter your results.') - ->param('search', '', function () {return new Text(256);}, 'Search term to filter your list results.', true) - ->param('limit', 25, function () {return new Range(0, 100);}, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) - ->param('offset', 0, function () {return new Range(0, 2000);}, 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('orderType', 'ASC', function () {return new WhiteList(['ASC', 'DESC']);}, 'Order result by ASC or DESC order.', true) + ->param('search', '', function () { + return new Text(256); + }, 'Search term to filter your list results.', true) + ->param('limit', 25, function () { + return new Range(0, 100); + }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) + ->param('offset', 0, function () { + return new Range(0, 2000); + }, 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('orderType', 'ASC', function () { + return new WhiteList(['ASC', 'DESC']); + }, 'Order result by ASC or DESC order.', true) ->action( function ($search, $limit, $offset, $orderType) use ($response, $projectDB, $providers) { $results = $projectDB->getCollection([ @@ -60,7 +68,8 @@ $utopia->get('/v1/users') 'registration', 'confirm', 'name', - ], $oauthKeys + ], + $oauthKeys )); }, $results); @@ -74,7 +83,9 @@ $utopia->get('/v1/users/:userId') ->label('sdk.namespace', 'users') ->label('sdk.method', 'getUser') ->label('sdk.description', 'Get user by its unique ID.') - ->param('userId', '', function () {return new UID();}, 'User unique ID.') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID.') ->action( function ($userId) use ($response, $projectDB, $providers) { $user = $projectDB->getDocument($userId); @@ -101,7 +112,8 @@ $utopia->get('/v1/users/:userId') 'registration', 'confirm', 'name', - ], $oauthKeys + ], + $oauthKeys )), ['roles' => Authorization::getRoles()])); } ); @@ -112,7 +124,9 @@ $utopia->get('/v1/users/:userId/prefs') ->label('sdk.namespace', 'users') ->label('sdk.method', 'getUserPrefs') ->label('sdk.description', 'Get user preferences by its unique ID.') - ->param('userId', '', function () {return new UID();}, 'User unique ID.') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID.') ->action( function ($userId) use ($response, $projectDB) { $user = $projectDB->getDocument($userId); @@ -143,7 +157,9 @@ $utopia->get('/v1/users/:userId/sessions') ->label('sdk.namespace', 'users') ->label('sdk.method', 'getUserSessions') ->label('sdk.description', 'Get user sessions list by its unique ID.') - ->param('userId', '', function () {return new UID();}, 'User unique ID.') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID.') ->action( function ($userId) use ($response, $projectDB) { $user = $projectDB->getDocument($userId); @@ -205,7 +221,9 @@ $utopia->get('/v1/users/:userId/logs') ->label('sdk.namespace', 'users') ->label('sdk.method', 'getUserLogs') ->label('sdk.description', 'Get user activity logs list by its unique ID.') - ->param('userId', '', function () {return new UID();}, 'User unique ID.') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID.') ->action( function ($userId) use ($response, $register, $projectDB, $project) { $user = $projectDB->getDocument($userId); @@ -266,9 +284,15 @@ $utopia->post('/v1/users') ->label('sdk.namespace', 'users') ->label('sdk.method', 'createUser') ->label('sdk.description', 'Create a new user.') - ->param('email', '', function () {return new Email();}, 'User account email.') - ->param('password', '', function () {return new Password();}, 'User account password.') - ->param('name', '', function () {return new Text(100);}, 'User account name.', true) + ->param('email', '', function () { + return new Email(); + }, 'User account email.') + ->param('password', '', function () { + return new Password(); + }, 'User account password.') + ->param('name', '', function () { + return new Text(100); + }, 'User account name.', true) ->action( function ($email, $password, $name) use ($response, $register, $projectDB, $providers) { $profile = $projectDB->getCollection([ // Get user by email address @@ -330,8 +354,12 @@ $utopia->patch('/v1/users/:userId/status') ->label('sdk.namespace', 'users') ->label('sdk.method', 'updateUserStatus') ->label('sdk.description', 'Update user status by its unique ID.') - ->param('userId', '', function () {return new UID();}, 'User unique ID.') - ->param('status', '', function () {return new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED]);}, 'User Status code. To activate the user pass '.Auth::USER_STATUS_ACTIVATED.', to blocking the user pass '.Auth::USER_STATUS_BLOCKED.' and for disabling the user pass '.Auth::USER_STATUS_UNACTIVATED) + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID.') + ->param('status', '', function () { + return new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED]); + }, 'User Status code. To activate the user pass '.Auth::USER_STATUS_ACTIVATED.', to blocking the user pass '.Auth::USER_STATUS_BLOCKED.' and for disabling the user pass '.Auth::USER_STATUS_UNACTIVATED) ->action( function ($userId, $status) use ($response, $projectDB) { $user = $projectDB->getDocument($userId); @@ -360,8 +388,12 @@ $utopia->delete('/v1/users/:userId/sessions/:session') ->label('sdk.method', 'deleteUsersSession') ->label('sdk.description', 'Delete user sessions by its unique ID.') ->label('abuse-limit', 100) - ->param('userId', '', function () {return new UID();}, 'User unique ID.') - ->param('sessionId', null, function () {return new UID();}, 'User unique session ID.') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID.') + ->param('sessionId', null, function () { + return new UID(); + }, 'User unique session ID.') ->action( function ($userId, $sessionId) use ($response, $request, $projectDB) { $user = $projectDB->getDocument($userId); @@ -391,7 +423,9 @@ $utopia->delete('/v1/users/:userId/sessions') ->label('sdk.method', 'deleteUserSessions') ->label('sdk.description', 'Delete all user sessions by its unique ID.') ->label('abuse-limit', 100) - ->param('userId', '', function () {return new UID();}, 'User unique ID.') + ->param('userId', '', function () { + return new UID(); + }, 'User unique ID.') ->action( function ($userId) use ($response, $request, $projectDB) { $user = $projectDB->getDocument($userId); diff --git a/app/init.php b/app/init.php index 7e987fcae8..d13979bbde 100644 --- a/app/init.php +++ b/app/init.php @@ -1,7 +1,7 @@ getServer('HTTP_HOST', null) === 'localhost' /** * Registry */ -$register->set('db', function() use ($request) { // Register DB connection +$register->set('db', function () use ($request) { // Register DB connection $dbHost = $request->getServer('_APP_DB_HOST', ''); $dbUser = $request->getServer('_APP_DB_USER', ''); $dbPass = $request->getServer('_APP_DB_PASS', ''); @@ -68,11 +68,11 @@ $register->set('db', function() use ($request) { // Register DB connection return $pdo; }); -$register->set('influxdb', function() use ($request) { // Register DB connection +$register->set('influxdb', function () use ($request) { // Register DB connection $host = $request->getServer('_APP_INFLUXDB_HOST', ''); $port = $request->getServer('_APP_INFLUXDB_PORT', ''); - if(empty($host) || empty($port)) { + if (empty($host) || empty($port)) { return null; } @@ -80,7 +80,7 @@ $register->set('influxdb', function() use ($request) { // Register DB connection return $client; }); -$register->set('statsd', function() use ($request) { // Register DB connection +$register->set('statsd', function () use ($request) { // Register DB connection $host = $request->getServer('_APP_STATSD_HOST', 'telegraf'); $port = $request->getServer('_APP_STATSD_PORT', 8125); @@ -89,13 +89,13 @@ $register->set('statsd', function() use ($request) { // Register DB connection return $statsd; }); -$register->set('cache', function() use ($redisHost, $redisPort) { // Register cache connection +$register->set('cache', function () use ($redisHost, $redisPort) { // Register cache connection $redis = new Redis(); $redis->connect($redisHost, $redisPort); return $redis; }); -$register->set('smtp', function() use ($request) { +$register->set('smtp', function () use ($request) { $mail = new PHPMailer(true); $mail->isSMTP(); @@ -128,10 +128,11 @@ Locale::$exceptions = false; Locale::setLanguage('en', include __DIR__ . '/config/locale/en.php'); Locale::setLanguage('he', include __DIR__ . '/config/locale/he.php'); +Locale::setLanguage('pt-br', include __DIR__ . '/config/locale/pt-br.php'); +Locale::setLanguage('es', include __DIR__ . '/config/locale/es.php'); Locale::setLanguage('ro', include __DIR__ . '/config/locale/ro.php'); - -if(in_array($locale, APP_LOCALES)) { +if (in_array($locale, APP_LOCALES)) { Locale::setDefault($locale); } @@ -159,7 +160,7 @@ Authorization::enable(); $console = $consoleDB->getDocument('console'); -if(is_null($project->getUid()) || Database::SYSTEM_COLLECTION_PROJECTS !== $project->getCollection()) { +if (is_null($project->getUid()) || Database::SYSTEM_COLLECTION_PROJECTS !== $project->getCollection()) { $project = $console; } @@ -167,7 +168,7 @@ $mode = $request->getParam('mode', $request->getHeader('X-Appwrite-Mode', 'defau Auth::setCookieName('a-session-' . $project->getUid()); -if(APP_MODE_ADMIN === $mode) { +if (APP_MODE_ADMIN === $mode) { Auth::setCookieName('a-session-' . $console->getUid()); } @@ -182,7 +183,7 @@ $projectDB->setMocks($collections); $user = $projectDB->getDocument(Auth::$unique); -if(APP_MODE_ADMIN === $mode) { +if (APP_MODE_ADMIN === $mode) { $user = $consoleDB->getDocument(Auth::$unique); $user @@ -190,17 +191,16 @@ if(APP_MODE_ADMIN === $mode) { ; } -if(empty($user->getUid()) // Check a document has been found in the DB +if (empty($user->getUid()) // Check a document has been found in the DB || Database::SYSTEM_COLLECTION_USERS !== $user->getCollection() // Validate returned document is really a user document || !Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_LOGIN, Auth::$secret)) { // Validate user has valid login token $user = new Document(['$uid' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]); } -if(APP_MODE_ADMIN === $mode) { - if(!empty($user->search('teamId', $project->getAttribute('teamId'), $user->getAttribute('memberships')))) { +if (APP_MODE_ADMIN === $mode) { + if (!empty($user->search('teamId', $project->getAttribute('teamId'), $user->getAttribute('memberships')))) { Authorization::disable(); - } - else { + } else { $user = new Document(['$uid' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]); } } diff --git a/app/sdks/php/docs/locale.md b/app/sdks/php/docs/locale.md index 7635546481..e977fa99cf 100644 --- a/app/sdks/php/docs/locale.md +++ b/app/sdks/php/docs/locale.md @@ -38,5 +38,5 @@ GET https://appwrite.test/v1/locale/countries/phones GET https://appwrite.test/v1/locale/currencies ``` -** List of all currencies, including currency symol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in supported language. ** +** List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in supported language. ** diff --git a/app/sdks/php/src/Appwrite/Client.php b/app/sdks/php/src/Appwrite/Client.php index 1ce0b3f536..edd8ec6671 100644 --- a/app/sdks/php/src/Appwrite/Client.php +++ b/app/sdks/php/src/Appwrite/Client.php @@ -185,7 +185,7 @@ class Client curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, php_uname('s') . '-' . php_uname('r') . ':php-' . phpversion()); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use (&$responseHeaders) { + curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) { $len = strlen($header); $header = explode(':', strtolower($header), 2); @@ -198,12 +198,12 @@ class Client return $len; }); - if($method != self::METHOD_GET) { + if ($method != self::METHOD_GET) { curl_setopt($ch, CURLOPT_POSTFIELDS, $query); } // Allow self signed certificates - if($this->selfSigned) { + if ($this->selfSigned) { curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } @@ -212,7 +212,7 @@ class Client $responseType = (isset($responseHeaders['content-type'])) ? $responseHeaders['content-type'] : ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); - switch(substr($responseType, 0, strpos($responseType, ';'))) { + switch (substr($responseType, 0, strpos($responseType, ';'))) { case 'application/json': $responseBody = json_decode($responseBody, true); break; @@ -234,16 +234,16 @@ class Client * @param string $prefix * @return array */ - protected function flatten(array $data, $prefix = '') { + protected function flatten(array $data, $prefix = '') + { $output = []; - foreach($data as $key => $value) { + foreach ($data as $key => $value) { $finalKey = $prefix ? "{$prefix}[{$key}]" : $key; if (is_array($value)) { $output += $this->flatten($value, $finalKey); // @todo: handle name collision here if needed - } - else { + } else { $output[$finalKey] = $value; } } diff --git a/app/sdks/php/src/Appwrite/Service.php b/app/sdks/php/src/Appwrite/Service.php index ea3ad92e2d..4eabee9e76 100644 --- a/app/sdks/php/src/Appwrite/Service.php +++ b/app/sdks/php/src/Appwrite/Service.php @@ -16,4 +16,4 @@ abstract class Service { $this->client = $client; } -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Account.php b/app/sdks/php/src/Appwrite/Services/Account.php index a1df7cb1ee..90650d4b5e 100644 --- a/app/sdks/php/src/Appwrite/Services/Account.php +++ b/app/sdks/php/src/Appwrite/Services/Account.php @@ -188,5 +188,4 @@ class Account extends Service return $this->client->call(Client::METHOD_GET, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Auth.php b/app/sdks/php/src/Appwrite/Services/Auth.php index 7b7495936b..d19cd05e91 100644 --- a/app/sdks/php/src/Appwrite/Services/Auth.php +++ b/app/sdks/php/src/Appwrite/Services/Auth.php @@ -13,13 +13,13 @@ class Auth extends Service * * Allow the user to login into his account by providing a valid email and * password combination. Use the success and failure arguments to provide a - * redirect URL\'s back to your app when login is completed. - * + * redirect URL\'s back to your app when login is completed. + * * Please notice that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) * the only valid redirect URL's are the once from domains you have set when * added your platforms in the console interface. - * + * * When not using the success or failure redirect arguments this endpoint will * result with a 200 status code and the user account object on success and * with 401 status error on failure. This behavior was applied to help the web @@ -165,7 +165,7 @@ class Auth extends Service * **userId** and **token** arguments will be passed as query parameters to * the redirect URL you have provided when sending your request to the * /auth/recovery endpoint. - * + * * Please notice that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) * the only valid redirect URL's are the once from domains you have set when @@ -198,18 +198,18 @@ class Auth extends Service * Use this endpoint to allow a new user to register an account in your * project. Use the success and failure URL's to redirect users back to your * application after signup completes. - * + * * If registration completes successfully user will be sent with a * confirmation email in order to confirm he is the owner of the account email * address. Use the redirect parameter to redirect the user from the * confirmation email back to your app. When the user is redirected, use the * /auth/confirm endpoint to complete the account confirmation. - * + * * Please notice that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) * the only valid redirect URL's are the once from domains you have set when * added your platforms in the console interface. - * + * * When not using the success or failure redirect arguments this endpoint will * result with a 200 status code and the user account object on success and * with 401 status error on failure. This behavior was applied to help the web @@ -272,7 +272,7 @@ class Auth extends Service * This endpoint allows the user to request your app to resend him his email * confirmation message. The redirect arguments acts the same way as in * /auth/register endpoint. - * + * * Please notice that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) * the only valid redirect URL's are the once from domains you have set when @@ -292,5 +292,4 @@ class Auth extends Service return $this->client->call(Client::METHOD_POST, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Avatars.php b/app/sdks/php/src/Appwrite/Services/Avatars.php index 8ee781814a..9a6dbedca5 100644 --- a/app/sdks/php/src/Appwrite/Services/Avatars.php +++ b/app/sdks/php/src/Appwrite/Services/Avatars.php @@ -165,5 +165,4 @@ class Avatars extends Service return $this->client->call(Client::METHOD_GET, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Database.php b/app/sdks/php/src/Appwrite/Services/Database.php index 1310909a54..b0e0565512 100644 --- a/app/sdks/php/src/Appwrite/Services/Database.php +++ b/app/sdks/php/src/Appwrite/Services/Database.php @@ -267,5 +267,4 @@ class Database extends Service return $this->client->call(Client::METHOD_DELETE, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Locale.php b/app/sdks/php/src/Appwrite/Services/Locale.php index 1ae5ae0427..e11104c75b 100644 --- a/app/sdks/php/src/Appwrite/Services/Locale.php +++ b/app/sdks/php/src/Appwrite/Services/Locale.php @@ -106,5 +106,4 @@ class Locale extends Service return $this->client->call(Client::METHOD_GET, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Projects.php b/app/sdks/php/src/Appwrite/Services/Projects.php index af68cf4e9a..f1cf92cc0a 100644 --- a/app/sdks/php/src/Appwrite/Services/Projects.php +++ b/app/sdks/php/src/Appwrite/Services/Projects.php @@ -610,5 +610,4 @@ class Projects extends Service return $this->client->call(Client::METHOD_DELETE, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Storage.php b/app/sdks/php/src/Appwrite/Services/Storage.php index e22622ebed..26b771a67c 100644 --- a/app/sdks/php/src/Appwrite/Services/Storage.php +++ b/app/sdks/php/src/Appwrite/Services/Storage.php @@ -205,5 +205,4 @@ class Storage extends Service return $this->client->call(Client::METHOD_GET, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Teams.php b/app/sdks/php/src/Appwrite/Services/Teams.php index 2c331b4c79..8b4f5c81a5 100644 --- a/app/sdks/php/src/Appwrite/Services/Teams.php +++ b/app/sdks/php/src/Appwrite/Services/Teams.php @@ -149,12 +149,12 @@ class Teams extends Service * Use this endpoint to invite a new member to your team. An email with a link * to join the team will be sent to the new member email address. If member * doesn't exists in the project it will be automatically created. - * + * * Use the redirect parameter to redirect the user from the invitation email * back to your app. When the user is redirected, use the * /teams/{teamId}/memberships/{inviteId}/status endpoint to finally join the * user to the team. - * + * * Please notice that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) * the only valid redirect URL's are the once from domains you have set when @@ -233,12 +233,12 @@ class Teams extends Service * is being redirect back to your app from the invitation email. Use the * success and failure URL's to redirect users back to your application after * the request completes. - * + * * Please notice that in order to avoid a [Redirect * Attacks](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) * the only valid redirect URL's are the once from domains you have set when * added your platforms in the console interface. - * + * * When not using the success or failure redirect arguments this endpoint will * result with a 200 status code on success and with 401 status error on * failure. This behavior was applied to help the web clients deal with @@ -267,5 +267,4 @@ class Teams extends Service return $this->client->call(Client::METHOD_PATCH, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/sdks/php/src/Appwrite/Services/Users.php b/app/sdks/php/src/Appwrite/Services/Users.php index 3b893c0e96..9159719e9b 100644 --- a/app/sdks/php/src/Appwrite/Services/Users.php +++ b/app/sdks/php/src/Appwrite/Services/Users.php @@ -195,5 +195,4 @@ class Users extends Service return $this->client->call(Client::METHOD_PATCH, $path, [ ], $params); } - -} \ No newline at end of file +} diff --git a/app/tasks/sdks.php b/app/tasks/sdks.php index f47564e405..1c3ab7b410 100644 --- a/app/tasks/sdks.php +++ b/app/tasks/sdks.php @@ -19,7 +19,6 @@ $cli = new CLI(); $cli ->task('generate') ->action(function () { - function getSSLPage($url) { $ch = curl_init(); @@ -211,4 +210,4 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND } }); -$cli->run(); \ No newline at end of file +$cli->run(); diff --git a/app/views/console/users/index.phtml b/app/views/console/users/index.phtml index ccc532861c..0ee7c32bed 100644 --- a/app/views/console/users/index.phtml +++ b/app/views/console/users/index.phtml @@ -307,8 +307,13 @@ $providers = $this->getParam('providers', []);
  • Providers

    - -
    + +
      $data): if(isset($data['enabled']) && !$data['enabled']) { continue; } ?>
    • @@ -357,7 +362,9 @@ $providers = $this->getParam('providers', []); - +  Disabled diff --git a/app/views/home/auth/recovery.phtml b/app/views/home/auth/recovery.phtml index 9511c66b85..9e5fd590f4 100644 --- a/app/views/home/auth/recovery.phtml +++ b/app/views/home/auth/recovery.phtml @@ -18,7 +18,7 @@ - + diff --git a/app/views/home/auth/signup.phtml b/app/views/home/auth/signup.phtml index 0399bcc2e0..f0882531fc 100644 --- a/app/views/home/auth/signup.phtml +++ b/app/views/home/auth/signup.phtml @@ -18,7 +18,7 @@ data-failure-param-alert-text="Registration Failed. Please try again later" data-failure-param-alert-classname="error"> - + diff --git a/app/workers/tasks.php b/app/workers/tasks.php index c1f6592848..64d70ed1c8 100644 --- a/app/workers/tasks.php +++ b/app/workers/tasks.php @@ -91,7 +91,10 @@ class TasksV1 curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, sprintf(APP_USERAGENT, $version)); - curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge($headers, [ + curl_setopt( + $ch, + CURLOPT_HTTPHEADER, + array_merge($headers, [ 'X-'.APP_NAME.'-Task-UID: '.$task->getAttribute('$uid', ''), 'X-'.APP_NAME.'-Task-Name: '.$task->getAttribute('name', ''), ]) diff --git a/app/workers/webhooks.php b/app/workers/webhooks.php index 00e03257dc..469a833b72 100644 --- a/app/workers/webhooks.php +++ b/app/workers/webhooks.php @@ -59,7 +59,10 @@ class WebhooksV1 curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, sprintf(APP_USERAGENT, $version)); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ + curl_setopt( + $ch, + CURLOPT_HTTPHEADER, + [ 'Content-Type: application/json', 'Content-Length: '.strlen($payload), 'X-'.APP_NAME.'-Event: '.$event, diff --git a/composer.lock b/composer.lock index b97afcba14..c1a3f41e58 100644 --- a/composer.lock +++ b/composer.lock @@ -4,6 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], + "hash": "cf3e9453a93f3ee5cfec76f6cd6bc139", "content-hash": "470f543ebf989400a43a6269f0b4d60a", "packages": [ { @@ -12,12 +13,12 @@ "source": { "type": "git", "url": "https://github.com/appwrite/sdk-for-php.git", - "reference": "6d920c6f7aa7c36a06915bbe4b91ab5a9cf7ebb6" + "reference": "457a20948a7f1e9b8e4cea09205b6fd42f8ca811" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/6d920c6f7aa7c36a06915bbe4b91ab5a9cf7ebb6", - "reference": "6d920c6f7aa7c36a06915bbe4b91ab5a9cf7ebb6", + "url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/457a20948a7f1e9b8e4cea09205b6fd42f8ca811", + "reference": "457a20948a7f1e9b8e4cea09205b6fd42f8ca811", "shasum": "" }, "require": { @@ -39,7 +40,7 @@ "BSD-3-Clause" ], "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)", - "time": "2019-09-20T06:34:28+00:00" + "time": "2019-09-21T12:46:08+00:00" }, { "name": "appwrite/php-clamav", @@ -84,7 +85,7 @@ "clamav", "php" ], - "time": "2019-09-08 17:36:32" + "time": "2019-09-08T17:36:32+00:00" }, { "name": "appwrite/sdk-generator", @@ -92,7 +93,15 @@ "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator", - "reference": "e456fafb3d32a83c104a47ad064b2295281e58c0" +<<<<<<< HEAD +<<<<<<< HEAD + "reference": "2cdf218f735e5c52a47f1d8977f460261fd9017f" +======= + "reference": "22cd594e2406fbcfc64262fdcdfa78069bf29aa0" +>>>>>>> upstream/master +======= + "reference": "22cd594e2406fbcfc64262fdcdfa78069bf29aa0" +>>>>>>> upstream/master }, "require": { "ext-curl": "*", @@ -122,7 +131,15 @@ } ], "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", - "time": "2019-09-20 06:30:54" +<<<<<<< HEAD +<<<<<<< HEAD + "time": "2019-09-22 12:47:11" +======= + "time": "2019-09-28 23:31:14" +>>>>>>> upstream/master +======= + "time": "2019-09-28 23:31:14" +>>>>>>> upstream/master }, { "name": "bacon/bacon-qr-code", @@ -171,7 +188,7 @@ ], "description": "BaconQrCode is a QR code generator for PHP.", "homepage": "https://github.com/Bacon/BaconQrCode", - "time": "2018-04-25T17:53:56+00:00" + "time": "2018-04-25 17:53:56" }, { "name": "chrisboulton/php-resque", @@ -228,7 +245,7 @@ "resque" ], "abandoned": "resque/php-resque", - "time": "2017-04-12 21:58:19" + "time": "2017-04-12T21:58:19+00:00" }, { "name": "chrisboulton/php-resque-scheduler", @@ -264,7 +281,7 @@ } ], "description": "php-resque-scheduler is a PHP port of resque-scheduler, which adds support for scheduling items in the future to Resque.", - "time": "2016-11-28 22:38:06" + "time": "2016-11-28T22:38:06+00:00" }, { "name": "colinmollenhour/credis", @@ -304,7 +321,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2019-03-05T16:29:14+00:00" + "time": "2019-03-05 16:29:14" }, { "name": "composer/ca-bundle", @@ -360,7 +377,7 @@ "ssl", "tls" ], - "time": "2019-08-30 08:44:50" + "time": "2019-08-30T08:44:50+00:00" }, { "name": "dasprid/enum", @@ -402,7 +419,7 @@ "enum", "map" ], - "time": "2017-10-25T22:45:27+00:00" + "time": "2017-10-25 22:45:27" }, { "name": "domnikl/statsd", @@ -449,7 +466,7 @@ "statsd", "udp" ], - "time": "2014-12-09T09:37:49+00:00" + "time": "2014-12-09 09:37:49" }, { "name": "dragonmantank/cron-expression", @@ -498,7 +515,7 @@ "cron", "schedule" ], - "time": "2018-06-06T03:12:17+00:00" + "time": "2018-06-06 03:12:17" }, { "name": "geoip2/geoip2", @@ -550,7 +567,7 @@ "geolocation", "maxmind" ], - "time": "2018-04-10T15:32:59+00:00" + "time": "2018-04-10 15:32:59" }, { "name": "guzzlehttp/guzzle", @@ -616,7 +633,7 @@ "rest", "web service" ], - "time": "2019-08-23 22:16:30" + "time": "2019-08-23T22:16:30+00:00" }, { "name": "guzzlehttp/promises", @@ -667,7 +684,7 @@ "keywords": [ "promise" ], - "time": "2019-07-02 14:54:06" + "time": "2019-07-02T14:54:06+00:00" }, { "name": "guzzlehttp/psr7", @@ -738,7 +755,7 @@ "uri", "url" ], - "time": "2019-08-13 16:05:52" + "time": "2019-08-13T16:05:52+00:00" }, { "name": "influxdb/influxdb-php", @@ -799,7 +816,7 @@ "influxdb library", "time series" ], - "time": "2019-05-30T00:15:14+00:00" + "time": "2019-05-30 00:15:14" }, { "name": "matthiasmullie/minify", @@ -859,7 +876,7 @@ "minifier", "minify" ], - "time": "2018-11-26T23:10:39+00:00" + "time": "2018-11-26 23:10:39" }, { "name": "matthiasmullie/path-converter", @@ -908,7 +925,7 @@ "paths", "relative" ], - "time": "2018-10-25T15:19:41+00:00" + "time": "2018-10-25 15:19:41" }, { "name": "maxmind-db/reader", @@ -964,7 +981,7 @@ "geolocation", "maxmind" ], - "time": "2019-01-04T19:55:56+00:00" + "time": "2019-01-04 19:55:56" }, { "name": "maxmind/web-service-common", @@ -1010,20 +1027,20 @@ ], "description": "Internal MaxMind Web Service API", "homepage": "https://github.com/maxmind/web-service-common-php", - "time": "2018-02-12T22:31:54+00:00" + "time": "2018-02-12 22:31:54" }, { "name": "mustangostang/spyc", "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/mustangostang/spyc.git", - "reference": "576c42ecbc9630b52a95da3279f07278572c6b15" + "url": "git@github.com:mustangostang/spyc.git", + "reference": "4627c838b16550b666d15aeae1e5289dd5b77da0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mustangostang/spyc/zipball/576c42ecbc9630b52a95da3279f07278572c6b15", - "reference": "576c42ecbc9630b52a95da3279f07278572c6b15", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/4627c838b16550b666d15aeae1e5289dd5b77da0", + "reference": "4627c838b16550b666d15aeae1e5289dd5b77da0", "shasum": "" }, "require": { @@ -1060,7 +1077,7 @@ "yaml", "yml" ], - "time": "2017-07-23 16:38:44" + "time": "2019-09-10T13:16:29+00:00" }, { "name": "phpmailer/phpmailer", @@ -1126,7 +1143,7 @@ } ], "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "time": "2019-02-01T15:04:28+00:00" + "time": "2019-02-01 15:04:28" }, { "name": "piwik/device-detector", @@ -1177,7 +1194,7 @@ "parser", "useragent" ], - "time": "2016-01-21T22:26:37+00:00" + "time": "2016-01-21 22:26:37" }, { "name": "psr/http-message", @@ -1227,7 +1244,7 @@ "request", "response" ], - "time": "2019-08-29 13:16:46" + "time": "2019-08-29T13:16:46+00:00" }, { "name": "psr/log", @@ -1274,7 +1291,7 @@ "psr", "psr-3" ], - "time": "2018-11-21 13:42:00" + "time": "2018-11-21T13:42:00+00:00" }, { "name": "ralouphie/getallheaders", @@ -1314,7 +1331,7 @@ } ], "description": "A polyfill for getallheaders.", - "time": "2019-03-08T08:55:37+00:00" + "time": "2019-03-08 08:55:37" }, { "name": "symfony/polyfill-ctype", @@ -1372,7 +1389,7 @@ "polyfill", "portable" ], - "time": "2019-08-06 08:03:45" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -1431,7 +1448,7 @@ "portable", "shim" ], - "time": "2019-09-17 10:46:08" + "time": "2019-09-17T10:46:08+00:00" }, { "name": "twig/twig", @@ -1439,12 +1456,12 @@ "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "d83802c011b99b5326ccd13e7fc87bacebd4c724" + "reference": "c2fd9990fcab344b67a12ead04890a88141d5897" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/d83802c011b99b5326ccd13e7fc87bacebd4c724", - "reference": "d83802c011b99b5326ccd13e7fc87bacebd4c724", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/c2fd9990fcab344b67a12ead04890a88141d5897", + "reference": "c2fd9990fcab344b67a12ead04890a88141d5897", "shasum": "" }, "require": { @@ -1498,7 +1515,15 @@ "keywords": [ "templating" ], - "time": "2019-09-17 06:08:14" +<<<<<<< HEAD +<<<<<<< HEAD + "time": "2019-09-20 12:53:54" +======= + "time": "2019-09-20T12:53:54+00:00" +>>>>>>> upstream/master +======= + "time": "2019-09-20T12:53:54+00:00" +>>>>>>> upstream/master }, { "name": "utopia-php/abuse", @@ -1545,7 +1570,7 @@ "upf", "utopia" ], - "time": "2019-05-08 20:26:59" + "time": "2019-05-08T20:26:59+00:00" }, { "name": "utopia-php/cache", @@ -1592,7 +1617,7 @@ "upf", "utopia" ], - "time": "2019-05-08 20:28:54" + "time": "2019-05-08T20:28:54+00:00" }, { "name": "utopia-php/cli", @@ -1640,7 +1665,7 @@ "upf", "utopia" ], - "time": "2019-05-08 20:27:54" + "time": "2019-05-08T20:27:54+00:00" }, { "name": "utopia-php/framework", @@ -1684,7 +1709,7 @@ "php", "upf" ], - "time": "2019-08-15 06:36:30" + "time": "2019-08-15T06:36:30+00:00" }, { "name": "utopia-php/locale", @@ -1730,7 +1755,7 @@ "upf", "utopia" ], - "time": "2019-08-17 08:18:24" + "time": "2019-08-17T08:18:24+00:00" }, { "name": "utopia-php/registry", @@ -1777,7 +1802,9 @@ "upf", "utopia" ], - "time": "2019-05-08 20:25:57" + "time": "2019-05-08T20:25:57+00:00" +<<<<<<< HEAD +======= } ], "packages-dev": [ @@ -3195,8 +3222,10 @@ "validate" ], "time": "2019-08-24T08:43:50+00:00" +>>>>>>> upstream/master } ], + "packages-dev": null, "aliases": [], "minimum-stability": "dev", "stability-flags": [], diff --git a/docker-compose.yml b/docker-compose.yml index 2cd1d9bb4d..c45a3294f7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,12 +16,12 @@ services: - "80:80" - "443:443" depends_on: - - mariadb - - redis - - smtp - - clamav - - influxdb - - telegraf + - mariadb + - redis + - smtp + - clamav + - influxdb + - telegraf environment: - _APP_ENV=development - _APP_OPENSSL_KEY_V1=your-secret-key diff --git a/docs/AddOAuthProvider.md b/docs/AddOAuthProvider.md index d35278d879..290f2a91df 100644 --- a/docs/AddOAuthProvider.md +++ b/docs/AddOAuthProvider.md @@ -18,11 +18,11 @@ The first step in adding a new OAuth provider is to list it in providers config ./app/config/providers.php ``` -Make sure to fill all data needed and that your provider array key name is in camelcase format and has no spaces or special characters. +Make sure to fill all data needed and that your provider array key name is in camelCase format and has no spaces or special characters. ### Add Provider Logo -Add a logo image to your new provider in this path: ./public/images/oauth. Your logo should be a png 100X100px file with the name ofyour provider (all lowercase). Please make sure to leave about 20px padding around the logo to be consistent with other logos. +Add a logo image to your new provider in this path: ./public/images/oauth. Your logo should be a png 100×100px file with the name of your provider (all lowercase). Please make sure to leave about 20px padding around the logo to be consistent with other logos. ### Add Provider Class @@ -30,8 +30,8 @@ Once finished setting all the metadata for the new provider you need to start co Create a new class that extends the basic OAuth provider abstract class in this location: -``` -\Auth\OAuth\ProviderName +```bash +src/Auth/OAuth/ProviderName ``` Note that the class name should start with a capital letter as PHP FIG standards suggest. diff --git a/package-lock.json b/package-lock.json index 1e3a04feb7..82fc5d86f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2517,8 +2517,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -2933,8 +2932,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -2990,7 +2988,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3034,14 +3031,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js index 6bedf84d45..6cb864f00c 100644 --- a/public/dist/scripts/app-all.js +++ b/public/dist/scripts/app-all.js @@ -38,15 +38,15 @@ let path='/auth/recovery';return http.post(path,{'content-type':'application/jso if(token===undefined){throw new Error('Missing required parameter: "token"');} if(passwordA===undefined){throw new Error('Missing required parameter: "passwordA"');} if(passwordB===undefined){throw new Error('Missing required parameter: "passwordB"');} -let path='/auth/recovery/reset';return http.put(path,{'content-type':'application/json'},{'userId':userId,'token':token,'password-a':passwordA,'password-b':passwordB});},register:function(email,password,confirmation,success,failure,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} +let path='/auth/recovery/reset';return http.put(path,{'content-type':'application/json'},{'userId':userId,'token':token,'password-a':passwordA,'password-b':passwordB});},register:function(email,password,confirm,success,failure,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} if(password===undefined){throw new Error('Missing required parameter: "password"');} -if(confirmation===undefined){throw new Error('Missing required parameter: "confirmation"');} +if(confirm===undefined){throw new Error('Missing required parameter: "confirm"');} if(success===undefined){throw new Error('Missing required parameter: "success"');} if(failure===undefined){throw new Error('Missing required parameter: "failure"');} -let path='/auth/register';return iframe('post',path,{project:config.project,'email':email,'password':password,'confirmation':confirmation,'success':success,'failure':failure,'name':name});},confirm:function(userId,token){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} +let path='/auth/register';return iframe('post',path,{project:config.project,'email':email,'password':password,'confirm':confirm,'success':success,'failure':failure,'name':name});},confirm:function(userId,token){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} if(token===undefined){throw new Error('Missing required parameter: "token"');} -let path='/auth/register/confirm';return http.post(path,{'content-type':'application/json'},{'userId':userId,'token':token});},confirmResend:function(redirect){if(redirect===undefined){throw new Error('Missing required parameter: "redirect"');} -let path='/auth/register/confirm/resend';return http.post(path,{'content-type':'application/json'},{'redirect':redirect});}};let avatars={getBrowser:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +let path='/auth/register/confirm';return http.post(path,{'content-type':'application/json'},{'userId':userId,'token':token});},confirmResend:function(confirm){if(confirm===undefined){throw new Error('Missing required parameter: "confirm"');} +let path='/auth/register/confirm/resend';return http.post(path,{'content-type':'application/json'},{'confirm':confirm});}};let avatars={getBrowser:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/browsers/{code}'.replace(new RegExp('{code}','g'),code);return http.get(path,{'content-type':'application/json'},{'width':width,'height':height,'quality':quality});},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/credit-cards/{code}'.replace(new RegExp('{code}','g'),code);return http.get(path,{'content-type':'application/json'},{'width':width,'height':height,'quality':quality});},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/favicon';return http.get(path,{'content-type':'application/json'},{'url':url});},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} diff --git a/public/dist/scripts/app-dep.js b/public/dist/scripts/app-dep.js index 495f8590ca..ae384c0c91 100644 --- a/public/dist/scripts/app-dep.js +++ b/public/dist/scripts/app-dep.js @@ -38,15 +38,15 @@ let path='/auth/recovery';return http.post(path,{'content-type':'application/jso if(token===undefined){throw new Error('Missing required parameter: "token"');} if(passwordA===undefined){throw new Error('Missing required parameter: "passwordA"');} if(passwordB===undefined){throw new Error('Missing required parameter: "passwordB"');} -let path='/auth/recovery/reset';return http.put(path,{'content-type':'application/json'},{'userId':userId,'token':token,'password-a':passwordA,'password-b':passwordB});},register:function(email,password,confirmation,success,failure,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} +let path='/auth/recovery/reset';return http.put(path,{'content-type':'application/json'},{'userId':userId,'token':token,'password-a':passwordA,'password-b':passwordB});},register:function(email,password,confirm,success,failure,name=''){if(email===undefined){throw new Error('Missing required parameter: "email"');} if(password===undefined){throw new Error('Missing required parameter: "password"');} -if(confirmation===undefined){throw new Error('Missing required parameter: "confirmation"');} +if(confirm===undefined){throw new Error('Missing required parameter: "confirm"');} if(success===undefined){throw new Error('Missing required parameter: "success"');} if(failure===undefined){throw new Error('Missing required parameter: "failure"');} -let path='/auth/register';return iframe('post',path,{project:config.project,'email':email,'password':password,'confirmation':confirmation,'success':success,'failure':failure,'name':name});},confirm:function(userId,token){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} +let path='/auth/register';return iframe('post',path,{project:config.project,'email':email,'password':password,'confirm':confirm,'success':success,'failure':failure,'name':name});},confirm:function(userId,token){if(userId===undefined){throw new Error('Missing required parameter: "userId"');} if(token===undefined){throw new Error('Missing required parameter: "token"');} -let path='/auth/register/confirm';return http.post(path,{'content-type':'application/json'},{'userId':userId,'token':token});},confirmResend:function(redirect){if(redirect===undefined){throw new Error('Missing required parameter: "redirect"');} -let path='/auth/register/confirm/resend';return http.post(path,{'content-type':'application/json'},{'redirect':redirect});}};let avatars={getBrowser:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} +let path='/auth/register/confirm';return http.post(path,{'content-type':'application/json'},{'userId':userId,'token':token});},confirmResend:function(confirm){if(confirm===undefined){throw new Error('Missing required parameter: "confirm"');} +let path='/auth/register/confirm/resend';return http.post(path,{'content-type':'application/json'},{'confirm':confirm});}};let avatars={getBrowser:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/browsers/{code}'.replace(new RegExp('{code}','g'),code);return http.get(path,{'content-type':'application/json'},{'width':width,'height':height,'quality':quality});},getCreditCard:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} let path='/avatars/credit-cards/{code}'.replace(new RegExp('{code}','g'),code);return http.get(path,{'content-type':'application/json'},{'width':width,'height':height,'quality':quality});},getFavicon:function(url){if(url===undefined){throw new Error('Missing required parameter: "url"');} let path='/avatars/favicon';return http.get(path,{'content-type':'application/json'},{'url':url});},getFlag:function(code,width=100,height=100,quality=100){if(code===undefined){throw new Error('Missing required parameter: "code"');} diff --git a/public/images/oauth/gitlab.png b/public/images/oauth/gitlab.png new file mode 100644 index 0000000000..35cb5e9dab Binary files /dev/null and b/public/images/oauth/gitlab.png differ diff --git a/public/images/oauth/google.png b/public/images/oauth/google.png new file mode 100644 index 0000000000..cd60f3a111 Binary files /dev/null and b/public/images/oauth/google.png differ diff --git a/public/index.php b/public/index.php index 6acdac894d..b37cdb732b 100644 --- a/public/index.php +++ b/public/index.php @@ -31,4 +31,4 @@ switch ($version) { // Switch between API version $service = $version . '/'; include __DIR__ . '/../app/app.php'; break; -} \ No newline at end of file +} diff --git a/src/Audit/Adapter/MySQL.php b/src/Audit/Adapter/MySQL.php index 297807795a..9f14940e08 100644 --- a/src/Audit/Adapter/MySQL.php +++ b/src/Audit/Adapter/MySQL.php @@ -46,14 +46,14 @@ class MySQL extends Adapter $data = mb_strcut(json_encode($data), 0, 64000, 'UTF-8'); // Limit data to MySQL 64kb limit - $st->bindValue(':userId', $userId, PDO::PARAM_STR); - $st->bindValue(':userType', $userType, PDO::PARAM_INT); - $st->bindValue(':event', $event, PDO::PARAM_STR); - $st->bindValue(':resource', $resource, PDO::PARAM_STR); - $st->bindValue(':userAgent', $userAgent, PDO::PARAM_STR); - $st->bindValue(':ip', $ip, PDO::PARAM_STR); - $st->bindValue(':location', $location, PDO::PARAM_STR); - $st->bindValue(':data', $data, PDO::PARAM_STR); + $st->bindValue(':userId', $userId, PDO::PARAM_STR); + $st->bindValue(':userType', $userType, PDO::PARAM_INT); + $st->bindValue(':event', $event, PDO::PARAM_STR); + $st->bindValue(':resource', $resource, PDO::PARAM_STR); + $st->bindValue(':userAgent', $userAgent, PDO::PARAM_STR); + $st->bindValue(':ip', $ip, PDO::PARAM_STR); + $st->bindValue(':location', $location, PDO::PARAM_STR); + $st->bindValue(':data', $data, PDO::PARAM_STR); $st->execute(); @@ -69,8 +69,8 @@ class MySQL extends Adapter ORDER BY `time` DESC LIMIT 10 '); - $st->bindValue(':userId', $userId, PDO::PARAM_STR); - $st->bindValue(':userType', $userType, PDO::PARAM_INT); + $st->bindValue(':userId', $userId, PDO::PARAM_STR); + $st->bindValue(':userType', $userType, PDO::PARAM_INT); $st->execute(); @@ -95,8 +95,8 @@ class MySQL extends Adapter ORDER BY `time` DESC LIMIT 10 '); - $st->bindValue(':userId', $userId, PDO::PARAM_STR); - $st->bindValue(':userType', $userType, PDO::PARAM_INT); + $st->bindValue(':userId', $userId, PDO::PARAM_STR); + $st->bindValue(':userType', $userType, PDO::PARAM_INT); foreach ($actions as $k => $id) { $st->bindValue(':action_'.$k, $id); diff --git a/src/Auth/OAuth.php b/src/Auth/OAuth.php index ae9539fa41..ec1ae9eff6 100644 --- a/src/Auth/OAuth.php +++ b/src/Auth/OAuth.php @@ -94,13 +94,15 @@ abstract class OAuth curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, 'Console_OAuth_Agent'); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); if (!empty($payload)) { curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); } - // Send the request & save response to $resp + $headers[] = "Content-length: ".strlen($payload); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + // Send the request & save response to $response $response = curl_exec($ch); curl_close($ch); diff --git a/src/Auth/OAuth/Facebook.php b/src/Auth/OAuth/Facebook.php index 1c1bbfd60b..ed50748bac 100644 --- a/src/Auth/OAuth/Facebook.php +++ b/src/Auth/OAuth/Facebook.php @@ -39,7 +39,9 @@ class Facebook extends OAuth */ public function getAccessToken(string $code):string { - $accessToken = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'. + $accessToken = $this->request( + 'GET', + 'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'. 'client_id='.urlencode($this->appID). '&redirect_uri='.urlencode($this->callback). '&client_secret='.urlencode($this->appSecret). diff --git a/src/Auth/OAuth/GitHub.php b/src/Auth/OAuth/GitHub.php index bcae83c53a..405f2f9f78 100644 --- a/src/Auth/OAuth/GitHub.php +++ b/src/Auth/OAuth/GitHub.php @@ -34,7 +34,10 @@ class Github extends OAuth */ public function getAccessToken(string $code):string { - $accessToken = $this->request('POST', 'https://github.com/login/oauth/access_token', [], + $accessToken = $this->request( + 'POST', + 'https://github.com/login/oauth/access_token', + [], 'client_id='.urlencode($this->appID). '&redirect_uri='.urlencode($this->callback). '&client_secret='.urlencode($this->appSecret). diff --git a/src/Auth/OAuth/Gitlab.php b/src/Auth/OAuth/Gitlab.php new file mode 100644 index 0000000000..923add88f7 --- /dev/null +++ b/src/Auth/OAuth/Gitlab.php @@ -0,0 +1,123 @@ +appID) . + '&redirect_uri=' . urlencode($this->callback) . + '&scope=read_user' . + '&state=' . urlencode(json_encode($this->state)) . + '&response_type=code'; + } + + /** + * @param string $code + * + * @return string + */ + public function getAccessToken(string $code): string + { + $accessToken = $this->request( + 'POST', + 'https://gitlab.com/oauth/token?'. + 'code=' . urlencode($code) . + '&client_id=' . urlencode($this->appID) . + '&client_secret=' . urlencode($this->appSecret) . + '&redirect_uri=' . urlencode($this->callback) . + '&grant_type=authorization_code' + ); + + $accessToken = json_decode($accessToken, true); + + if (isset($accessToken['access_token'])) { + return $accessToken['access_token']; + } + + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserID(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['id'])) { + return $user['id']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserEmail(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['email'])) { + return $user['email']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserName(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['name'])) { + return $user['name']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return array + */ + protected function getUser(string $accessToken): array + { + if (empty($this->user)) { + $user = $this->request('GET', 'https://gitlab.com/api/v4/user?access_token=' . urlencode($accessToken)); + $this->user = json_decode($user, true); + } + return $this->user; + } +} diff --git a/src/Auth/OAuth/Google.php b/src/Auth/OAuth/Google.php new file mode 100644 index 0000000000..252d629ab5 --- /dev/null +++ b/src/Auth/OAuth/Google.php @@ -0,0 +1,127 @@ +appID) . + '&redirect_uri=' . urlencode($this->callback) . + '&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile' . + '&state=' . urlencode(json_encode($this->state)) . + '&response_type=code'; + } + + /** + * @param string $code + * + * @return string + */ + public function getAccessToken(string $code): string + { + $accessToken = $this->request( + 'POST', + 'https://www.googleapis.com/oauth2/' . $this->version . '/token?' . + 'code=' . urlencode($code) . + '&client_id=' . urlencode($this->appID) . + '&client_secret=' . urlencode($this->appSecret) . + '&redirect_uri=' . urlencode($this->callback) . + '&scope=' . + '&grant_type=authorization_code' + ); + + $accessToken = json_decode($accessToken, true); + + if (isset($accessToken['access_token'])) { + return $accessToken['access_token']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserID(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['id'])) { + return $user['id']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserEmail(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['email'])) { + return $user['email']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserName(string $accessToken): string + { + $user = $this->getUser($accessToken); + + if (isset($user['name'])) { + return $user['name']; + } + + return ''; + } + + /** + * @param string $accessToken + * + * @return array + */ + protected function getUser(string $accessToken): array + { + if (empty($this->user)) { + $user = $this->request('GET', 'https://www.googleapis.com/oauth2/v2/userinfo?access_token=' . urlencode($accessToken)); + $this->user = json_decode($user, true); + } + return $this->user; + } +} diff --git a/src/Auth/OAuth/LinkedIn.php b/src/Auth/OAuth/LinkedIn.php index 638071efcf..101e1f09c5 100644 --- a/src/Auth/OAuth/LinkedIn.php +++ b/src/Auth/OAuth/LinkedIn.php @@ -61,7 +61,10 @@ class LinkedIn extends OAuth */ public function getAccessToken(string $code):string { - $accessToken = $this->request('POST', 'https://www.linkedin.com/oauth/v2/accessToken', ['Content-Type: application/x-www-form-urlencoded'], + $accessToken = $this->request( + 'POST', + 'https://www.linkedin.com/oauth/v2/accessToken', + ['Content-Type: application/x-www-form-urlencoded'], http_build_query([ 'grant_type' => 'authorization_code', 'code' => $code, diff --git a/src/Database/Adapter/MySQL.php b/src/Database/Adapter/MySQL.php index c0aeccb9ee..2d3006aa17 100644 --- a/src/Database/Adapter/MySQL.php +++ b/src/Database/Adapter/MySQL.php @@ -189,11 +189,11 @@ class MySQL extends Adapter $data['$uid'] = $this->getUid(); } - $st1->bindValue(':uid', $data['$uid'], PDO::PARAM_STR); - $st1->bindValue(':revision', $revision, PDO::PARAM_STR); - $st1->bindValue(':signature', $signature, PDO::PARAM_STR); - $st1->bindValue(':createdAt', date('Y-m-d H:i:s', time()), PDO::PARAM_STR); - $st1->bindValue(':updatedAt', date('Y-m-d H:i:s', time()), PDO::PARAM_STR); + $st1->bindValue(':uid', $data['$uid'], PDO::PARAM_STR); + $st1->bindValue(':revision', $revision, PDO::PARAM_STR); + $st1->bindValue(':signature', $signature, PDO::PARAM_STR); + $st1->bindValue(':createdAt', date('Y-m-d H:i:s', time()), PDO::PARAM_STR); + $st1->bindValue(':updatedAt', date('Y-m-d H:i:s', time()), PDO::PARAM_STR); $st1->bindValue(':permissions', json_encode($data['$permissions']), PDO::PARAM_STR); $st1->execute(); @@ -274,14 +274,14 @@ class MySQL extends Adapter if (is_array($prop['value'])) { throw new Exception('Value can\'t be an array: '.json_encode($prop['value'])); } - $st2->bindValue(':documentUid', $data['$uid'], PDO::PARAM_STR); - $st2->bindValue(':documentRevision', $revision, PDO::PARAM_STR); + $st2->bindValue(':documentUid', $data['$uid'], PDO::PARAM_STR); + $st2->bindValue(':documentRevision', $revision, PDO::PARAM_STR); - $st2->bindValue(':key', $prop['key'], PDO::PARAM_STR); - $st2->bindValue(':value', $prop['value'], PDO::PARAM_STR); - $st2->bindValue(':primitive', $prop['type'], PDO::PARAM_STR); - $st2->bindValue(':array', $prop['array'], PDO::PARAM_BOOL); - $st2->bindValue(':order', $prop['order'], PDO::PARAM_STR); + $st2->bindValue(':key', $prop['key'], PDO::PARAM_STR); + $st2->bindValue(':value', $prop['value'], PDO::PARAM_STR); + $st2->bindValue(':primitive', $prop['type'], PDO::PARAM_STR); + $st2->bindValue(':array', $prop['array'], PDO::PARAM_BOOL); + $st2->bindValue(':order', $prop['order'], PDO::PARAM_STR); $st2->execute(); } @@ -367,12 +367,12 @@ class MySQL extends Adapter (`revision`, `start`, `end`, `key`, `array`, `order`) VALUES (:revision, :start, :end, :key, :array, :order)'); - $st2->bindValue(':revision', $revision, PDO::PARAM_STR); - $st2->bindValue(':start', $start, PDO::PARAM_STR); - $st2->bindValue(':end', $end, PDO::PARAM_STR); - $st2->bindValue(':key', $key, PDO::PARAM_STR); - $st2->bindValue(':array', $isArray, PDO::PARAM_INT); - $st2->bindValue(':order', $order, PDO::PARAM_INT); + $st2->bindValue(':revision', $revision, PDO::PARAM_STR); + $st2->bindValue(':start', $start, PDO::PARAM_STR); + $st2->bindValue(':end', $end, PDO::PARAM_STR); + $st2->bindValue(':key', $key, PDO::PARAM_STR); + $st2->bindValue(':array', $isArray, PDO::PARAM_INT); + $st2->bindValue(':order', $order, PDO::PARAM_INT); $st2->execute(); diff --git a/src/Database/Validator/Collection.php b/src/Database/Validator/Collection.php index 6b9fa7f6c8..2d58da7bb1 100644 --- a/src/Database/Validator/Collection.php +++ b/src/Database/Validator/Collection.php @@ -38,7 +38,8 @@ class Collection extends Structure public function isValid($document) { $document = new Document( - array_merge($this->merge, ($document instanceof Document) ? $document->getArrayCopy() : $document)); + array_merge($this->merge, ($document instanceof Document) ? $document->getArrayCopy() : $document) + ); if (is_null($document->getCollection())) { $this->message = 'Missing collection attribute $collection'; diff --git a/src/Database/Validator/Structure.php b/src/Database/Validator/Structure.php index 3f60d812be..c2753d2769 100644 --- a/src/Database/Validator/Structure.php +++ b/src/Database/Validator/Structure.php @@ -187,8 +187,12 @@ class Structure extends Validator if (empty($validator)) { // Error creating validator for property $this->message = 'Unknown rule type "' . $ruleType . '" for property "' . htmlspecialchars($key, ENT_QUOTES, 'UTF-8') . '"'; - // $this->message = 'Unknown property "'.$key.'" type'. - // '. Make sure to follow '.strtolower($collection->getAttribute('name', 'unknown')).' collection structure'; + + if (empty($ruleType)) { + $this->message = 'Unknown property "'.$key.'" type'. + '. Make sure to follow '.strtolower($collection->getAttribute('name', 'unknown')).' collection structure'; + } + return false; } diff --git a/src/OpenSSL/OpenSSL.php b/src/OpenSSL/OpenSSL.php index 73e1d44271..3dd2dabf37 100644 --- a/src/OpenSSL/OpenSSL.php +++ b/src/OpenSSL/OpenSSL.php @@ -34,9 +34,9 @@ class OpenSSL * * @return string */ - public static function decrypt($data, $method, $password, $options = 1, $iv = '', $tag = '', $aad = '') + public static function decrypt($data, $method, $password, $options = 1, $iv = '', $tag = '', $aad = '') { - return openssl_decrypt($data, $method, $password, $options, $iv, $tag, $aad); + return openssl_decrypt($data, $method, $password, $options, $iv, $tag, $aad); } /** diff --git a/tests/e2e/BaseConsole.php b/tests/e2e/BaseConsole.php index 14787e510b..96fa9d274c 100644 --- a/tests/e2e/BaseConsole.php +++ b/tests/e2e/BaseConsole.php @@ -23,8 +23,8 @@ class BaseConsole extends TestCase ->setEndpoint($this->endpoint) ; - $this->demoEmail = 'user.' . rand(0,1000000) . '@appwrite.io'; - $this->demoPassword = 'password.' . rand(0,1000000); + $this->demoEmail = 'user.' . rand(0, 1000000) . '@appwrite.io'; + $this->demoPassword = 'password.' . rand(0, 1000000); } public function tearDown() @@ -32,14 +32,15 @@ class BaseConsole extends TestCase $this->client = null; } - public function register() { + public function register() + { $response = $this->client->call(Client::METHOD_POST, '/auth/register', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', ], [ 'email' => $this->demoEmail, 'password' => $this->demoPassword, - 'confirmation' => 'http://localhost/confirm', + 'confirm' => 'http://localhost/confirm', 'success' => 'http://localhost/success', 'failure' => 'http://localhost/failure', 'name' => 'Demo User', @@ -47,4 +48,4 @@ class BaseConsole extends TestCase return $response; } -} \ No newline at end of file +} diff --git a/tests/e2e/BaseProjects.php b/tests/e2e/BaseProjects.php index bb65122313..63bd528a54 100644 --- a/tests/e2e/BaseProjects.php +++ b/tests/e2e/BaseProjects.php @@ -16,8 +16,8 @@ class BaseProjects extends BaseConsole { parent::setUp(); - $this->projectsDemoEmail = 'user.' . rand(0,1000000) . '@appwrite.io'; - $this->projectsDemoPassword = 'password.' . rand(0,1000000); + $this->projectsDemoEmail = 'user.' . rand(0, 1000000) . '@appwrite.io'; + $this->projectsDemoPassword = 'password.' . rand(0, 1000000); } public function tearDown() @@ -36,7 +36,7 @@ class BaseProjects extends BaseConsole ], [ 'email' => $this->projectsDemoEmail, 'password' => $this->projectsDemoPassword, - 'confirmation' => 'http://localhost/confirm', + 'confirm' => 'http://localhost/confirm', 'success' => 'http://localhost/success', 'failure' => 'http://localhost/failure', 'name' => 'Porject Demo User', @@ -44,4 +44,4 @@ class BaseProjects extends BaseConsole return $response; } -} \ No newline at end of file +} diff --git a/tests/e2e/Client.php b/tests/e2e/Client.php index 5fd7c90a45..9508f2cfd4 100644 --- a/tests/e2e/Client.php +++ b/tests/e2e/Client.php @@ -185,7 +185,7 @@ class Client curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, php_uname('s') . '-' . php_uname('r') . ':php-' . phpversion()); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use (&$responseHeaders) { + curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) { $len = strlen($header); $header = explode(':', $header, 2); @@ -198,12 +198,12 @@ class Client return $len; }); - if($method != self::METHOD_GET) { + if ($method != self::METHOD_GET) { curl_setopt($ch, CURLOPT_POSTFIELDS, $query); } // Allow self signed certificates - if($this->selfSigned) { + if ($this->selfSigned) { curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } @@ -212,7 +212,7 @@ class Client $responseType = (isset($responseHeaders['content-type'])) ? $responseHeaders['content-type'] : ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); - switch(substr($responseType, 0, strpos($responseType, ';'))) { + switch (substr($responseType, 0, strpos($responseType, ';'))) { case 'application/json': $responseBody = json_decode($responseBody, true); break; @@ -254,16 +254,16 @@ class Client * @param string $prefix * @return array */ - protected function flatten(array $data, $prefix = '') { + protected function flatten(array $data, $prefix = '') + { $output = []; - foreach($data as $key => $value) { + foreach ($data as $key => $value) { $finalKey = $prefix ? "{$prefix}[{$key}]" : $key; if (is_array($value)) { $output += $this->flatten($value, $finalKey); // @todo: handle name collision here if needed - } - else { + } else { $output[$finalKey] = $value; } } diff --git a/tests/e2e/ConsoleHealthTest.php b/tests/e2e/ConsoleHealthTest.php index 34b1b5d546..a795ab49e6 100644 --- a/tests/e2e/ConsoleHealthTest.php +++ b/tests/e2e/ConsoleHealthTest.php @@ -5,7 +5,7 @@ namespace Tests\E2E; use Tests\E2E\Client; class ConsoleHealthTest extends BaseConsole -{ +{ public function testHTTPSuccess() { $response = $this->client->call(Client::METHOD_GET, '/health', [ @@ -88,4 +88,4 @@ class ConsoleHealthTest extends BaseConsole $this->assertEquals('online', $response['body']['status']); $this->assertStringStartsWith('ClamAV ', $response['body']['version']); } -} \ No newline at end of file +} diff --git a/tests/e2e/ConsoleProjectsTest.php b/tests/e2e/ConsoleProjectsTest.php index 3cfc9a5d7b..e0bd1b39be 100644 --- a/tests/e2e/ConsoleProjectsTest.php +++ b/tests/e2e/ConsoleProjectsTest.php @@ -5,7 +5,7 @@ namespace Tests\E2E; use Tests\E2E\Client; class ConsoleProjectsTest extends BaseConsole -{ +{ public function testRegisterSuccess() { $response = $this->register(); @@ -25,7 +25,8 @@ class ConsoleProjectsTest extends BaseConsole /** * @depends testRegisterSuccess */ - public function testProjectsList($data) { + public function testProjectsList($data) + { $response = $this->client->call(Client::METHOD_GET, '/projects', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', @@ -39,7 +40,8 @@ class ConsoleProjectsTest extends BaseConsole /** * @depends testRegisterSuccess */ - public function testProjectsCreateSuccess($data) { + public function testProjectsCreateSuccess($data) + { $team = $this->client->call(Client::METHOD_POST, '/teams', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', @@ -81,8 +83,8 @@ class ConsoleProjectsTest extends BaseConsole /** * @depends testProjectsCreateSuccess */ - public function testProjectsUpdateSuccess($data) { - + public function testProjectsUpdateSuccess($data) + { $response = $this->client->call(Client::METHOD_POST, '/projects', [ 'origin' => 'http://localhost', 'content-type' => 'application/json', @@ -100,4 +102,4 @@ class ConsoleProjectsTest extends BaseConsole $this->assertEquals('New Demo Project Description', $response['body']['description']); $this->assertEquals('https://appwrite.io/new', $response['body']['url']); } -} \ No newline at end of file +} diff --git a/tests/e2e/ConsoleTest.php b/tests/e2e/ConsoleTest.php index 469e9f14b4..624b15dd75 100644 --- a/tests/e2e/ConsoleTest.php +++ b/tests/e2e/ConsoleTest.php @@ -10,6 +10,8 @@ class ConsoleTest extends BaseConsole { $response = $this->register(); + var_dump($_SERVER); + $this->assertEquals('http://localhost/success', $response['headers']['location']); $this->assertEquals("\n", $response['body']); @@ -93,4 +95,4 @@ class ConsoleTest extends BaseConsole $this->assertEquals('401', $response['body']['code']); } -} \ No newline at end of file +} diff --git a/tests/e2e/ProjectDatabaseTest.php b/tests/e2e/ProjectDatabaseTest.php index 24282ae19c..e253e89d53 100644 --- a/tests/e2e/ProjectDatabaseTest.php +++ b/tests/e2e/ProjectDatabaseTest.php @@ -79,8 +79,8 @@ class ProjectDatabaseTest extends BaseProjects /** * @depends testRegisterSuccess */ - public function testCollectionCreateSuccess($data) { - + public function testCollectionCreateSuccess($data) + { $actors = $this->client->call(Client::METHOD_POST, '/database', [ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectUid'], @@ -170,7 +170,8 @@ class ProjectDatabaseTest extends BaseProjects /** * @depends testCollectionCreateSuccess */ - public function testDocumentCreateSuccess($data) { + public function testDocumentCreateSuccess($data) + { $document1 = $this->client->call(Client::METHOD_POST, '/database/' . $data['moviesId'] . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectUid'], @@ -313,7 +314,8 @@ class ProjectDatabaseTest extends BaseProjects /** * @depends testDocumentCreateSuccess */ - public function testDocumentsListSuccessOrderAndCasting($data) { + public function testDocumentsListSuccessOrderAndCasting($data) + { $documents = $this->client->call(Client::METHOD_GET, '/database/' . $data['moviesId'] . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectUid'], @@ -348,7 +350,8 @@ class ProjectDatabaseTest extends BaseProjects /** * @depends testDocumentCreateSuccess */ - public function testDocumentsListSuccessLimitAndOffset($data) { + public function testDocumentsListSuccessLimitAndOffset($data) + { $documents = $this->client->call(Client::METHOD_GET, '/database/' . $data['moviesId'] . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectUid'], @@ -383,7 +386,8 @@ class ProjectDatabaseTest extends BaseProjects /** * @depends testDocumentCreateSuccess */ - public function testDocumentsListSuccessFirstAndLast($data) { + public function testDocumentsListSuccessFirstAndLast($data) + { $documents = $this->client->call(Client::METHOD_GET, '/database/' . $data['moviesId'] . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectUid'], @@ -417,7 +421,8 @@ class ProjectDatabaseTest extends BaseProjects /** * @depends testDocumentCreateSuccess */ - public function testDocumentsListSuccessSerach($data) { + public function testDocumentsListSuccessSerach($data) + { $documents = $this->client->call(Client::METHOD_GET, '/database/' . $data['moviesId'] . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectUid'], @@ -456,7 +461,8 @@ class ProjectDatabaseTest extends BaseProjects /** * @depends testDocumentCreateSuccess */ - public function testDocumentsListSuccessFilters($data) { + public function testDocumentsListSuccessFilters($data) + { $documents = $this->client->call(Client::METHOD_GET, '/database/' . $data['moviesId'] . '/documents', [ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectUid'], @@ -498,4 +504,4 @@ class ProjectDatabaseTest extends BaseProjects $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['name']); $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['name']); } -} \ No newline at end of file +}