diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index beaa176249..21d9c6df3a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -346,8 +346,7 @@ If you are in PHP Storm you don't need any plugin. Below are the settings requir 1. Create an init file. 2. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php**. -3. Change the IP address to your development machine's IP. Without the proper IP address, the debugger won't connect. -4. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file. +3. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file. ### VS Code Launch Configuration diff --git a/Dockerfile b/Dockerfile index 392f4de5bf..050ccab3cd 100755 --- a/Dockerfile +++ b/Dockerfile @@ -182,7 +182,7 @@ RUN chmod +x /usr/local/bin/doctor && \ RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/ # Enable Extensions -RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/local/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi +RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/src/code/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi RUN if [ "$DEBUG" == "true" ]; then echo "opcache.enable=0" >> /usr/local/etc/php/conf.d/appwrite.ini; fi RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini diff --git a/README-CN.md b/README-CN.md index 6de3770f20..d1243da985 100644 --- a/README-CN.md +++ b/README-CN.md @@ -12,7 +12,7 @@

- +[![We're Hiring](https://img.shields.io/static/v1?label=We're&message=Hiring&color=blue&style=flat-square)](https://appwrite.io/company/careers) [![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=friendly&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github) [![Build Status](https://img.shields.io/github/actions/workflow/status/appwrite/appwrite/tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions) diff --git a/README.md b/README.md index fbf577f100..d39bf510d1 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ +[![We're Hiring](https://img.shields.io/static/v1?label=We're&message=Hiring&color=blue&style=flat-square)](https://appwrite.io/company/careers) [![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=ready&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github) [![Build Status](https://img.shields.io/github/actions/workflow/status/appwrite/appwrite/tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions) diff --git a/app/config/errors.php b/app/config/errors.php index 266e017e93..0c1524772d 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -549,6 +549,11 @@ return [ 'description' => 'Domain verification for the requested domain has failed.', 'code' => 401, ], + Exception::DOMAIN_TARGET_INVALID => [ + 'name' => Exception::DOMAIN_TARGET_INVALID, + 'description' => 'Your Appwrite instance is not publicly accessible. Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.', + 'code' => 501, + ], Exception::GRAPHQL_NO_QUERY => [ 'name' => Exception::GRAPHQL_NO_QUERY, 'description' => 'Param "query" is not optional.', diff --git a/app/config/services.php b/app/config/services.php index e0d5e263f2..f7fe5fe8d1 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -186,4 +186,17 @@ return [ 'optional' => true, 'icon' => '/images/services/graphql.png', ], + 'console' => [ + 'key' => 'console', + 'name' => 'Console', + 'subtitle' => 'The Console service allows you to interact with console relevant informations.', + 'description' => '', + 'controller' => 'api/console.php', + 'sdk' => true, + 'docs' => true, + 'docsUrl' => '', + 'tests' => false, + 'optional' => false, + 'icon' => '', + ], ]; diff --git a/app/controllers/api/console.php b/app/controllers/api/console.php new file mode 100644 index 0000000000..060fa10cb5 --- /dev/null +++ b/app/controllers/api/console.php @@ -0,0 +1,40 @@ +groups(['console']) + ->inject('project') + ->action(function (Document $project) { + if ($project->getId() !== 'console') { + throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN); + } + }); + + +App::get('/v1/console/variables') + ->desc('Get Variables') + ->groups(['api', 'projects']) + ->label('scope', 'projects.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'console') + ->label('sdk.method', 'variables') + ->label('sdk.description', '/docs/references/console/variables.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES) + ->inject('response') + ->action(function (Response $response) { + + $variables = new Document([ + '_APP_DOMAIN_TARGET' => App::getEnv('_APP_DOMAIN_TARGET'), + '_APP_STORAGE_LIMIT' => +App::getEnv('_APP_STORAGE_LIMIT'), + '_APP_FUNCTIONS_SIZE_LIMIT' => +App::getEnv('_APP_FUNCTIONS_SIZE_LIMIT'), + '_APP_USAGE_STATS' => App::getEnv('_APP_USAGE_STATS'), + ]); + + $response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES); + }); diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 29a193748d..deff177ab2 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1340,7 +1340,7 @@ App::post('/v1/projects/:projectId/domains') $target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', '')); if (!$target->isKnown() || $target->isTest()) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.'); + throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.'); } $domain = new Domain($domain); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 271f2af6b3..9396d9f29b 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -348,7 +348,7 @@ App::post('/v1/storage/buckets/:bucketId/files') ->label('sdk.response.model', Response::MODEL_FILE) ->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).') ->param('fileId', '', new CustomId(), 'File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('file', [], new File(), 'Binary file.', false) + ->param('file', [], new File(), 'Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](/docs/storage#file-input).', false) ->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](/docs/permissions).', true) ->inject('request') ->inject('response') diff --git a/app/workers/certificates.php b/app/workers/certificates.php index 33752215b8..03dfe0231c 100644 --- a/app/workers/certificates.php +++ b/app/workers/certificates.php @@ -383,7 +383,7 @@ class CertificatesV1 extends Worker $locale->setDefault('en'); } - $body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl'); + $body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl'); $subject = \sprintf($locale->getText("emails.certificate.subject"), $domain); $body->setParam('{{domain}}', $domain); diff --git a/composer.lock b/composer.lock index 985a33a518..b39d09f277 100644 --- a/composer.lock +++ b/composer.lock @@ -3128,6 +3128,49 @@ }, "time": "2022-05-02T15:47:09+00:00" }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" + }, { "name": "doctrine/instantiator", "version": "1.5.0", diff --git a/dev/yasd_init.php.stub b/dev/yasd_init.php.stub index a7d977fbf7..efcc37c0b5 100644 --- a/dev/yasd_init.php.stub +++ b/dev/yasd_init.php.stub @@ -1,4 +1,4 @@ ./tests/e2e/General ./tests/e2e/Scopes ./tests/e2e/Services/Account + ./tests/e2e/Services/Console ./tests/e2e/Services/Realtime ./tests/e2e/Services/Avatars ./tests/e2e/Services/Databases diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 8b240aa971..9e2e8f9cb1 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -177,6 +177,7 @@ class Exception extends \Exception public const DOMAIN_NOT_FOUND = 'domain_not_found'; public const DOMAIN_ALREADY_EXISTS = 'domain_already_exists'; public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed'; + public const DOMAIN_TARGET_INVALID = 'domain_target_invalid'; /** GraphqQL */ public const GRAPHQL_NO_QUERY = 'graphql_no_query'; diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 2ab514f91c..1f69dbb772 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -44,6 +44,7 @@ use Appwrite\Utopia\Response\Model\Execution; use Appwrite\Utopia\Response\Model\Build; use Appwrite\Utopia\Response\Model\File; use Appwrite\Utopia\Response\Model\Bucket; +use Appwrite\Utopia\Response\Model\ConsoleVariables; use Appwrite\Utopia\Response\Model\Func; use Appwrite\Utopia\Response\Model\Index; use Appwrite\Utopia\Response\Model\JWT; @@ -213,6 +214,9 @@ class Response extends SwooleResponse public const MODEL_HEALTH_TIME = 'healthTime'; public const MODEL_HEALTH_ANTIVIRUS = 'healthAntivirus'; + // Console + public const MODEL_CONSOLE_VARIABLES = 'consoleVariables'; + // Deprecated public const MODEL_PERMISSIONS = 'permissions'; public const MODEL_RULE = 'rule'; @@ -341,6 +345,7 @@ class Response extends SwooleResponse ->setModel(new UsageFunctions()) ->setModel(new UsageFunction()) ->setModel(new UsageProject()) + ->setModel(new ConsoleVariables()) // Verification // Recovery // Tests (keep last) diff --git a/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php b/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php new file mode 100644 index 0000000000..e52638f82a --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php @@ -0,0 +1,58 @@ +addRule('_APP_DOMAIN_TARGET', [ + 'type' => self::TYPE_STRING, + 'description' => 'CNAME target for your Appwrite custom domains.', + 'default' => '', + 'example' => 'appwrite.io', + ]) + ->addRule('_APP_STORAGE_LIMIT', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Maximum file size allowed for file upload in bytes.', + 'default' => '', + 'example' => '30000000', + ]) + ->addRule('_APP_FUNCTIONS_SIZE_LIMIT', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Maximum file size allowed for deployment in bytes.', + 'default' => '', + 'example' => '30000000', + ]) + ->addRule('_APP_USAGE_STATS', [ + 'type' => self::TYPE_STRING, + 'description' => 'Defines if usage stats are enabled. This value is set to \'enabled\' by default, to disable the usage stats set the value to \'disabled\'.', + 'default' => '', + 'example' => 'enabled', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Console Variables'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_CONSOLE_VARIABLES; + } +} diff --git a/tests/e2e/Services/Console/ConsoleBase.php b/tests/e2e/Services/Console/ConsoleBase.php new file mode 100644 index 0000000000..e7d2eabd01 --- /dev/null +++ b/tests/e2e/Services/Console/ConsoleBase.php @@ -0,0 +1,7 @@ +client->call(Client::METHOD_GET, '/console/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(4, $response['body']); + $this->assertIsString($response['body']['_APP_DOMAIN_TARGET']); + $this->assertIsInt($response['body']['_APP_STORAGE_LIMIT']); + $this->assertIsInt($response['body']['_APP_FUNCTIONS_SIZE_LIMIT']); + $this->assertIsString($response['body']['_APP_DOMAIN_TARGET']); + } +} diff --git a/tests/e2e/Services/Console/ConsoleCustomClientTest.php b/tests/e2e/Services/Console/ConsoleCustomClientTest.php new file mode 100644 index 0000000000..4b78b7f43c --- /dev/null +++ b/tests/e2e/Services/Console/ConsoleCustomClientTest.php @@ -0,0 +1,27 @@ +client->call(Client::METHOD_GET, '/console/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(401, $response['headers']['status-code']); + } +} diff --git a/tests/e2e/Services/Console/ConsoleCustomServerTest.php b/tests/e2e/Services/Console/ConsoleCustomServerTest.php new file mode 100644 index 0000000000..3748bbe546 --- /dev/null +++ b/tests/e2e/Services/Console/ConsoleCustomServerTest.php @@ -0,0 +1,27 @@ +client->call(Client::METHOD_GET, '/console/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(401, $response['headers']['status-code']); + } +}