diff --git a/CHANGES.md b/CHANGES.md index 4c38927b9..464780732 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,11 +2,11 @@ - Anonymous login -# Version 0.7.1 (Not Released Yet) +# Version 0.7.1 ## Features -- Better error logs on appwrite cretificates worker +- Better error logs on appwrite certificates worker - Added option for Redis authentication - Force adding a security email on setup - SMTP is now disabled by default, no dummy SMTP is included in setup @@ -27,7 +27,10 @@ ## Bug Fixes - Updated missing storage env vars +- Fixed a bug, that added a wrong timzone offset to user log timestamps - Fixed a bug, that Response format header was not added in the access-control-allow-header list. +- Fixed a bug where countryName is unknown on sessions (#933) +- Added missing event users.update.prefs (#952) ## Security diff --git a/README.md b/README.md index 950c5a301..3d4bd7573 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:0.7.0 + appwrite/appwrite:0.7.1 ``` ### Windows @@ -65,7 +65,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:0.7.0 + appwrite/appwrite:0.7.1 ``` #### PowerShell @@ -75,7 +75,7 @@ docker run -it --rm , --volume /var/run/docker.sock:/var/run/docker.sock , --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw , --entrypoint="install" , - appwrite/appwrite:0.7.0 + appwrite/appwrite:0.7.1 ``` Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please note that on non-linux native hosts, the server might take a few minutes to start after installation completes. diff --git a/app/config/events.php b/app/config/events.php index 2bb3862fd..601b50216 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -117,6 +117,11 @@ return [ 'model' => Response::MODEL_USER, 'note' => 'version >= 0.7', ], + 'users.update.prefs' => [ + 'description' => 'This event triggers when a user preference is updated from the users API.', + 'model' => Response::MODEL_ANY, + 'note' => 'version >= 0.7', + ], 'users.update.status' => [ 'description' => 'This event triggers when a user status is updated from the users API.', 'model' => Response::MODEL_USER, diff --git a/app/config/variables.php b/app/config/variables.php index 14b29bc45..369a860fe 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -107,8 +107,8 @@ return [ 'name' => '_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', 'description' => 'This is the email address used to issue SSL certificates for custom domains or the user agent in your webhooks payload.', 'introduction' => '0.7.0', - 'default' => '', - 'required' => true, + 'default' => 'certs@appwrite.io', + 'required' => false, 'question' => '', ], [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index e8ae76312..cab25eb74 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -236,9 +236,11 @@ App::post('/v1/account/sessions') ->setStatusCode(Response::STATUS_CODE_CREATED) ; + $countries = $locale->getText('countries'); + $session ->setAttribute('current', true) - ->setAttribute('countryName', (isset($countries[$session->getAttribute('countryCode')])) ? $countries[$session->getAttribute('countryCode')] : $locale->getText('locale.country.unknown')) + ->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))])) ? $countries[strtoupper($session->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown')) ; $response->dynamic($session, Response::MODEL_SESSION); @@ -679,8 +681,8 @@ App::get('/v1/account/sessions') continue; } - $token->setAttribute('countryName', (isset($countries[$token->getAttribute('contryCode')])) - ? $countries[$token->getAttribute('contryCode')] + $token->setAttribute('countryName', (isset($countries[strtoupper($token->getAttribute('countryCode'))])) + ? $countries[strtoupper($token->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown')); $token->setAttribute('current', ($current == $token->getId()) ? true : false); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index efb0041ce..958dfc148 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -205,8 +205,8 @@ App::get('/v1/users/:userId/sessions') continue; } - $token->setAttribute('countryName', (isset($countries[$token->getAttribute('contryCode')])) - ? $countries[$token->getAttribute('contryCode')] + $token->setAttribute('countryName', (isset($countries[strtoupper($token->getAttribute('countryCode'))])) + ? $countries[strtoupper($token->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown')); $token->setAttribute('current', false); @@ -373,6 +373,7 @@ App::patch('/v1/users/:userId/status') App::patch('/v1/users/:userId/prefs') ->desc('Update User Preferences') ->groups(['api', 'users']) + ->label('event', 'users.update.prefs') ->label('scope', 'users.write') ->label('sdk.platform', [APP_PLATFORM_SERVER]) ->label('sdk.namespace', 'users') diff --git a/app/http.php b/app/http.php index 9e45bc3b5..d144c2e54 100644 --- a/app/http.php +++ b/app/http.php @@ -94,7 +94,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo return; } - $app = new App('America/New_York'); + $app = new App('UTC'); try { Authorization::cleanRoles(); diff --git a/app/init.php b/app/init.php index a70ed1b88..effa61ad5 100644 --- a/app/init.php +++ b/app/init.php @@ -40,7 +40,7 @@ const APP_MODE_DEFAULT = 'default'; const APP_MODE_ADMIN = 'admin'; const APP_PAGING_LIMIT = 12; const APP_CACHE_BUSTER = 144; -const APP_VERSION_STABLE = '0.7.0'; +const APP_VERSION_STABLE = '0.7.1'; const APP_STORAGE_UPLOADS = '/storage/uploads'; const APP_STORAGE_FUNCTIONS = '/storage/functions'; const APP_STORAGE_CACHE = '/storage/cache'; diff --git a/app/preload.php b/app/preload.php index f73aaea61..7c8ae0093 100644 --- a/app/preload.php +++ b/app/preload.php @@ -28,10 +28,9 @@ foreach ([ realpath(__DIR__ . '/../vendor/felixfbecker'), realpath(__DIR__ . '/../vendor/twig/twig'), realpath(__DIR__ . '/../vendor/guzzlehttp/guzzle'), - realpath(__DIR__ . '/../vendor/domnikl'), - realpath(__DIR__ . '/../vendor/domnikl'), + realpath(__DIR__ . '/../vendor/slickdeals'), realpath(__DIR__ . '/../vendor/psr/log'), - realpath(__DIR__ . '/../vendor/piwik'), + realpath(__DIR__ . '/../vendor/matomo'), realpath(__DIR__ . '/../vendor/symfony'), ] as $key => $value) { if($value !== false) { diff --git a/app/tasks/sdks.php b/app/tasks/sdks.php index be99b7d15..40797a20b 100644 --- a/app/tasks/sdks.php +++ b/app/tasks/sdks.php @@ -99,7 +99,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND $config->setComposerVendor('appwrite'); $config->setComposerPackage('cli'); $config->setExecutableName('appwrite'); - $config->setExecutableName('appwrite'); $config->setLogo(" _ _ _ ___ __ _____ /_\ _ __ _ ____ ___ __(_) |_ ___ / __\ / / \_ \ diff --git a/composer.json b/composer.json index 39e8a0416..d4135536d 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,7 @@ "slickdeals/statsd": "~3.0" }, "require-dev": { - "appwrite/sdk-generator": "dev-master", + "appwrite/sdk-generator": "0.6.3", "phpunit/phpunit": "9.4.2", "swoole/ide-helper": "4.5.5", "vimeo/psalm": "4.1.1" diff --git a/docs/sdks/dart/GETTING_STARTED.md b/docs/sdks/dart/GETTING_STARTED.md new file mode 100644 index 000000000..7a5e8340d --- /dev/null +++ b/docs/sdks/dart/GETTING_STARTED.md @@ -0,0 +1,31 @@ +## Getting Started + +### Initialize & Make API Request +Once you add the dependencies, its extremely easy to get started with the SDK; All you need to do is import the package in your code, set your Appwrite credentials, and start making API calls. Below is a simple example: + +```dart +import 'package:dart_appwrite/dart_appwrite.dart'; + +void main() async { + Client client = Client(); + .setEndpoint('http://[HOSTNAME_OR_IP]/v1') // Make sure your endpoint is accessible + .setProject('5ff3379a01d25') // Your project ID + .setKey('cd868c7af8bdc893b4...93b7535db89') + + Users users = Users(client); + + try { + final response = await users.create(email: ‘email@example.com’,password: ‘password’, name: ‘name’); + print(response.data); + } on AppwriteException catch(e) { + print(e.message); + } +} +``` + +### Learn more +You can use followng resources to learn more and get help +- 🚀 [Getting Started Tutorial](https://appwrite.io/docs/getting-started-for-server) +- 📜 [Appwrite Docs](https://appwrite.io/docs) +- 💬 [Discord Community](https://appwrite.io/discord) +- 🚂 [Appwrite Dart Playground](https://github.com/appwrite/playground-for-dart) diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index e1059f6af..0596aee09 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -117,6 +117,7 @@ trait ProjectCustom 'storage.files.update', 'storage.files.delete', 'users.create', + 'users.update.prefs', 'users.update.status', 'users.delete', 'users.sessions.delete', diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 360dee2cb..d2d554913 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -186,10 +186,43 @@ class WebhooksCustomServerTest extends Scope */ return ['userId' => $user['body']['$id'], 'name' => $user['body']['name'], 'email' => $user['body']['email']]; } - - /** + + /** * @depends testCreateUser */ + public function testUpdateUserPrefs(array $data):array + { + /** + * Test for SUCCESS + */ + $user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/prefs', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'prefs' => ['a' => 'b'] + ]); + + $this->assertEquals($user['headers']['status-code'], 200); + $this->assertEquals($user['body']['a'], 'b'); + + $webhook = $this->getLastRequest(); + + $this->assertEquals($webhook['method'], 'POST'); + $this->assertEquals($webhook['headers']['Content-Type'], 'application/json'); + $this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io'); + $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Event'], 'users.update.prefs'); + $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented'); + $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); + $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); + $this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide())); + $this->assertEquals($webhook['data']['a'], 'b'); + + return $data; + } + + /** + * @depends testUpdateUserPrefs + */ public function testUpdateUserStatus(array $data):array { /** @@ -221,7 +254,7 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['data']['status'], 2); $this->assertEquals($webhook['data']['email'], $data['email']); $this->assertEquals($webhook['data']['emailVerification'], false); - $this->assertEquals($webhook['data']['prefs'], []); + $this->assertEquals($webhook['data']['prefs']['a'], 'b'); return $data; } @@ -257,8 +290,8 @@ class WebhooksCustomServerTest extends Scope $this->assertEquals($webhook['data']['status'], 2); $this->assertEquals($webhook['data']['email'], $data['email']); $this->assertEquals($webhook['data']['emailVerification'], false); - $this->assertEquals($webhook['data']['prefs'], []); + $this->assertEquals($webhook['data']['prefs']['a'], 'b'); return $data; } -} \ No newline at end of file +}