1
0
Fork 0
mirror of synced 2024-06-03 11:24:48 +12:00

Merge remote-tracking branch 'origin/0.16.x' into fix-datetime-attr-ui

This commit is contained in:
Matej Bačo 2022-09-11 07:34:44 +00:00
commit 8b864324de
53 changed files with 585 additions and 302 deletions

View file

@ -2,33 +2,19 @@ name: "Linter"
on: [pull_request]
jobs:
tests:
lint:
name: Linter
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
- name: Install dependencies
uses: php-actions/composer@v6
with:
php_version: '8.0'
args: --profile --ignore-platform-reqs
- name: Run Linter
run: ./vendor/bin/phpcs -p
run: |
docker run --rm -v $PWD:/app composer sh -c \
"composer install --profile --ignore-platform-reqs && composer lint"

View file

@ -1,3 +1,36 @@
# Version 1.0.0-RC1
# DO NOT INSTALL THIS VERSION ON ANY EXISTING INSTANCES OF APPWRITE, THIS IS A TEST RELEASE AND DOES NOT HAVE BACKWARDS COMPATIBILITY!!
## BREAKING CHANGES
- All Date values are now stored as ISO-8601 instead of UNIX timestamps [#3516](https://github.com/appwrite/appwrite/pull/3516)
- Permission levels and syntax have been reworked. See the Permissions V2 section in the document for more information [#3700](https://github.com/appwrite/appwrite/pull/3700)
- Function Variables are now stored in a seperate collection with their own API endpoints [#3634](https://github.com/appwrite/appwrite/pull/3634)
- Resources that are computed asynchronously, such as function deployments, will now return a `202 Accepted` status code instead of `200 OK` [#3547](https://github.com/appwrite/appwrite/pull/3547)
- Queries have been improved to allow even more flexibility, and introduced to new endpoints. See the Queries V2 section in the document for more information [#3702](https://github.com/appwrite/appwrite/pull/3702)
- Compound indexes are now more flexible [#151](https://github.com/utopia-php/database/pull/151)
- `createExecution` parameter `async` default value was changed from `true` to `false` [#3781](https://github.com/appwrite/appwrite/pull/3781)
## Features
- Added the UI to see the Parent ID of all resources within the UI. [#3653](https://github.com/appwrite/appwrite/pull/3653)
- Added automatic cache cleaning for internal Appwrite services [#3491](https://github.com/appwrite/appwrite/pull/3491)
- Added the ability for Appwrite to handle importing hashed passwords, this can be leveraged to import existing user data from other systems. More information can be found in the document linked above. [#2747](https://github.com/appwrite/appwrite/pull/2747)
- `Users` has now been renamed to `Authentication` within the Appwrite console [#3664](https://github.com/appwrite/appwrite/pull/3664)
- More endpoints were made public (for guests) with proper rate limits [#3741](https://github.com/appwrite/appwrite/pull/3741)
- Added Disqus, Podio, and Etsy OAuth providers [#3526](https://github.com/appwrite/appwrite/pull/3526), [#3488](https://github.com/appwrite/appwrite/pull/3488), [#3522](https://github.com/appwrite/appwrite/pull/3522)
- Function logs now capture stdout [#3656](https://github.com/appwrite/appwrite/pull/3656)
- Added the ability to grant guests write permissions for documents, files and executions [#3727](https://github.com/appwrite/appwrite/pull/3727)
## Bugs
- Fixed an issue where after resetting your password in the Appwrite console, you would not be redirected to the login page. [#3654](https://github.com/appwrite/appwrite/pull/3654)
- Fixed an issue where invalid data could be loaded into the Appwrite console. [#3660](https://github.com/appwrite/appwrite/pull/3660)
- Fixed an issue where users using the MySQL adapter for Appwrite would run into an issue with full text indexes [#154](https://github.com/utopia-php/database/pull/154)
- Fix teams being created with no owners [#3558](https://github.com/appwrite/appwrite/pull/3558)
- Fixed a bug where you could not search users by phone [#3619](https://github.com/appwrite/appwrite/pull/3619)
- Fixed a bug where unaccepted invitations would grant access to projects [#3738](https://github.com/appwrite/appwrite/pull/3738)
For more information on the changes, please see our [1.0-RC1 Documentation](https://warm-tray-285.notion.site/Appwrite-1-0-0-RC1-a5eab87e115d454db0259f707fc88535).
# Version 0.15.3
## Features
- Added hint during Installation for DNS Configuration by @PineappleIOnic in https://github.com/appwrite/appwrite/pull/2450

View file

@ -15,7 +15,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
'version' => '9.1.0-RC1',
'version' => '10.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@ -63,7 +63,7 @@ return [
[
'key' => 'flutter',
'name' => 'Flutter',
'version' => '8.0.0-dev.1',
'version' => '8.0.0-dev.2',
'url' => 'https://github.com/appwrite/sdk-for-flutter',
'package' => 'https://pub.dev/packages/appwrite',
'enabled' => true,
@ -81,7 +81,7 @@ return [
[
'key' => 'apple',
'name' => 'Apple',
'version' => '0.7.0-RC1',
'version' => '1.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-apple',
'package' => 'https://github.com/appwrite/sdk-for-apple',
'enabled' => true,
@ -116,7 +116,7 @@ return [
[
'key' => 'android',
'name' => 'Android',
'version' => '0.8.0-SNAPSHOT',
'version' => '1.0.0-SNAPSHOT',
'url' => 'https://github.com/appwrite/sdk-for-android',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
'enabled' => true,
@ -162,7 +162,7 @@ return [
[
'key' => 'web',
'name' => 'Console',
'version' => '6.1.0-RC1',
'version' => '7.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-console',
'package' => '',
'enabled' => true,
@ -180,7 +180,7 @@ return [
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '0.19.0-RC1',
'version' => '1.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
@ -208,7 +208,7 @@ return [
[
'key' => 'nodejs',
'name' => 'Node.js',
'version' => '7.1.0-RC1',
'version' => '8.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-node',
'package' => 'https://www.npmjs.com/package/node-appwrite',
'enabled' => true,
@ -226,7 +226,7 @@ return [
[
'key' => 'deno',
'name' => 'Deno',
'version' => '5.1.0-RC1',
'version' => '6.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-deno',
'package' => 'https://deno.land/x/appwrite',
'enabled' => true,
@ -244,7 +244,7 @@ return [
[
'key' => 'php',
'name' => 'PHP',
'version' => '6.1.0-RC1',
'version' => '7.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-php',
'package' => 'https://packagist.org/packages/appwrite/appwrite',
'enabled' => true,
@ -262,7 +262,7 @@ return [
[
'key' => 'python',
'name' => 'Python',
'version' => '0.11.0-RC1',
'version' => '1.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-python',
'package' => 'https://pypi.org/project/appwrite/',
'enabled' => true,
@ -280,7 +280,7 @@ return [
[
'key' => 'ruby',
'name' => 'Ruby',
'version' => '6.1.0-RC1',
'version' => '7.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-ruby',
'package' => 'https://rubygems.org/gems/appwrite',
'enabled' => true,
@ -298,7 +298,7 @@ return [
[
'key' => 'go',
'name' => 'Go',
'version' => '0.2.0-RC1',
'version' => '1.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-go',
'package' => '',
'enabled' => false,
@ -316,7 +316,7 @@ return [
[
'key' => 'java',
'name' => 'Java',
'version' => '0.0.3-SNAPSHOT',
'version' => '1.0.0-SNAPSHOT',
'url' => 'https://github.com/appwrite/sdk-for-java',
'package' => '',
'enabled' => false,
@ -334,7 +334,7 @@ return [
[
'key' => 'dotnet',
'name' => '.NET',
'version' => '0.5.0-RC1',
'version' => '1.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
'package' => 'https://www.nuget.org/packages/Appwrite',
'enabled' => false,
@ -352,7 +352,7 @@ return [
[
'key' => 'dart',
'name' => 'Dart',
'version' => '7.0.0-dev.1',
'version' => '7.0.0-dev.2',
'url' => 'https://github.com/appwrite/sdk-for-dart',
'package' => 'https://pub.dev/packages/dart_appwrite',
'enabled' => true,
@ -370,7 +370,7 @@ return [
[
'key' => 'kotlin',
'name' => 'Kotlin',
'version' => '0.7.0-SNAPSHOT',
'version' => '1.0.0-SNAPSHOT',
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
'enabled' => true,
@ -392,7 +392,7 @@ return [
[
'key' => 'swift',
'name' => 'Swift',
'version' => '0.7.0-RC1',
'version' => '1.0.0-RC2',
'url' => 'https://github.com/appwrite/sdk-for-swift',
'package' => 'https://github.com/appwrite/sdk-for-swift',
'enabled' => true,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -134,8 +134,9 @@ App::post('/v1/account')
$events->setParam('userId', $user->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_ACCOUNT);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_ACCOUNT);
});
App::post('/v1/account/sessions/email')
@ -1250,8 +1251,9 @@ App::post('/v1/account/jwt')
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic(new Document(['jwt' => $jwt->encode([
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic(new Document(['jwt' => $jwt->encode([
// 'uid' => 1,
// 'aud' => 'http://site.com',
// 'scopes' => ['user'],
@ -1979,8 +1981,9 @@ App::post('/v1/account/recovery')
// Hide secret for clients
$recovery->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $secret : '');
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($recovery, Response::MODEL_TOKEN);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($recovery, Response::MODEL_TOKEN);
});
App::put('/v1/account/recovery')
@ -2135,8 +2138,9 @@ App::post('/v1/account/verification')
// Hide secret for clients
$verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : '');
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($verification, Response::MODEL_TOKEN);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($verification, Response::MODEL_TOKEN);
});
App::put('/v1/account/verification')
@ -2276,8 +2280,9 @@ App::post('/v1/account/verification/phone')
// Hide secret for clients
$verification->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $verificationSecret : '');
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($verification, Response::MODEL_TOKEN);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($verification, Response::MODEL_TOKEN);
});
App::put('/v1/account/verification/phone')

View file

@ -354,27 +354,20 @@ App::get('/v1/avatars/initials')
->param('name', '', new Text(128), 'Full Name. When empty, current user name or email will be used. Max length: 128 chars.', true)
->param('width', 500, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 500, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('color', '', new HexColor(), 'Changes text color. By default a random color will be picked and stay will persistent to the given name.', true)
->param('background', '', new HexColor(), 'Changes background color. By default a random color will be picked and stay will persistent to the given name.', true)
->inject('response')
->inject('user')
->action(function (string $name, int $width, int $height, string $color, string $background, Response $response, Document $user) {
->action(function (string $name, int $width, int $height, string $background, Response $response, Document $user) {
$themes = [
['color' => '#27005e', 'background' => '#e1d2f6'], // VIOLET
['color' => '#5e2700', 'background' => '#f3d9c6'], // ORANGE
['color' => '#006128', 'background' => '#c9f3c6'], // GREEN
['color' => '#580061', 'background' => '#f2d1f5'], // FUSCHIA
['color' => '#00365d', 'background' => '#c6e1f3'], // BLUE
['color' => '#00075c', 'background' => '#d2d5f6'], // INDIGO
['color' => '#610038', 'background' => '#f5d1e6'], // PINK
['color' => '#386100', 'background' => '#dcf1bd'], // LIME
['color' => '#615800', 'background' => '#f1ecba'], // YELLOW
['color' => '#610008', 'background' => '#f6d2d5'], // RED
['background' => '#F2F2F8'], // Default
['background' => '#FDC584'], // Orange
['background' => '#94DBD1'], // Green
['background' => '#A1C4FF'], // Blue
['background' => '#FFA1CE'], // Pink
['background' => '#CBB1FC'] // Purple
];
$rand = \rand(0, \count($themes) - 1);
$name = (!empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', ''));
$words = \explode(' ', \strtoupper($name));
// if there is no space, try to split by `_` underscore
@ -393,25 +386,34 @@ App::get('/v1/avatars/initials')
}
$rand = \substr($code, -1);
// Wrap rand value to avoid out of range
$rand = ($rand > \count($themes) - 1) ? $rand % \count($themes) : $rand;
$background = (!empty($background)) ? '#' . $background : $themes[$rand]['background'];
$color = (!empty($color)) ? '#' . $color : $themes[$rand]['color'];
$image = new \Imagick();
$punch = new \Imagick();
$draw = new \ImagickDraw();
$fontSize = \min($width, $height) / 2;
$punch->newImage($width, $height, 'transparent');
$draw->setFont(__DIR__ . "/../../../public/fonts/poppins-v9-latin-500.ttf");
$image->setFont(__DIR__ . "/../../../public/fonts/poppins-v9-latin-500.ttf");
$draw->setFillColor(new \ImagickPixel($color));
$draw->setFillColor(new ImagickPixel('black'));
$draw->setFontSize($fontSize);
$draw->setTextAlignment(\Imagick::ALIGN_CENTER);
$draw->annotation($width / 1.97, ($height / 2) + ($fontSize / 3), $initials);
$punch->drawImage($draw);
$punch->negateImage(true, Imagick::CHANNEL_ALPHA);
$image->newImage($width, $height, $background);
$image->setImageFormat("png");
$image->drawImage($draw);
$image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
//$image->setImageCompressionQuality(9 - round(($quality / 100) * 9));

View file

@ -217,8 +217,9 @@ App::post('/v1/databases')
$events->setParam('databaseId', $database->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($database, Response::MODEL_DATABASE);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($database, Response::MODEL_DATABASE);
});
App::get('/v1/databases')
@ -529,8 +530,9 @@ App::post('/v1/databases/:databaseId/collections')
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($collection, Response::MODEL_COLLECTION);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($collection, Response::MODEL_COLLECTION);
});
App::get('/v1/databases/:databaseId/collections')
@ -887,8 +889,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
'array' => $array,
]), $response, $dbForProject, $database, $events);
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING);
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email')
@ -929,8 +932,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email'
'format' => APP_DATABASE_ATTRIBUTE_EMAIL,
]), $response, $dbForProject, $database, $events);
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_EMAIL);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_EMAIL);
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum')
@ -987,8 +991,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum')
'formatOptions' => ['elements' => $elements],
]), $response, $dbForProject, $database, $events);
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_ENUM);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_ENUM);
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip')
@ -1029,8 +1034,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip')
'format' => APP_DATABASE_ATTRIBUTE_IP,
]), $response, $dbForProject, $database, $events);
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_IP);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_IP);
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url')
@ -1071,8 +1077,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url')
'format' => APP_DATABASE_ATTRIBUTE_URL,
]), $response, $dbForProject, $database, $events);
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_URL);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_URL);
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/integer')
@ -1142,8 +1149,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege
$attribute->setAttribute('max', \intval($formatOptions['max']));
}
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_INTEGER);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_INTEGER);
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float')
@ -1216,8 +1224,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float'
$attribute->setAttribute('max', \floatval($formatOptions['max']));
}
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_FLOAT);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_FLOAT);
});
App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolean')
@ -1257,8 +1266,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea
'array' => $array,
]), $response, $dbForProject, $database, $events);
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_BOOLEAN);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_BOOLEAN);
});
@ -1300,8 +1310,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti
'filters' => ['datetime']
]), $response, $dbForProject, $database, $events);
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($attribute, Response::MODEL_ATTRIBUTE_DATETIME);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_DATETIME);
});
@ -1557,7 +1568,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
$oldAttributes[] = [
'key' => '$id',
'type' => 'string',
'type' => Database::VAR_STRING,
'status' => 'available',
'required' => true,
'array' => false,
@ -1567,7 +1578,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
$oldAttributes[] = [
'key' => '$createdAt',
'type' => 'string',
'type' => Database::VAR_DATETIME,
'status' => 'available',
'signed' => false,
'required' => false,
@ -1578,7 +1589,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
$oldAttributes[] = [
'key' => '$updatedAt',
'type' => 'string',
'type' => Database::VAR_DATETIME,
'status' => 'available',
'signed' => false,
'required' => false,
@ -1642,12 +1653,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('indexId', $index->getId())
->setContext('collection', $collection)
->setContext('database', $db)
->setContext('collection', $collection)
->setContext('database', $db)
;
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($index, Response::MODEL_INDEX);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($index, Response::MODEL_INDEX);
});
App::get('/v1/databases/:databaseId/collections/:collectionId/indexes')
@ -1827,7 +1839,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. 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('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.')
->param('data', [], new JSON(), 'Document data as JSON object.')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE]), 'An array of permissions strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true)
->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 permissions strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true)
->inject('response')
->inject('dbForProject')
->inject('user')
@ -1925,8 +1937,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->setContext('database', $database)
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($document, Response::MODEL_DOCUMENT);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($document, Response::MODEL_DOCUMENT);
});
App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
@ -2207,7 +2220,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
->param('collectionId', null, new UID(), 'Collection ID.')
->param('documentId', null, new UID(), 'Document ID.')
->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true)
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permissions strings. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
->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 permissions strings. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
->inject('response')
->inject('dbForProject')
->inject('events')

View file

@ -90,8 +90,9 @@ App::post('/v1/functions')
$eventsInstance->setParam('functionId', $function->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($function, Response::MODEL_FUNCTION);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($function, Response::MODEL_FUNCTION);
});
App::get('/v1/functions')
@ -754,8 +755,9 @@ App::post('/v1/functions/:functionId/deployments')
->setParam('functionId', $function->getId())
->setParam('deploymentId', $deployment->getId());
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
$response->dynamic($deployment, Response::MODEL_DEPLOYMENT);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($deployment, Response::MODEL_DEPLOYMENT);
});
App::get('/v1/functions/:functionId/deployments')
@ -936,7 +938,7 @@ App::post('/v1/functions/:functionId/executions')
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
->param('functionId', '', new UID(), 'Function ID.')
->param('data', '', new Text(8192), 'String of custom data to send to function.', true)
->param('async', true, new Boolean(), 'Execute code asynchronously. Default value is true.', true)
->param('async', false, new Boolean(), 'Execute code in the background. Default value is false.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
@ -1041,9 +1043,9 @@ App::post('/v1/functions/:functionId/executions')
$event->trigger();
$response->setStatusCode(Response::STATUS_CODE_ACCEPTED);
return $response->dynamic($execution, Response::MODEL_EXECUTION);
return $response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
->dynamic($execution, Response::MODEL_EXECUTION);
}
$vars = array_reduce($function['vars'] ?? [], function (array $carry, Document $var) {
@ -1108,6 +1110,7 @@ App::post('/v1/functions/:functionId/executions')
$roles = Authorization::getRoles();
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
$isAppUser = Auth::isAppUser($roles);
if (!$isPrivilegedUser && !$isAppUser) {
$execution->setAttribute('stdout', '');
$execution->setAttribute('stderr', '');
@ -1339,8 +1342,9 @@ App::post('/v1/functions/:functionId/variables')
$dbForProject->deleteCachedDocument('functions', $function->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($variable, Response::MODEL_VARIABLE);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($variable, Response::MODEL_VARIABLE);
});
App::get('/v1/functions/:functionId/variables')

View file

@ -167,8 +167,9 @@ App::post('/v1/projects')
$dbForProject->createCollection($key, $attributes, $indexes);
}
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($project, Response::MODEL_PROJECT);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($project, Response::MODEL_PROJECT);
});
App::get('/v1/projects')
@ -624,8 +625,9 @@ App::post('/v1/projects/:projectId/webhooks')
$dbForConsole->deleteCachedDocument('projects', $project->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($webhook, Response::MODEL_WEBHOOK);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($webhook, Response::MODEL_WEBHOOK);
});
App::get('/v1/projects/:projectId/webhooks')
@ -871,8 +873,9 @@ App::post('/v1/projects/:projectId/keys')
$dbForConsole->deleteCachedDocument('projects', $project->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($key, Response::MODEL_KEY);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($key, Response::MODEL_KEY);
});
App::get('/v1/projects/:projectId/keys')
@ -1072,8 +1075,9 @@ App::post('/v1/projects/:projectId/platforms')
$dbForConsole->deleteCachedDocument('projects', $project->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($platform, Response::MODEL_PLATFORM);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($platform, Response::MODEL_PLATFORM);
});
App::get('/v1/projects/:projectId/platforms')
@ -1289,8 +1293,9 @@ App::post('/v1/projects/:projectId/domains')
$dbForConsole->deleteCachedDocument('projects', $project->getId());
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($domain, Response::MODEL_DOMAIN);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($domain, Response::MODEL_DOMAIN);
});
App::get('/v1/projects/:projectId/domains')

View file

@ -48,7 +48,7 @@ App::post('/v1/storage/buckets')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
->label('event', 'buckets.[bucketId].create')
->label('audits.resource', 'buckets/{response.$id}')
->label('audits.resource', 'bucket/{response.$id}')
->label('usage.metric', 'buckets.{scope}.requests.create')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
@ -136,8 +136,9 @@ App::post('/v1/storage/buckets')
->setParam('bucketId', $bucket->getId())
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($bucket, Response::MODEL_BUCKET);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($bucket, Response::MODEL_BUCKET);
});
App::get('/v1/storage/buckets')
@ -218,7 +219,7 @@ App::put('/v1/storage/buckets/:bucketId')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
->label('event', 'buckets.[bucketId].update')
->label('audits.resource', 'buckets/{response.$id}')
->label('audits.resource', 'bucket/{response.$id}')
->label('usage.metric', 'buckets.{scope}.requests.update')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
@ -284,7 +285,7 @@ App::delete('/v1/storage/buckets/:bucketId')
->groups(['api', 'storage'])
->label('scope', 'buckets.write')
->label('event', 'buckets.[bucketId].delete')
->label('audits.resource', 'buckets/{request.bucketId}')
->label('audits.resource', 'bucket/{request.bucketId}')
->label('usage.metric', 'buckets.{scope}.requests.delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'storage')
@ -326,7 +327,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->groups(['api', 'storage'])
->label('scope', 'files.write')
->label('event', 'buckets.[bucketId].files.[fileId].create')
->label('audits.resource', 'files/{response.$id}')
->label('audits.resource', 'file/{response.$id}')
->label('usage.metric', 'files.{scope}.requests.create')
->label('usage.params', ['bucketId:{request.bucketId}'])
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
@ -344,7 +345,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->param('bucketId', null, 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 your own unique ID or pass the string "unique()" to auto generate it. 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('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE]), 'An array of permission strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true)
->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 the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).', true)
->inject('request')
->inject('response')
->inject('dbForProject')
@ -643,8 +644,9 @@ App::post('/v1/storage/buckets/:bucketId/files')
$metadata = null; // was causing leaks as it was passed by reference
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($file, Response::MODEL_FILE);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($file, Response::MODEL_FILE);
});
App::get('/v1/storage/buckets/:bucketId/files')
@ -1236,7 +1238,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->groups(['api', 'storage'])
->label('scope', 'files.write')
->label('event', 'buckets.[bucketId].files.[fileId].update')
->label('audits.resource', 'files/{response.$id}')
->label('audits.resource', 'file/{response.$id}')
->label('usage.metric', 'files.{scope}.requests.update')
->label('usage.params', ['bucketId:{request.bucketId}'])
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
@ -1251,7 +1253,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->label('sdk.response.model', Response::MODEL_FILE)
->param('bucketId', null, 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 UID(), 'File unique ID.')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission string. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
->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 string. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
->inject('response')
->inject('dbForProject')
->inject('user')

View file

@ -116,8 +116,9 @@ App::post('/v1/teams')
$events->setParam('userId', $user->getId());
}
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($team, Response::MODEL_TEAM);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($team, Response::MODEL_TEAM);
});
App::get('/v1/teams')
@ -446,14 +447,15 @@ App::post('/v1/teams/:teamId/memberships')
->setParam('membershipId', $membership->getId())
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic(
$membership
->setAttribute('teamName', $team->getAttribute('name'))
->setAttribute('userName', $invitee->getAttribute('name'))
->setAttribute('userEmail', $invitee->getAttribute('email')),
Response::MODEL_MEMBERSHIP
);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic(
$membership
->setAttribute('teamName', $team->getAttribute('name'))
->setAttribute('userName', $invitee->getAttribute('name'))
->setAttribute('userEmail', $invitee->getAttribute('email')),
Response::MODEL_MEMBERSHIP
);
});
App::get('/v1/teams/:teamId/memberships')

View file

@ -108,8 +108,9 @@ App::post('/v1/users')
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::post('/v1/users/bcrypt')
@ -136,8 +137,9 @@ App::post('/v1/users/bcrypt')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('bcrypt', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::post('/v1/users/md5')
@ -164,8 +166,9 @@ App::post('/v1/users/md5')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('md5', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::post('/v1/users/argon2')
@ -192,8 +195,9 @@ App::post('/v1/users/argon2')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('argon2', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::post('/v1/users/sha')
@ -227,8 +231,9 @@ App::post('/v1/users/sha')
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::post('/v1/users/phpass')
@ -255,8 +260,9 @@ App::post('/v1/users/phpass')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('phpass', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::post('/v1/users/scrypt')
@ -296,8 +302,9 @@ App::post('/v1/users/scrypt')
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::post('/v1/users/scrypt-modified')
@ -327,8 +334,9 @@ App::post('/v1/users/scrypt-modified')
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $dbForProject, $events);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($user, Response::MODEL_USER);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($user, Response::MODEL_USER);
});
App::get('/v1/users')

View file

@ -223,7 +223,7 @@ App::init()
->addHeader('Server', 'Appwrite')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $refDomain)
->addHeader('Access-Control-Allow-Credentials', 'true')
@ -374,7 +374,7 @@ App::options()
$response
->addHeader('Server', 'Appwrite')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')

View file

@ -413,7 +413,7 @@ $permissions = $this->getParam('permissions', null);
</div>
</li>
<?php if(!$new): ?>
<li data-state="/console/databases/document/activity?id={{router.params.id}}&collection={{router.params.collection}}&project={{router.params.project}}">
<li data-state="/console/databases/document/activity?id={{router.params.id}}&collection={{router.params.collection}}&project={{router.params.project}}&databaseId={{router.params.databaseId}}">
<h2>Activity</h2>
<?php echo $logs->render(); ?>

View file

@ -596,7 +596,7 @@ sort($patterns);
</form>
<div>
<span class="text-one-liner" data-ls-bind="{{variable.key}}"></span>
<span data-ls-bind="{{variable.key}}"></span>
</div>
<div data-ui-modal class="modal box close" data-button-text="Show Value" data-button-class="link pull-start margin-end-small margin-top-tiny">

View file

@ -45,13 +45,13 @@
"appwrite/php-runtimes": "0.11.*",
"utopia-php/framework": "0.21.*",
"utopia-php/logger": "0.3.*",
"utopia-php/abuse": "0.12.*",
"utopia-php/abuse": "0.13.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.13.*",
"utopia-php/audit": "0.14.*",
"utopia-php/cache": "0.6.*",
"utopia-php/cli": "0.13.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "dev-fix-force-datetime-filter as 0.24.0",
"utopia-php/database": "dev-fix-force-datetime-filter as 0.25.0",
"utopia-php/locale": "0.4.*",
"utopia-php/registry": "0.5.*",
"utopia-php/preloader": "0.2.*",
@ -77,7 +77,7 @@
}
],
"require-dev": {
"appwrite/sdk-generator": "0.23.0",
"appwrite/sdk-generator": "0.25.0",
"ext-fileinfo": "*",
"phpunit/phpunit": "9.5.20",
"squizlabs/php_codesniffer": "^3.6",

48
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b3bac751cba7eabe3dd207fa9aef8c86",
"content-hash": "aebe91f66ec287492dfd575da6385082",
"packages": [
{
"name": "adhocore/jwt",
@ -1741,23 +1741,23 @@
},
{
"name": "utopia-php/abuse",
"version": "0.12.0",
"version": "0.13.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "aa1e1aae163ecf8ea81d48857ff55c241dcb695f"
"reference": "4c1b8fe742f17158c59550cdfd9074a94bf474ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/aa1e1aae163ecf8ea81d48857ff55c241dcb695f",
"reference": "aa1e1aae163ecf8ea81d48857ff55c241dcb695f",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/4c1b8fe742f17158c59550cdfd9074a94bf474ac",
"reference": "4c1b8fe742f17158c59550cdfd9074a94bf474ac",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.24.0"
"utopia-php/database": "0.25.*"
},
"require-dev": {
"phpunit/phpunit": "^9.4",
@ -1789,9 +1789,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.12.0"
"source": "https://github.com/utopia-php/abuse/tree/0.13.1"
},
"time": "2022-08-27T09:50:09+00:00"
"time": "2022-09-07T16:02:58+00:00"
},
{
"name": "utopia-php/analytics",
@ -1850,22 +1850,22 @@
},
{
"name": "utopia-php/audit",
"version": "0.13.0",
"version": "0.14.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b"
"reference": "b011224ed9bfef7e5c849938e65619af28f7cf41"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b",
"reference": "a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/b011224ed9bfef7e5c849938e65619af28f7cf41",
"reference": "b011224ed9bfef7e5c849938e65619af28f7cf41",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.24.0"
"utopia-php/database": "0.25.*"
},
"require-dev": {
"phpunit/phpunit": "^9.3",
@ -1897,9 +1897,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.13.0"
"source": "https://github.com/utopia-php/audit/tree/0.14.1"
},
"time": "2022-08-27T09:18:57+00:00"
"time": "2022-09-07T16:03:16+00:00"
},
{
"name": "utopia-php/cache",
@ -2840,16 +2840,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.23.0",
"version": "0.25.0",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "efadccb9abd6263d045ef157881143d3a59dc710"
"reference": "91e2b9bfb06521faabd610935cbfc1825110666a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/efadccb9abd6263d045ef157881143d3a59dc710",
"reference": "efadccb9abd6263d045ef157881143d3a59dc710",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/91e2b9bfb06521faabd610935cbfc1825110666a",
"reference": "91e2b9bfb06521faabd610935cbfc1825110666a",
"shasum": ""
},
"require": {
@ -2884,9 +2884,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.23.0"
"source": "https://github.com/appwrite/sdk-generator/tree/0.25.0"
},
"time": "2022-09-04T17:29:33+00:00"
"time": "2022-09-06T16:32:52+00:00"
},
{
"name": "doctrine/instantiator",
@ -5362,8 +5362,8 @@
{
"package": "utopia-php/database",
"version": "dev-fix-force-datetime-filter",
"alias": "0.24.0",
"alias_normalized": "0.24.0.0"
"alias": "0.25.0",
"alias_normalized": "0.25.0.0"
}
],
"minimum-stability": "stable",
@ -5393,5 +5393,5 @@
"platform-overrides": {
"php": "8.0"
},
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.2.0"
}

View file

@ -3,4 +3,3 @@ appwrite avatars getInitials \

View file

@ -3970,7 +3970,7 @@ return false;};return{isRTL:isRTL,};},true);})(window);(function(window){"use st
let size=element.dataset["size"]||80;let name=$value.name||$value||"";name=(typeof name!=='string')?'--':name;return def="/v1/avatars/initials?project=console"+"&name="+
encodeURIComponent(name)+"&width="+
size+"&height="+
size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let now=new Date();now.setMinutes(now.getMinutes()+now.getTimezoneOffset());let timestamp=new Date(now.toISOString()).getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let timestamp=new Date().getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
let value=seconds;if(seconds>=31536000){value=Math.floor(seconds/31536000);unit="year";}
else if(seconds>=86400){value=Math.floor(seconds/86400);unit="day";}
else if(seconds>=3600){value=Math.floor(seconds/3600);unit="hour";}

View file

@ -558,7 +558,7 @@ return false;};return{isRTL:isRTL,};},true);})(window);(function(window){"use st
let size=element.dataset["size"]||80;let name=$value.name||$value||"";name=(typeof name!=='string')?'--':name;return def="/v1/avatars/initials?project=console"+"&name="+
encodeURIComponent(name)+"&width="+
size+"&height="+
size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let now=new Date();now.setMinutes(now.getMinutes()+now.getTimezoneOffset());let timestamp=new Date(now.toISOString()).getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
size;}).add("selectedCollection",function($value,router){return $value===router.params.collectionId?"selected":"";}).add("selectedDocument",function($value,router){return $value===router.params.documentId?"selected":"";}).add("localeString",function($value){$value=parseInt($value);return!Number.isNaN($value)?$value.toLocaleString():"";}).add("dateTime",function($value,date){return $value?date.format({year:'numeric',month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'},$value):"";}).add("date",function($value,date){return $value?date.format({year:'numeric',month:'short',day:'2-digit',},$value):"";}).add("timeSince",function($value){$value=new Date($value).getTime();let timestamp=new Date().getTime();let seconds=Math.floor((timestamp-$value)/1000);let unit="second";let direction="ago";if(seconds<0){seconds=-seconds;direction="from now";}
let value=seconds;if(seconds>=31536000){value=Math.floor(seconds/31536000);unit="year";}
else if(seconds>=86400){value=Math.floor(seconds/86400);unit="day";}
else if(seconds>=3600){value=Math.floor(seconds/3600);unit="hour";}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -47,13 +47,7 @@ window.ls.filter
.add("timeSince", function ($value) {
$value = new Date($value).getTime();
/**
* Adapt to timezone UTC.
*/
let now = new Date();
now.setMinutes(now.getMinutes() + now.getTimezoneOffset());
let timestamp = new Date(now.toISOString()).getTime();
let timestamp = new Date().getTime();
let seconds = Math.floor((timestamp - $value) / 1000);
let unit = "second";
let direction = "ago";

View file

@ -424,7 +424,7 @@ fieldset {
width: ~"calc(100% - 2px)";
max-height: 180px;
visibility: visible !important;
object-fit: contain;
object-fit: cover;
}
.video-preview {

View file

@ -431,11 +431,14 @@ class Auth
continue;
}
if (isset($node['teamId']) && isset($node['roles'])) {
if (isset($node['$id']) && isset($node['teamId'])) {
$roles[] = Role::team($node['teamId'])->toString();
$roles[] = Role::member($node['$id'])->toString();
foreach ($node['roles'] as $nodeRole) { // Set all team roles
$roles[] = Role::team($node['teamId'], $nodeRole)->toString();
if (isset($node['roles'])) {
foreach ($node['roles'] as $nodeRole) { // Set all team roles
$roles[] = Role::team($node['teamId'], $nodeRole)->toString();
}
}
}
}

View file

@ -36,9 +36,9 @@ class Bucket extends Model
'array' => true,
])
->addRule('fileSecurity', [
'type' => self::TYPE_STRING,
'type' => self::TYPE_BOOLEAN,
'description' => 'Whether file-level security is enabled. [Learn more about permissions](/docs/permissions).',
'default' => '',
'default' => false,
'example' => true,
])
->addRule('name', [

View file

@ -26,7 +26,7 @@ class HTTPTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEquals('Appwrite', $response['headers']['server']);
$this->assertEquals('GET, POST, PUT, PATCH, DELETE', $response['headers']['access-control-allow-methods']);
$this->assertEquals('Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies', $response['headers']['access-control-allow-headers']);
$this->assertEquals('Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies', $response['headers']['access-control-allow-headers']);
$this->assertEquals('X-Fallback-Cookies', $response['headers']['access-control-expose-headers']);
$this->assertEquals('http://localhost', $response['headers']['access-control-allow-origin']);
$this->assertEquals('true', $response['headers']['access-control-allow-credentials']);

View file

@ -1185,6 +1185,7 @@ trait AccountBase
/**
* @depends testCreateAccountRecovery
*/
#[Retry(count: 1)]
public function testUpdateAccountRecovery($data): array
{
$id = $data['id'] ?? '';

View file

@ -491,7 +491,6 @@ trait AvatarsBase
'name' => 'W W',
'width' => 200,
'height' => 200,
'color' => 'ffffff',
'background' => '000000',
]);
@ -508,34 +507,33 @@ trait AvatarsBase
'name' => 'W W',
'width' => 200000,
'height' => 200,
'color' => 'ffffff',
'background' => '000000',
]);
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200,
'height' => 200,
'color' => 'white',
'background' => '000000',
]);
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200,
'height' => 200,
'color' => 'ffffff',
'background' => 'black',
]);
$this->assertEquals(400, $response['headers']['status-code']);
}
public function testInitialImage()
{
$response = $this->client->call(Client::METHOD_GET, '/avatars/initials', [
'x-appwrite-project' => $this->getProject()['$id'],
], [
'name' => 'W W',
'width' => 200,
'height' => 200,
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('image/png', $response['headers']['content-type']);
$this->assertNotEmpty($response['body']);
$image = new \Imagick();
$image->readImageBlob($response['body']);
$original = new \Imagick(__DIR__ . '/../../../resources/initials.png');
$this->assertEquals($image->getImageWidth(), $original->getImageWidth());
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
$this->assertEquals('PNG', $image->getImageFormat());
$this->assertEquals(strlen(\file_get_contents(__DIR__ . '/../../../resources/initials.png')), strlen($response['body']));
}
}

View file

@ -16,6 +16,94 @@ class DatabasesCustomClientTest extends Scope
use ProjectCustom;
use SideClient;
public function testAllowedPermissions(): void
{
/**
* Test for SUCCESS
*/
$database = $this->client->call(Client::METHOD_POST, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
], [
'databaseId' => ID::unique(),
'name' => 'Test Database'
]);
$databaseId = $database['body']['$id'];
// Collection aliases write to create, update, delete
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'collectionId' => ID::unique(),
'name' => 'Movies',
'documentSecurity' => true,
'permissions' => [
Permission::write(Role::user($this->getUser()['$id'])),
],
]);
$moviesId = $movies['body']['$id'];
$this->assertContains(Permission::create(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']);
$this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']);
$this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']);
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'title',
'size' => 256,
'required' => true,
]);
sleep(1);
// Document aliases write to update, delete
$document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'documentId' => ID::unique(),
'data' => [
'title' => 'Captain America',
],
'permissions' => [
Permission::write(Role::user($this->getUser()['$id'])),
]
]);
$this->assertNotContains(Permission::create(Role::user($this->getUser()['$id'])), $document1['body']['$permissions']);
$this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $document1['body']['$permissions']);
$this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $document1['body']['$permissions']);
/**
* Test for FAILURE
*/
// Document does not allow create permission
$document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'documentId' => ID::unique(),
'data' => [
'title' => 'Captain America',
],
'permissions' => [
Permission::create(Role::user($this->getUser()['$id'])),
]
]);
$this->assertEquals(400, $document2['headers']['status-code']);
}
public function testUpdateWithoutPermission(): array
{
// If document has been created by server and client tried to update it without adjusting permissions, permission validation should be skipped

View file

@ -225,4 +225,54 @@ class DatabasesPermissionsGuestTest extends Scope
Authorization::setRole($role);
}
}
public function testWriteDocumentWithPermissions()
{
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'databaseId' => ID::unique(),
'name' => 'GuestPermissionsWrite',
]);
$this->assertEquals(201, $database['headers']['status-code']);
$this->assertEquals('GuestPermissionsWrite', $database['body']['name']);
$databaseId = $database['body']['$id'];
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', $this->getServerHeader(), [
'collectionId' => ID::unique(),
'name' => 'Movies',
'permissions' => [
Permission::create(Role::any()),
],
'documentSecurity' => true
]);
$moviesId = $movies['body']['$id'];
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/attributes/string', $this->getServerHeader(), [
'key' => 'title',
'size' => 256,
'required' => true,
]);
sleep(1);
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $moviesId . '/documents', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], [
'documentId' => ID::unique(),
'data' => [
'title' => 'Thor: Ragnarok',
],
'permissions' => [
Permission::read(Role::any()),
]
]);
$this->assertEquals(201, $document['headers']['status-code']);
$this->assertEquals('Thor: Ragnarok', $document['body']['title']);
}
}

View file

@ -245,6 +245,7 @@ class FunctionsCustomClientTest extends Scope
'x-appwrite-project' => $projectId,
], $this->getHeaders()), [
'data' => 'foobar',
'async' => true
]);
$this->assertEquals(202, $execution['headers']['status-code']);
@ -343,6 +344,7 @@ class FunctionsCustomClientTest extends Scope
'x-appwrite-project' => $projectId,
], [
'data' => 'foobar',
'async' => true,
]);
$this->assertEquals(202, $execution['headers']['status-code']);
@ -388,6 +390,7 @@ class FunctionsCustomClientTest extends Scope
'x-appwrite-project' => $projectId,
], $this->getHeaders()), [
'data' => 'foobar',
'async' => true
]);
$this->assertEquals(202, $execution['headers']['status-code']);
@ -568,7 +571,7 @@ class FunctionsCustomClientTest extends Scope
'x-appwrite-project' => $projectId,
], $this->getHeaders()), [
'data' => 'foobar',
'async' => false
// Testing default value, should be 'async' => false
]);
$output = json_decode($execution['body']['response'], true);

View file

@ -727,6 +727,7 @@ class FunctionsCustomServerTest extends Scope
/**
* @depends testUpdateDeployment
*/
#[Retry(count: 2)]
public function testSyncCreateExecution($data): array
{
/**
@ -737,7 +738,7 @@ class FunctionsCustomServerTest extends Scope
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'async' => false,
// Testing default value, should be 'async' => false
]);
$this->assertEquals(201, $execution['headers']['status-code']);
@ -978,6 +979,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'data' => 'foobar',
'async' => true
]);
$executionId = $execution['body']['$id'] ?? '';
@ -1092,6 +1094,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'data' => 'foobar',
'async' => true
]);
$executionId = $execution['body']['$id'] ?? '';
@ -1204,6 +1207,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'data' => 'foobar',
'async' => true
]);
$executionId = $execution['body']['$id'] ?? '';
@ -1317,6 +1321,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'data' => 'foobar',
'async' => true
]);
$executionId = $execution['body']['$id'] ?? '';
@ -1430,6 +1435,7 @@ class FunctionsCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'data' => 'foobar',
'async' => true
]);
$executionId = $execution['body']['$id'] ?? '';

View file

@ -1122,7 +1122,6 @@ class RealtimeCustomClientTest extends Scope
], $this->getHeaders()), [
'permissions' => [
Permission::read(Role::any()),
Permission::create(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
@ -1263,7 +1262,9 @@ class RealtimeCustomClientTest extends Scope
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), []);
], $this->getHeaders()), [
'async' => true
]);
$this->assertEquals($execution['headers']['status-code'], 202);
$this->assertNotEmpty($execution['body']['$id']);

View file

@ -1065,6 +1065,68 @@ class StorageCustomClientTest extends Scope
$this->assertEmpty($file['body']);
}
public function testAllowedPermissions(): void
{
/**
* Test for SUCCESS
*/
// Bucket aliases write to create, update, delete
$bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'bucketId' => ID::unique(),
'name' => 'Test Bucket',
'permissions' => [
Permission::write(Role::user($this->getUser()['$id'])),
],
'fileSecurity' => true,
]);
$bucketId = $bucket['body']['$id'];
$this->assertEquals(201, $bucket['headers']['status-code']);
$this->assertContains(Permission::create(Role::user($this->getUser()['$id'])), $bucket['body']['$permissions']);
$this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $bucket['body']['$permissions']);
$this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $bucket['body']['$permissions']);
// File aliases write to update, delete
$file1 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'fileId' => ID::unique(),
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'),
'permissions' => [
Permission::write(Role::user($this->getUser()['$id'])),
]
]);
$this->assertNotContains(Permission::create(Role::user($this->getUser()['$id'])), $file1['body']['$permissions']);
$this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $file1['body']['$permissions']);
$this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $file1['body']['$permissions']);
/**
* Test for FAILURE
*/
// File does not allow create permission
$file2 = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', [
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], [
'fileId' => ID::unique(),
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'),
'permissions' => [
Permission::create(Role::user($this->getUser()['$id'])),
]
]);
$this->assertEquals(400, $file2['headers']['status-code']);
}
public function testCreateFileDefaultPermissions(): array
{
/**
@ -1220,9 +1282,8 @@ class StorageCustomClientTest extends Scope
], $this->getHeaders()), [
'permissions' => [
Permission::read(Role::user(ID::custom('notme'))),
Permission::create(Role::user(ID::custom('notme'))),
Permission::update(Role::user(ID::custom('notme'))),
Permission::delete(Role::user(ID::custom('notme'))),
Permission::update(Role::user(ID::custom('notme'))),
Permission::delete(Role::user(ID::custom('notme'))),
],
]);

View file

@ -2,6 +2,7 @@
namespace Tests\E2E\Services\Users;
use Appwrite\Tests\Retry;
use Tests\E2E\Client;
use Utopia\Database\ID;
@ -852,6 +853,7 @@ trait UsersBase
/**
* @depends testGetUser
*/
#[Retry(count: 1)]
public function testUpdateUserStatus(array $data): array
{
/**

View file

@ -556,7 +556,6 @@ trait WebhooksBase
], $this->getHeaders()), [
'permissions' => [
Permission::read(Role::any()),
Permission::create(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],

View file

@ -2,6 +2,7 @@
namespace Tests\E2E\Services\Webhooks;
use Appwrite\Tests\Retry;
use Tests\E2E\Client;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\ProjectCustom;
@ -416,6 +417,7 @@ class WebhooksCustomClientTest extends Scope
/**
* @depends testDeleteAccountSessions
*/
#[Retry(count: 1)]
public function testUpdateAccountName($data): array
{
$id = $data['id'] ?? '';

View file

@ -605,7 +605,9 @@ class WebhooksCustomServerTest extends Scope
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $id . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
], $this->getHeaders()), [
'async' => true
]);
$executionId = $execution['body']['$id'] ?? '';

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -353,16 +353,58 @@ class AuthTest extends TestCase
'$id' => ID::custom('123'),
'memberships' => [
[
'confirm' => true,
'$id' => ID::custom('456'),
'teamId' => ID::custom('abc'),
'confirm' => true,
'roles' => [
'administrator',
'moderator'
]
],
[
'confirm' => true,
'$id' => ID::custom('abc'),
'teamId' => ID::custom('def'),
'confirm' => true,
'roles' => [
'guest'
]
]
]
]);
$roles = Auth::getRoles($user);
$this->assertCount(9, $roles);
$this->assertContains(Role::users()->toString(), $roles);
$this->assertContains(Role::user(ID::custom('123'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'), 'administrator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
$this->assertContains(Role::member(ID::custom('456'))->toString(), $roles);
$this->assertContains(Role::member(ID::custom('abc'))->toString(), $roles);
}
public function testPrivilegedUserRoles(): void
{
Authorization::setRole(Auth::USER_ROLE_OWNER);
$user = new Document([
'$id' => ID::custom('123'),
'memberships' => [
[
'$id' => ID::custom('def'),
'teamId' => ID::custom('abc'),
'confirm' => true,
'roles' => [
'administrator',
'moderator'
]
],
[
'$id' => ID::custom('abc'),
'teamId' => ID::custom('def'),
'confirm' => true,
'roles' => [
'guest'
]
@ -373,42 +415,6 @@ class AuthTest extends TestCase
$roles = Auth::getRoles($user);
$this->assertCount(7, $roles);
$this->assertContains(Role::users()->toString(), $roles);
$this->assertContains(Role::user(ID::custom('123'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'), 'administrator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
}
public function testPrivilegedUserRoles(): void
{
Authorization::setRole(Auth::USER_ROLE_OWNER);
$user = new Document([
'$id' => ID::custom('123'),
'memberships' => [
[
'confirm' => true,
'teamId' => ID::custom('abc'),
'roles' => [
'administrator',
'moderator'
]
],
[
'confirm' => true,
'teamId' => ID::custom('def'),
'roles' => [
'guest'
]
]
]
]);
$roles = Auth::getRoles($user);
$this->assertCount(5, $roles);
$this->assertNotContains(Role::users()->toString(), $roles);
$this->assertNotContains(Role::user(ID::custom('123'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
@ -416,6 +422,8 @@ class AuthTest extends TestCase
$this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
$this->assertContains(Role::member(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::member(ID::custom('abc'))->toString(), $roles);
}
public function testAppUserRoles(): void
@ -425,16 +433,18 @@ class AuthTest extends TestCase
'$id' => ID::custom('123'),
'memberships' => [
[
'confirm' => true,
'$id' => ID::custom('def'),
'teamId' => ID::custom('abc'),
'confirm' => true,
'roles' => [
'administrator',
'moderator'
]
],
[
'confirm' => true,
'$id' => ID::custom('abc'),
'teamId' => ID::custom('def'),
'confirm' => true,
'roles' => [
'guest'
]
@ -444,7 +454,7 @@ class AuthTest extends TestCase
$roles = Auth::getRoles($user);
$this->assertCount(5, $roles);
$this->assertCount(7, $roles);
$this->assertNotContains(Role::users()->toString(), $roles);
$this->assertNotContains(Role::user(ID::custom('123'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('abc'))->toString(), $roles);
@ -452,5 +462,7 @@ class AuthTest extends TestCase
$this->assertContains(Role::team(ID::custom('abc'), 'moderator')->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::team(ID::custom('def'), 'guest')->toString(), $roles);
$this->assertContains(Role::member(ID::custom('def'))->toString(), $roles);
$this->assertContains(Role::member(ID::custom('abc'))->toString(), $roles);
}
}

View file

@ -54,8 +54,9 @@ class MessagingChannelsTest extends TestCase
'$id' => ID::custom('user' . $this->connectionsCount),
'memberships' => [
[
'confirm' => true,
'$id' => ID::custom('member' . $i),
'teamId' => ID::custom('team' . $i),
'confirm' => true,
'roles' => [
empty($index % 2)
? Auth::USER_ROLE_ADMIN
@ -122,11 +123,11 @@ class MessagingChannelsTest extends TestCase
* Check for correct amount of subscriptions:
* - XXX users
* - XXX teams
* - XXX team roles (2 roles per team)
* - XXX team roles (3 roles per team)
* - 1 guests
* - 1 users
*/
$this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
$this->assertCount(($this->connectionsAuthenticated + (4 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
/**
* Check for connections
@ -138,7 +139,7 @@ class MessagingChannelsTest extends TestCase
$this->realtime->unsubscribe(-1);
$this->assertCount($this->connectionsTotal, $this->realtime->connections);
$this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
$this->assertCount(($this->connectionsAuthenticated + (4 * $this->connectionsPerChannel) + 2), $this->realtime->subscriptions['1']);
for ($i = 0; $i < $this->connectionsCount; $i++) {
$this->realtime->unsubscribe($i);
@ -259,6 +260,7 @@ class MessagingChannelsTest extends TestCase
for ($i = 0; $i < $this->connectionsPerChannel; $i++) {
$permissions[] = Role::team(ID::custom('team' . $i))->toString();
$permissions[] = Role::member(ID::custom('member' . $i))->toString();
}
$event = [
'project' => '1',
@ -284,13 +286,13 @@ class MessagingChannelsTest extends TestCase
$this->assertStringEndsWith($index, $receiver);
}
$role = empty($index % 2)
? Auth::USER_ROLE_ADMIN
: 'member';
$permissions = [
Role::team(
ID::custom('team' . $index),
(empty($index % 2)
? Auth::USER_ROLE_ADMIN
: 'member')
)->toString()
Role::team(ID::custom('team' . $index), $role)->toString(),
Role::member(ID::custom('member' . $index))->toString()
];
$event = [