Compare commits

...
Author SHA1 Message Date
fogelito 499db3cf5e line 2024-06-20 15:46:21 +03:00
fogelito 6f200e8c7f isDevelopment 2024-06-20 15:39:01 +03:00
fogelito 34f74f82e6 Increase timeout text 2024-06-20 15:37:39 +03:00
Christy JacobandGitHub 65a4a3bbfa Merge pull request #8275 from appwrite/fix-tests-for-cl
Fix for Tests, also fix Create bucket endpoint validator for maximum file size
2024-06-19 12:21:26 +05:30
Shimon NewmanandGitHub 1febae5e03 Merge pull request #8285 from appwrite/chore-bump-lib-ver
Chore:update cache & database
2024-06-18 19:04:04 +03:00
shimon 12813a2f29 update cache and database lib 2024-06-18 18:51:00 +03:00
Damodar LohaniandGitHub 076f718203 Update tests/e2e/Services/Storage/StorageBase.php 2024-06-18 12:14:47 +05:45
Damodar LohaniandGitHub a93dcfa1b3 Update storage.php 2024-06-18 11:46:31 +05:45
Damodar Lohani 349b78d5e5 fix assertion 2024-06-17 04:55:06 +00:00
Damodar Lohani 3dcd1314f5 fix file size multiplier 2024-06-17 04:50:22 +00:00
Damodar Lohani 4c8d5d2c89 increase file size 2024-06-16 09:49:19 +00:00
Jake BarnbyandGitHub e195018abd Merge pull request #8255 from appwrite/feat-update-pwd-abuse
Feat update pwd abuse
2024-06-11 16:56:21 +12:00
Jake Barnby a4c1275764 Add abuse limit for update password 2024-06-10 18:09:30 +12:00
Jake BarnbyandGitHub 3c123d372a Merge pull request #8244 from appwrite/1.5.x
Sync 1.5.x into refactor-usage-sn
2024-06-10 12:22:16 +12:00
Damodar LohaniandGitHub 00a633759e Merge pull request #7936 from appwrite/feat-upgrade-platform-with-module
Use latest Platform and add Core module
2024-06-09 06:40:13 +05:45
Steven NguyenandGitHub 4a168f6948 Merge pull request #8245 from appwrite/fix-oauth2-mfa
Fix MFA for OAuth2 only accounts
2024-06-07 18:11:24 -07:00
Steven Nguyen a09a09a7a9 fix(auth): fix MFA verification for OAuth2 sessions
Before this, users who only signed in with OAuth2 were not able to
verify their sessions with MFA because their session already used an
email factor and they couldn't use an additional email factor.

This commit changes the OAuth2 session to include 2 factors: email and
oauth2. This second special factor is used to bypass MFA checks. It is
fine to bypass MFA checks because OAuth2 is supposed to handle the
entire authentication process, verifying who the user is and we, as the
resource provider, only need to trust the OAuth2 provider.
2024-06-07 16:45:14 -07:00
Jake BarnbyandGitHub 7e3070a4b2 Merge pull request #8240 from appwrite/revert-8237-revert-8193-feat-remove-random-shared-tables
Revert "Merge pull request #8237 from appwrite/revert-8193-feat-remov…
2024-06-07 17:34:14 +12:00
Jake Barnby e58e849504 Fix function test 2024-06-06 21:29:34 +12:00
Jake Barnby c87a6a863b Increase sleep 2024-06-06 20:52:22 +12:00
Damodar Lohani f44ed18b05 remove worker index 2024-06-06 08:45:15 +00:00
Damodar Lohani 131de2ea7a refactor module 2024-06-06 08:35:50 +00:00
Damodar Lohani ec69507818 Merge remote-tracking branch 'origin/refactor-usage-sn' into feat-upgrade-platform-with-module 2024-06-06 08:32:07 +00:00
Jake Barnby 9e487b8ccf Revert "Merge pull request #8237 from appwrite/revert-8193-feat-remove-random-shared-tables"
This reverts commit 930ae6ded0, reversing
changes made to 1f6417b156.
2024-06-06 20:11:19 +12:00
Jake BarnbyandGitHub 035144d1ff Merge pull request #8238 from appwrite/chore-bump-base-image
Bump base image from 0.9.0 to 0.9.1
2024-06-06 13:47:01 +12:00
Steven NguyenandGitHub c7157b3692 chore: bump base image from 0.9.0 to 0.9.1 2024-06-06 00:23:00 +00:00
Christy JacobandGitHub 37a1c804b5 Merge pull request #8230 from appwrite/refactor-redis-cache
refactor redis cache
2024-06-06 01:33:48 +05:30
shimon cdf7e1a8dc composer 2024-06-05 22:29:47 +03:00
Christy JacobandGitHub 930ae6ded0 Merge pull request #8237 from appwrite/revert-8193-feat-remove-random-shared-tables
Revert "Feat remove random shared tables"
2024-06-06 00:15:12 +05:30
Christy JacobandGitHub ff6efc2855 Revert "Feat remove random shared tables" 2024-06-06 00:11:56 +05:30
shimon f06e19d8fa composer 2024-06-05 20:52:35 +03:00
shimon eb28841cb1 Merge branch 'refactor-usage-sn' of github.com:appwrite/appwrite into refactor-redis-cache
 Conflicts:
	composer.lock
2024-06-05 20:47:48 +03:00
shimon e2c6c61083 composer 2024-06-05 20:40:14 +03:00
Jake BarnbyandGitHub 1f6417b156 Merge pull request #8193 from appwrite/feat-remove-random-shared-tables
Feat remove random shared tables
2024-06-05 17:17:58 +12:00
Jake Barnby 5b3a3d5bf9 Add flaky test retry 2024-06-04 20:10:45 +12:00
Damodar Lohani a823bca463 update platform 2024-06-04 08:04:51 +00:00
Damodar Lohani fef769271f Merge remote-tracking branch 'origin/refactor-usage-sn' into feat-upgrade-platform-with-module 2024-06-04 08:00:19 +00:00
Jake Barnby f459a5c458 Merge remote-tracking branch 'origin/refactor-usage-sn' into feat-remove-random-shared-tables
# Conflicts:
#	docker-compose.yml
2024-06-04 17:43:14 +12:00
Jake BarnbyandGitHub 026933ff74 Merge pull request #8218 from appwrite/chore-release-sdks
Release SDKs
2024-06-04 16:05:58 +12:00
shimon e28224976a refactor redis cache 2024-06-02 16:17:11 +03:00
Luke B. SilverandGitHub 065dfa6663 Merge pull request #8222 from appwrite/feat-support-twilio-messaging-service-sid
feat: support twilio messaging service sid
2024-05-30 17:24:38 +01:00
loks0n 61336be50d doc: update _APP_SMS_FROM 2024-05-30 16:51:48 +01:00
loks0n 64e0c88349 Merge branch 'refactor-usage-sn' of https://github.com/appwrite/appwrite into feat-support-twilio-messaging-service-sid 2024-05-30 16:48:08 +01:00
fogelito e91a532e74 Database tag 2024-05-30 18:46:21 +03:00
loks0n ab4401992c Revert "feat: use param instead"
This reverts commit 72cca45d6d.
2024-05-30 16:36:05 +01:00
loks0n 72cca45d6d feat: use param instead 2024-05-30 16:34:43 +01:00
loks0n c6a520909e feat: support twilio messaging service sid 2024-05-30 16:23:15 +01:00
Christy JacobandGitHub fd7c6a6a71 Merge pull request #8220 from appwrite/test-main-1
test
2024-05-30 19:19:46 +04:00
fogelito 065b5f4858 test 2024-05-30 16:07:11 +03:00
Steven Nguyen 4b5e86cc05 chore(sdks): bump major version since there are breaking changes 2024-05-29 13:59:59 -07:00
Steven Nguyen 2f8380e97d fix(docs): remove extraneous word in Verify authenticator description 2024-05-29 13:59:12 -07:00
Christy JacobandGitHub 7da997b5cd Merge pull request #8189 from appwrite/chore-sync-1.5.x
Sync 1.5.x into main
2024-05-28 18:38:04 +04:00
Christy Jacob 11b94cf22e Merge branch '1.5.x' of https://github.com/appwrite/appwrite into chore-sync-1.5.x 2024-05-28 13:13:37 +00:00
Jake Barnby bbb4b0bc12 Remove shared table headers 2024-05-24 20:29:25 +12:00
Jake Barnby 00c047d804 Run full tests on shared tables 2024-05-24 20:29:06 +12:00
Jake Barnby e19b465ce2 Move shared tables db to env var from const 2024-05-24 20:10:47 +12:00
Jake Barnby 4ed125f7c8 Remove random shared tables assignment in preparation of setting as override instead 2024-05-24 16:53:09 +12:00
Jake Barnby a895ce4270 Remove redundant backup checks 2024-05-24 16:51:29 +12:00
Steven NguyenandGitHub 1ac7d3576d Merge branch '1.5.x' into chore-sync-1.5.x 2024-05-24 00:49:02 +00:00
Damodar Lohani 1d9f5fa29d Merge remote-tracking branch 'origin/refactor-usage-sn' into feat-upgrade-platform-with-module 2024-05-09 07:50:17 +00:00
Damodar Lohani 70eb56a388 refactor module 2024-04-08 05:25:55 +00:00
Damodar Lohani a67c6bfacb update platform version 2024-04-08 05:16:37 +00:00
Damodar Lohani 5e12eaa2e3 fix type 2024-04-08 05:09:51 +00:00
Damodar Lohani 8c008df1a9 fix change 2024-04-08 05:08:55 +00:00
Damodar Lohani 8fe6ce64b2 create and use core module 2024-04-08 05:05:04 +00:00
Damodar Lohani 4d15e0dbd2 update platform version 2024-04-08 05:03:18 +00:00
30 changed files with 165 additions and 702 deletions
+3
View File
@@ -145,3 +145,6 @@ jobs:
- name: Run ${{matrix.service}} Tests
run: docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
- name: Run ${{matrix.service}} Shared Tables Tests
run: _APP_DATABASE_SHARED_TABLES=database_db_main docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
+1 -1
View File
@@ -29,7 +29,7 @@ ENV VITE_APPWRITE_GROWTH_ENDPOINT=$VITE_APPWRITE_GROWTH_ENDPOINT
RUN npm ci
RUN npm run build
FROM appwrite/base:0.9.0 as final
FROM appwrite/base:0.9.1 as final
LABEL maintainer="team@appwrite.io"
+3 -3
View File
@@ -109,7 +109,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
if (isset($databases[$dsn->getHost()])) {
$database = $databases[$dsn->getHost()];
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
@@ -133,7 +133,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
$databases[$dsn->getHost()] = $database;
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
@@ -202,7 +202,7 @@ CLI::setResource('logError', function (Registry $register) {
}, ['register']);
$platform = new Appwrite();
$platform->init(Service::TYPE_CLI);
$platform->init(Service::TYPE_TASK);
$cli = $platform->getCli();
+3 -3
View File
@@ -15,7 +15,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
'version' => '14.0.2',
'version' => '15.0.0',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@@ -138,7 +138,7 @@ return [
[
'key' => 'react-native',
'name' => 'React Native',
'version' => '0.3.2',
'version' => '0.4.0',
'url' => 'https://github.com/appwrite/sdk-for-react-native',
'package' => 'https://npmjs.com/package/react-native-appwrite',
'enabled' => true,
@@ -267,7 +267,7 @@ return [
[
'key' => 'deno',
'name' => 'Deno',
'version' => '10.0.2',
'version' => '11.0.0',
'url' => 'https://github.com/appwrite/sdk-for-deno',
'package' => 'https://deno.land/x/appwrite',
'enabled' => true,
+1 -1
View File
@@ -450,7 +450,7 @@ return [
],
[
'name' => '_APP_SMS_FROM',
'description' => 'Phone number used for sending out messages. Must start with a leading \'+\' and maximum of 15 digits without spaces (+123456789).',
'description' => 'Phone number used for sending out messages. If using Twilio, this may be a Messaging Service SID, starting with MG. Otherwise, the number must start with a leading \'+\' and maximum of 15 digits without spaces (+123456789). ',
'introduction' => '0.15.0',
'default' => '',
'required' => false,
+4 -3
View File
@@ -86,8 +86,8 @@ $createSession = function (string $userId, string $secret, Request $request, Res
$factor = (match ($verifiedToken->getAttribute('type')) {
Auth::TOKEN_TYPE_MAGIC_URL,
Auth::TOKEN_TYPE_OAUTH2,
Auth::TOKEN_TYPE_EMAIL => 'email',
Auth::TOKEN_TYPE_PHONE => 'phone',
Auth::TOKEN_TYPE_EMAIL => Type::EMAIL,
Auth::TOKEN_TYPE_PHONE => Type::PHONE,
Auth::TOKEN_TYPE_GENERIC => 'token',
default => throw new Exception(Exception::USER_INVALID_TOKEN)
});
@@ -1506,7 +1506,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
'factors' => ['email'],
'factors' => [TYPE::EMAIL, 'oauth2'], // include a special oauth2 factor to bypass MFA checks
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
'expire' => DateTime::addSeconds(new \DateTime(), $duration)
], $detector->getOS(), $detector->getClient(), $detector->getDevice()));
@@ -2524,6 +2524,7 @@ App::patch('/v1/account/password')
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->label('abuse-limit', 10)
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
->param('oldPassword', '', new Password(), 'Current user password. Must be at least 8 chars.', true)
->inject('requestTimestamp')
+1
View File
@@ -387,6 +387,7 @@ App::init()
->action(function (Request $request, Database $dbForProject) {
$timeout = \intval($request->getHeader('x-appwrite-timeout'));
// isDevelopment
if (!empty($timeout) && App::isDevelopment()) {
$dbForProject->setTimeout($timeout);
}
+4 -56
View File
@@ -111,35 +111,8 @@ App::post('/v1/projects')
$projectId = ($projectId == 'unique()') ? ID::unique() : $projectId;
$backups['database_db_fra1_v14x_02'] = ['from' => '03:00', 'to' => '05:00'];
$backups['database_db_fra1_v14x_03'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_04'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_05'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_06'] = ['from' => '00:00', 'to' => '02:00'];
$backups['database_db_fra1_v14x_07'] = ['from' => '00:00', 'to' => '02:00'];
$databases = Config::getParam('pools-database', []);
/**
* Remove databases from the list that are currently undergoing an backup
*/
if (count($databases) > 1) {
$now = new \DateTime();
foreach ($databases as $index => $database) {
if (empty($backups[$database])) {
continue;
}
$backup = $backups[$database];
$from = \DateTime::createFromFormat('H:i', $backup['from']);
$to = \DateTime::createFromFormat('H:i', $backup['to']);
if ($now >= $from && $now <= $to) {
unset($databases[$index]);
break;
}
}
}
$databaseOverride = System::getEnv('_APP_DATABASE_OVERRIDE');
$index = \array_search($databaseOverride, $databases);
if ($index !== false) {
@@ -152,37 +125,12 @@ App::post('/v1/projects')
throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project.");
}
// TODO: 1 in 5 projects use shared tables. Temporary until all projects are using shared tables.
if (
(
!\mt_rand(0, 4)
&& System::getEnv('_APP_DATABASE_SHARED_TABLES', 'enabled') === 'enabled'
&& System::getEnv('_APP_EDITION', 'self-hosted') !== 'self-hosted'
) ||
(
$dsn === DATABASE_SHARED_TABLES
)
) {
// TODO: Temporary until all projects are using shared tables.
if ($dsn === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$schema = 'appwrite';
$database = 'appwrite';
$namespace = System::getEnv('_APP_DATABASE_SHARED_NAMESPACE', '');
$dsn = $schema . '://' . DATABASE_SHARED_TABLES . '?database=' . $database;
if (!empty($namespace)) {
$dsn .= '&namespace=' . $namespace;
}
}
// TODO: Allow overriding in development mode. Temporary until all projects are using shared tables.
if (
App::isDevelopment()
&& System::getEnv('_APP_EDITION', 'self-hosted') !== 'self-hosted'
&& $request->getHeader('x-appwrited-share-tables', false)
) {
$schema = 'appwrite';
$database = 'appwrite';
$namespace = System::getEnv('_APP_DATABASE_SHARED_NAMESPACE', '');
$dsn = $schema . '://' . DATABASE_SHARED_TABLES . '?database=' . $database;
$dsn = $schema . '://' . System::getEnv('_APP_DATABASE_SHARED_TABLES', '') . '?database=' . $database;
if (!empty($namespace)) {
$dsn .= '&namespace=' . $namespace;
@@ -236,7 +184,7 @@ App::post('/v1/projects')
$adapter = $pools->get($dsn->getHost())->pop()->getResource();
$dbForProject = new Database($adapter, $cache);
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$dbForProject
->setSharedTables(true)
->setTenant($project->getInternalId())
+2 -2
View File
@@ -63,7 +63,7 @@ App::post('/v1/storage/buckets')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true)
->param('maximumFileSize', fn (array $plan) => empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1024 * 1024, fn (array $plan) => new Range(1, empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1024 * 1024 * 1024), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true, ['plan'])
->param('maximumFileSize', fn (array $plan) => empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1024 * 1024, fn (array $plan) => new Range(1, empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1024 * 1024), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true, ['plan'])
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
@@ -240,7 +240,7 @@ App::put('/v1/storage/buckets/:bucketId')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true)
->param('maximumFileSize', null, new Range(1, (int) System::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true)
->param('maximumFileSize', fn (array $plan) => empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1024 * 1024, fn (array $plan) => new Range(1, empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1024 * 1024), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true, ['plan'])
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
+2 -2
View File
@@ -584,7 +584,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-Appwrite-Timeout, X-Appwrite-Shared-Tables, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Forwarded-For, X-Forwarded-User-Agent')
->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-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Expose-Headers', 'X-Appwrite-Session, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $refDomain)
->addHeader('Access-Control-Allow-Credentials', 'true');
@@ -635,7 +635,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-Appwrite-Timeout, X-Appwrite-Shared-Tables, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent')
->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-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Expose-Headers', 'X-Appwrite-Session, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')
+2 -5
View File
@@ -143,9 +143,6 @@ const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
const APP_SOCIAL_YOUTUBE = 'https://www.youtube.com/c/appwrite?sub_confirmation=1';
const APP_HOSTNAME_INTERNAL = 'appwrite';
// Databases
const DATABASE_SHARED_TABLES = 'database_db_fra1_self_hosted_16_0';
// Database Reconnect
const DATABASE_RECONNECT_SLEEP = 2;
const DATABASE_RECONNECT_MAX_ATTEMPTS = 10;
@@ -1338,7 +1335,7 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole,
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
}
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
@@ -1391,7 +1388,7 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
->setMetadata('project', $project->getId())
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS);
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
+1 -1
View File
@@ -92,7 +92,7 @@ if (!function_exists("getProjectDB")) {
$database = new Database($adapter, getCache());
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
+3 -8
View File
@@ -93,7 +93,7 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register,
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
}
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
@@ -126,7 +126,7 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForConso
if (isset($databases[$dsn->getHost()])) {
$database = $databases[$dsn->getHost()];
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
@@ -150,7 +150,7 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForConso
$databases[$dsn->getHost()] = $database;
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
@@ -284,11 +284,6 @@ if (!isset($args[1])) {
\array_shift($args);
$workerName = $args[0];
$workerIndex = $args[1] ?? '';
if (!empty($workerIndex)) {
$workerName .= '_' . $workerIndex;
}
if (\str_starts_with($workerName, 'databases')) {
$queueName = System::getEnv('_APP_QUEUE_NAME', 'database_db_main');
+3 -3
View File
@@ -47,7 +47,7 @@
"utopia-php/abuse": "0.37.*",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.39.*",
"utopia-php/cache": "0.9.*",
"utopia-php/cache": "0.10.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.49.*",
@@ -58,10 +58,10 @@
"utopia-php/image": "0.6.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.5.*",
"utopia-php/messaging": "0.11.*",
"utopia-php/messaging": "0.12.*",
"utopia-php/migration": "0.4.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.5.*",
"utopia-php/platform": "0.7.*",
"utopia-php/pools": "0.5.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/queue": "0.7.*",
Generated
+67 -65
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": "53996479cd4ba0c73dbc72d46b240be0",
"content-hash": "e002600539435ca8eaaace6e73b4004d",
"packages": [
{
"name": "adhocore/jwt",
@@ -1427,16 +1427,16 @@
},
{
"name": "utopia-php/abuse",
"version": "0.37.0",
"version": "0.37.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "2de5c12886cbd516e511e559afdd9e615d871062"
"reference": "4dfcff4754c7804d1a70039792c0f2d59a5cc981"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/2de5c12886cbd516e511e559afdd9e615d871062",
"reference": "2de5c12886cbd516e511e559afdd9e615d871062",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/4dfcff4754c7804d1a70039792c0f2d59a5cc981",
"reference": "4dfcff4754c7804d1a70039792c0f2d59a5cc981",
"shasum": ""
},
"require": {
@@ -1470,9 +1470,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.37.0"
"source": "https://github.com/utopia-php/abuse/tree/0.37.1"
},
"time": "2024-03-06T21:20:27+00:00"
"time": "2024-06-05T18:03:59+00:00"
},
{
"name": "utopia-php/analytics",
@@ -1522,16 +1522,16 @@
},
{
"name": "utopia-php/audit",
"version": "0.39.0",
"version": "0.39.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "f0bc15012e05cc0b9dde012ab27d25f193768a2c"
"reference": "7ea91e0ceea7b94293612fea94022b73315677c2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/f0bc15012e05cc0b9dde012ab27d25f193768a2c",
"reference": "f0bc15012e05cc0b9dde012ab27d25f193768a2c",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/7ea91e0ceea7b94293612fea94022b73315677c2",
"reference": "7ea91e0ceea7b94293612fea94022b73315677c2",
"shasum": ""
},
"require": {
@@ -1563,22 +1563,22 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.39.0"
"source": "https://github.com/utopia-php/audit/tree/0.39.1"
},
"time": "2024-03-06T21:20:37+00:00"
"time": "2024-06-05T19:28:22+00:00"
},
{
"name": "utopia-php/cache",
"version": "0.9.1",
"version": "0.10.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/cache.git",
"reference": "552b4c554bb14d0c529631ce304cdf4a2b9d06a6"
"reference": "87ee4fc91e50d4ddfef650aa999ea12be3a99583"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/552b4c554bb14d0c529631ce304cdf4a2b9d06a6",
"reference": "552b4c554bb14d0c529631ce304cdf4a2b9d06a6",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/87ee4fc91e50d4ddfef650aa999ea12be3a99583",
"reference": "87ee4fc91e50d4ddfef650aa999ea12be3a99583",
"shasum": ""
},
"require": {
@@ -1613,9 +1613,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/cache/issues",
"source": "https://github.com/utopia-php/cache/tree/0.9.1"
"source": "https://github.com/utopia-php/cache/tree/0.10.1"
},
"time": "2024-03-19T17:07:20+00:00"
"time": "2024-06-18T13:20:25+00:00"
},
{
"name": "utopia-php/cli",
@@ -1719,23 +1719,23 @@
},
{
"name": "utopia-php/database",
"version": "0.49.10",
"version": "0.49.13",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "216209121bc97a2010f67a39c561fafe1e936bec"
"reference": "fff42e0bd1db5a03d8c5df4302d72443bde3b860"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/216209121bc97a2010f67a39c561fafe1e936bec",
"reference": "216209121bc97a2010f67a39c561fafe1e936bec",
"url": "https://api.github.com/repos/utopia-php/database/zipball/fff42e0bd1db5a03d8c5df4302d72443bde3b860",
"reference": "fff42e0bd1db5a03d8c5df4302d72443bde3b860",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/cache": "0.9.*",
"utopia-php/cache": "0.10.*",
"utopia-php/framework": "0.33.*",
"utopia-php/mongo": "0.3.*"
},
@@ -1769,9 +1769,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.49.10"
"source": "https://github.com/utopia-php/database/tree/0.49.13"
},
"time": "2024-05-20T02:14:20+00:00"
"time": "2024-06-18T14:33:55+00:00"
},
{
"name": "utopia-php/domains",
@@ -2119,16 +2119,16 @@
},
{
"name": "utopia-php/messaging",
"version": "0.11.0",
"version": "0.12.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
"reference": "b499c3ad11af711c28252c62d83f24e6106a2154"
"reference": "6e466d3511981291843c6ebf9ce3f44fc75e37b0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/b499c3ad11af711c28252c62d83f24e6106a2154",
"reference": "b499c3ad11af711c28252c62d83f24e6106a2154",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/6e466d3511981291843c6ebf9ce3f44fc75e37b0",
"reference": "6e466d3511981291843c6ebf9ce3f44fc75e37b0",
"shasum": ""
},
"require": {
@@ -2164,9 +2164,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/messaging/issues",
"source": "https://github.com/utopia-php/messaging/tree/0.11.0"
"source": "https://github.com/utopia-php/messaging/tree/0.12.0"
},
"time": "2024-05-08T17:10:02+00:00"
"time": "2024-05-30T14:58:25+00:00"
},
{
"name": "utopia-php/migration",
@@ -2327,16 +2327,16 @@
},
{
"name": "utopia-php/platform",
"version": "0.5.2",
"version": "0.7.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/platform.git",
"reference": "b9feabc79b92dc2b05683a986ad43bce5c1583e3"
"reference": "beeea0f2c9bce14a6869fc5c87a1047cdecb5c52"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/b9feabc79b92dc2b05683a986ad43bce5c1583e3",
"reference": "b9feabc79b92dc2b05683a986ad43bce5c1583e3",
"url": "https://api.github.com/repos/utopia-php/platform/zipball/beeea0f2c9bce14a6869fc5c87a1047cdecb5c52",
"reference": "beeea0f2c9bce14a6869fc5c87a1047cdecb5c52",
"shasum": ""
},
"require": {
@@ -2344,7 +2344,8 @@
"ext-redis": "*",
"php": ">=8.0",
"utopia-php/cli": "0.15.*",
"utopia-php/framework": "0.33.*"
"utopia-php/framework": "0.33.*",
"utopia-php/queue": "0.7.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
@@ -2370,9 +2371,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/platform/issues",
"source": "https://github.com/utopia-php/platform/tree/0.5.2"
"source": "https://github.com/utopia-php/platform/tree/0.7.0"
},
"time": "2024-05-22T12:50:35+00:00"
"time": "2024-05-08T17:00:55+00:00"
},
{
"name": "utopia-php/pools",
@@ -2755,22 +2756,22 @@
},
{
"name": "utopia-php/vcs",
"version": "0.6.6",
"version": "0.6.7",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/vcs.git",
"reference": "e538264cfee5e3efdfe1771efba04750cf20b2c4"
"reference": "8d8ff1ac68e991b95adb6f91fcde8f9bb8f24974"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/e538264cfee5e3efdfe1771efba04750cf20b2c4",
"reference": "e538264cfee5e3efdfe1771efba04750cf20b2c4",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/8d8ff1ac68e991b95adb6f91fcde8f9bb8f24974",
"reference": "8d8ff1ac68e991b95adb6f91fcde8f9bb8f24974",
"shasum": ""
},
"require": {
"adhocore/jwt": "^1.1",
"php": ">=8.0",
"utopia-php/cache": "^0.9.0",
"utopia-php/cache": "^0.10.0",
"utopia-php/framework": "0.*.*"
},
"require-dev": {
@@ -2798,9 +2799,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/vcs/issues",
"source": "https://github.com/utopia-php/vcs/tree/0.6.6"
"source": "https://github.com/utopia-php/vcs/tree/0.6.7"
},
"time": "2024-05-17T09:36:30+00:00"
"time": "2024-06-05T17:38:29+00:00"
},
{
"name": "utopia-php/websocket",
@@ -2987,16 +2988,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.38.6",
"version": "0.38.7",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "d7016d6d72545e84709892faca972eb4bf5bd699"
"reference": "0a66c1149ef05ed9f45ce1c897c4a0ce9ee5e95a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/d7016d6d72545e84709892faca972eb4bf5bd699",
"reference": "d7016d6d72545e84709892faca972eb4bf5bd699",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/0a66c1149ef05ed9f45ce1c897c4a0ce9ee5e95a",
"reference": "0a66c1149ef05ed9f45ce1c897c4a0ce9ee5e95a",
"shasum": ""
},
"require": {
@@ -3032,9 +3033,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.38.6"
"source": "https://github.com/appwrite/sdk-generator/tree/0.38.7"
},
"time": "2024-05-20T18:00:16+00:00"
"time": "2024-06-10T00:23:02+00:00"
},
{
"name": "doctrine/deprecations",
@@ -3345,16 +3346,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.11.1",
"version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
"shasum": ""
},
"require": {
@@ -3362,11 +3363,12 @@
},
"conflict": {
"doctrine/collections": "<1.6.8",
"doctrine/common": "<2.13.3 || >=3,<3.2.2"
"doctrine/common": "<2.13.3 || >=3 <3.2.2"
},
"require-dev": {
"doctrine/collections": "^1.6.8",
"doctrine/common": "^2.13.3 || ^3.2.2",
"phpspec/prophecy": "^1.10",
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
},
"type": "library",
@@ -3392,7 +3394,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
},
"funding": [
{
@@ -3400,7 +3402,7 @@
"type": "tidelift"
}
],
"time": "2023-03-08T13:26:56+00:00"
"time": "2024-06-12T14:39:25+00:00"
},
{
"name": "nikic/php-parser",
@@ -3824,16 +3826,16 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.29.0",
"version": "1.29.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc"
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc",
"reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4",
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4",
"shasum": ""
},
"require": {
@@ -3865,9 +3867,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1"
},
"time": "2024-05-06T12:04:23+00:00"
"time": "2024-05-31T08:52:43+00:00"
},
{
"name": "phpunit/php-code-coverage",
+18 -22
View File
@@ -189,6 +189,7 @@ services:
- _APP_CONSOLE_COUNTRIES_DENYLIST
- _APP_EXPERIMENT_LOGGING_PROVIDER
- _APP_EXPERIMENT_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
appwrite-realtime:
entrypoint: realtime
@@ -238,6 +239,7 @@ services:
- _APP_USAGE_STATS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-audits:
entrypoint: worker-audits
@@ -267,6 +269,7 @@ services:
- _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-webhooks:
entrypoint: worker-webhooks
@@ -299,6 +302,7 @@ services:
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_WEBHOOK_MAX_FAILED_ATTEMPTS
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-deletes:
entrypoint: worker-deletes
@@ -356,6 +360,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_EXECUTOR_SECRET
- _APP_EXECUTOR_HOST
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-databases:
entrypoint: worker-databases
@@ -387,6 +392,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_WORKERS_NUM
- _APP_QUEUE_NAME
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-builds:
entrypoint: worker-builds
@@ -452,6 +458,7 @@ services:
- _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-certificates:
entrypoint: worker-certificates
@@ -487,6 +494,7 @@ services:
- _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-functions:
entrypoint: worker-functions
@@ -526,6 +534,7 @@ services:
- _APP_DOCKER_HUB_PASSWORD
- _APP_LOGGING_CONFIG
- _APP_LOGGING_PROVIDER
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-mails:
entrypoint: worker-mails
@@ -560,6 +569,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_DOMAIN
- _APP_OPTIONS_FORCE_HTTPS
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-messaging:
entrypoint: worker-messaging
@@ -614,6 +624,7 @@ services:
- _APP_STORAGE_WASABI_SECRET
- _APP_STORAGE_WASABI_REGION
- _APP_STORAGE_WASABI_BUCKET
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-migrations:
entrypoint: worker-migrations
@@ -649,6 +660,7 @@ services:
- _APP_LOGGING_CONFIG
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- _APP_DATABASE_SHARED_TABLES
appwrite-task-maintenance:
entrypoint: maintenance
@@ -686,6 +698,7 @@ services:
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
- _APP_MAINTENANCE_DELAY
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-usage:
entrypoint: worker-usage
@@ -717,6 +730,7 @@ services:
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-usage-dump:
entrypoint: worker-usage-dump
@@ -748,6 +762,7 @@ services:
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
appwrite-task-scheduler-functions:
entrypoint: schedule-functions
@@ -775,6 +790,7 @@ services:
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DATABASE_SHARED_TABLES
appwrite-task-scheduler-messages:
entrypoint: schedule-messages
@@ -802,6 +818,7 @@ services:
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DATABASE_SHARED_TABLES
appwrite-assistant:
container_name: appwrite-assistant
@@ -900,20 +917,7 @@ services:
- MYSQL_USER=${_APP_DB_USER}
- MYSQL_PASSWORD=${_APP_DB_PASS}
- MARIADB_AUTO_UPGRADE=1
command: "mysqld --innodb-flush-method=fsync" # add ' --query_cache_size=0' for DB tests
# command: mv /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile0.bu && mv /var/lib/mysql/ib_logfile1 /var/lib/mysql/ib_logfile1.bu
# smtp:
# image: appwrite/smtp:1.2.0
# container_name: appwrite-smtp
# restart: unless-stopped
# networks:
# - appwrite
# environment:
# - LOCAL_DOMAINS=@
# - RELAY_FROM_HOSTS=192.168.0.0/16 ; *.yourdomain.com
# - SMARTHOST_HOST=smtp
# - SMARTHOST_PORT=587
command: "mysqld --innodb-flush-method=fsync"
redis:
image: redis:7.2.4-alpine
@@ -931,14 +935,6 @@ services:
volumes:
- appwrite-redis:/data:rw
# clamav:
# image: appwrite/clamav:1.2.0
# container_name: appwrite-clamav
# networks:
# - appwrite
# volumes:
# - appwrite-uploads:/storage/uploads
# Dev Tools Start ------------------------------------------------------------------------------------------
#
# The Appwrite Team uses the following tools to help debug, monitor and diagnose the Appwrite stack
@@ -1 +1 @@
Verify an authenticator app after adding it using the [add authenticator](/docs/references/cloud/client-web/account#createMfaAuthenticator) method. add
Verify an authenticator app after adding it using the [add authenticator](/docs/references/cloud/client-web/account#createMfaAuthenticator) method.
+2 -4
View File
@@ -2,15 +2,13 @@
namespace Appwrite\Platform;
use Appwrite\Platform\Services\Tasks;
use Appwrite\Platform\Services\Workers;
use Appwrite\Platform\Modules\Core;
use Utopia\Platform\Platform;
class Appwrite extends Platform
{
public function __construct()
{
$this->addService('tasks', new Tasks());
$this->addService('workers', new Workers());
parent::__construct(new Core());
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace Appwrite\Platform\Modules;
use Appwrite\Platform\Services\Tasks;
use Appwrite\Platform\Services\Workers;
use Utopia\Platform\Module;
class Core extends Module
{
public function __construct()
{
$this->addService('tasks', new Tasks());
$this->addService('workers', new Workers());
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ class Tasks extends Service
{
public function __construct()
{
$this->type = self::TYPE_CLI;
$this->type = Service::TYPE_TASK;
$this
->addAction(Doctor::getName(), new Doctor())
->addAction(Install::getName(), new Install())
+1 -1
View File
@@ -20,7 +20,7 @@ class Workers extends Service
{
public function __construct()
{
$this->type = self::TYPE_WORKER;
$this->type = Service::TYPE_WORKER;
$this
->addAction(Audits::getName(), new Audits())
->addAction(Builds::getName(), new Builds())
+3 -3
View File
@@ -498,14 +498,14 @@ class Deletes extends Action
$collections = $dbForProject->listCollections($limit);
foreach ($collections as $collection) {
if ($dsn->getHost() !== DATABASE_SHARED_TABLES || !\in_array($collection->getId(), $projectCollectionIds)) {
if ($dsn->getHost() !== System::getEnv('_APP_DATABASE_SHARED_TABLES', '') || !\in_array($collection->getId(), $projectCollectionIds)) {
$dbForProject->deleteCollection($collection->getId());
} else {
$this->deleteByGroup($collection->getId(), [], database: $dbForProject);
}
}
if ($dsn->getHost() === DATABASE_SHARED_TABLES) {
if ($dsn->getHost() === System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$collectionsIds = \array_map(fn ($collection) => $collection->getId(), $collections);
if (empty(\array_diff($collectionsIds, $projectCollectionIds))) {
@@ -554,7 +554,7 @@ class Deletes extends Action
], $dbForConsole);
// Delete metadata table
if ($dsn->getHost() !== DATABASE_SHARED_TABLES) {
if ($dsn->getHost() !== System::getEnv('_APP_DATABASE_SHARED_TABLES', '')) {
$dbForProject->deleteCollection('_metadata');
} else {
$this->deleteByGroup('_metadata', [], $dbForProject);
+13 -5
View File
@@ -399,7 +399,10 @@ class Messaging extends Action
'credentials' => match ($host) {
'twilio' => [
'accountSid' => $user,
'authToken' => $password
'authToken' => $password,
// Twilio Messaging Service SIDs always start with MG
// https://www.twilio.com/docs/messaging/services
'messagingServiceSid' => \str_starts_with($from, 'MG') ? $from : null
],
'textmagic' => [
'username' => $user,
@@ -420,9 +423,14 @@ class Messaging extends Action
],
default => null
},
'options' => [
'from' => $from
]
'options' => match ($host) {
'twilio' => [
'from' => \str_starts_with($from, 'MG') ? null : $from
],
default => [
'from' => $from
]
}
]);
$adapter = $this->getSmsAdapter($provider);
@@ -465,7 +473,7 @@ class Messaging extends Action
return match ($provider->getAttribute('provider')) {
'mock' => new Mock('username', 'password'),
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']),
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken'], null, isset($credentials['messagingServiceSid']) ? $credentials['messagingServiceSid'] : null),
'textmagic' => new TextMagic($credentials['username'], $credentials['apiKey']),
'telesign' => new Telesign($credentials['customerId'], $credentials['apiKey']),
'msg91' => new Msg91($credentials['senderId'], $credentials['authKey'], $credentials['templateId']),
+1 -1
View File
@@ -31,7 +31,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-Appwrite-Timeout, X-Appwrite-Shared-Tables, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent', $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-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent', $response['headers']['access-control-allow-headers']);
$this->assertEquals('X-Appwrite-Session, 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']);
@@ -4754,6 +4754,8 @@ trait DatabasesBase
$this->assertEquals($longtext['headers']['status-code'], 202);
$text = file_get_contents(__DIR__ . '/../../../resources/longtext.txt');
for ($i = 0; $i < 1; $i++) {
$this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
'content-type' => 'application/json',
@@ -4761,7 +4763,7 @@ trait DatabasesBase
], $this->getHeaders()), [
'documentId' => ID::unique(),
'data' => [
'longtext' => file_get_contents(__DIR__ . '/../../../resources/longtext.txt'),
'longtext' => $text . $text,
],
'permissions' => [
Permission::read(Role::user($this->getUser()['$id'])),
@@ -2,6 +2,7 @@
namespace Tests\E2E\Services\Functions;
use Appwrite\Tests\Retry;
use CURLFile;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
@@ -42,6 +43,7 @@ class FunctionsCustomClientTest extends Scope
return [];
}
#[Retry(count: 2)]
public function testCreateExecution(): array
{
/**
@@ -988,7 +988,7 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals($executions['body']['executions'][0]['logs'], '');
$this->assertStringContainsString('timed out', $executions['body']['executions'][0]['errors']);
sleep(70); //wait for scheduled execution to be created and time out
sleep(75); // Wait for scheduled execution to be created and time out
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', array_merge([
'content-type' => 'application/json',
@@ -999,12 +999,6 @@ class FunctionsCustomServerTest extends Scope
$this->assertCount(2, $executions['body']['executions']);
$this->assertIsArray($executions['body']['executions']);
$this->assertEquals($executions['body']['executions'][1]['trigger'], 'schedule');
$this->assertEquals($executions['body']['executions'][1]['status'], 'failed');
$this->assertEquals($executions['body']['executions'][1]['responseStatusCode'], 500);
$this->assertLessThan(20, $executions['body']['executions'][1]['duration']);
$this->assertEquals($executions['body']['executions'][1]['responseBody'], '');
$this->assertEquals($executions['body']['executions'][1]['logs'], '');
$this->assertStringContainsString('timed out', $executions['body']['executions'][1]['errors']);
// Cleanup : Delete function
$response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
@@ -9,7 +9,6 @@ use Tests\E2E\General\UsageTest;
use Tests\E2E\Scopes\ProjectConsole;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideClient;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
@@ -3494,504 +3493,4 @@ class ProjectsConsoleClientTest extends Scope
return $data;
}
public function testTenantIsolation(): void
{
// Create a team and a project
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Amazing Team',
]);
$teamId = $team['body']['$id'];
// Project-level isolation
$project1 = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-shared-tables' => false
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Amazing Project',
'teamId' => $teamId,
'region' => 'default'
]);
// Application level isolation (shared tables)
$project2 = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-shared-tables' => true
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Amazing Project',
'teamId' => $teamId,
'region' => 'default'
]);
// Project-level isolation
$project3 = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-shared-tables' => false
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Amazing Project',
'teamId' => $teamId,
'region' => 'default'
]);
// Application level isolation (shared tables)
$project4 = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-shared-tables' => true
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Amazing Project',
'teamId' => $teamId,
'region' => 'default'
]);
// Create and API key in each project
$key1 = $this->client->call(Client::METHOD_POST, '/projects/' . $project1['body']['$id'] . '/keys', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Key Test',
'scopes' => ['databases.read', 'databases.write', 'collections.read', 'collections.write', 'attributes.read', 'attributes.write', 'indexes.read', 'indexes.write', 'documents.read', 'documents.write', 'users.read', 'users.write'],
]);
$key2 = $this->client->call(Client::METHOD_POST, '/projects/' . $project2['body']['$id'] . '/keys', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Key Test',
'scopes' => ['databases.read', 'databases.write', 'collections.read', 'collections.write', 'attributes.read', 'attributes.write', 'indexes.read', 'indexes.write', 'documents.read', 'documents.write', 'users.read', 'users.write'],
]);
$key3 = $this->client->call(Client::METHOD_POST, '/projects/' . $project3['body']['$id'] . '/keys', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Key Test',
'scopes' => ['databases.read', 'databases.write', 'collections.read', 'collections.write', 'attributes.read', 'attributes.write', 'indexes.read', 'indexes.write', 'documents.read', 'documents.write', 'users.read', 'users.write'],
]);
$key4 = $this->client->call(Client::METHOD_POST, '/projects/' . $project4['body']['$id'] . '/keys', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Key Test',
'scopes' => ['databases.read', 'databases.write', 'collections.read', 'collections.write', 'attributes.read', 'attributes.write', 'indexes.read', 'indexes.write', 'documents.read', 'documents.write', 'users.read', 'users.write'],
]);
// Create a database in each project
$database1 = $this->client->call(Client::METHOD_POST, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
], [
'databaseId' => ID::unique(),
'name' => 'Amazing Database',
]);
$database2 = $this->client->call(Client::METHOD_POST, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
], [
'databaseId' => ID::unique(),
'name' => 'Amazing Database',
]);
$database3 = $this->client->call(Client::METHOD_POST, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
], [
'databaseId' => ID::unique(),
'name' => 'Amazing Database',
]);
$database4 = $this->client->call(Client::METHOD_POST, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
], [
'databaseId' => ID::unique(),
'name' => 'Amazing Database',
]);
// Create a collection in each project
$collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $database1['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
], [
'databaseId' => $database1['body']['$id'],
'collectionId' => ID::unique(),
'name' => 'Amazing Collection',
]);
$collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $database2['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
], [
'databaseId' => $database2['body']['$id'],
'collectionId' => ID::unique(),
'name' => 'Amazing Collection',
]);
$collection3 = $this->client->call(Client::METHOD_POST, '/databases/' . $database3['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
], [
'databaseId' => $database3['body']['$id'],
'collectionId' => ID::unique(),
'name' => 'Amazing Collection',
]);
$collection4 = $this->client->call(Client::METHOD_POST, '/databases/' . $database4['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
], [
'databaseId' => $database4['body']['$id'],
'collectionId' => ID::unique(),
'name' => 'Amazing Collection',
]);
// Create an attribute in each project
$attribute1 = $this->client->call(Client::METHOD_POST, '/databases/' . $database1['body']['$id'] . '/collections/' . $collection1['body']['$id'] . '/attributes/string', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
], [
'databaseId' => $database1['body']['$id'],
'collectionId' => $collection1['body']['$id'],
'key' => ID::unique(),
'size' => 255,
'required' => true
]);
$attribute2 = $this->client->call(Client::METHOD_POST, '/databases/' . $database2['body']['$id'] . '/collections/' . $collection2['body']['$id'] . '/attributes/string', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
], [
'databaseId' => $database2['body']['$id'],
'collectionId' => $collection2['body']['$id'],
'key' => ID::unique(),
'size' => 255,
'required' => true
]);
$attribute3 = $this->client->call(Client::METHOD_POST, '/databases/' . $database3['body']['$id'] . '/collections/' . $collection3['body']['$id'] . '/attributes/string', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
], [
'databaseId' => $database3['body']['$id'],
'collectionId' => $collection3['body']['$id'],
'key' => ID::unique(),
'size' => 255,
'required' => true
]);
$attribute4 = $this->client->call(Client::METHOD_POST, '/databases/' . $database4['body']['$id'] . '/collections/' . $collection4['body']['$id'] . '/attributes/string', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
], [
'databaseId' => $database4['body']['$id'],
'collectionId' => $collection4['body']['$id'],
'key' => ID::unique(),
'size' => 255,
'required' => true
]);
// Wait for attributes
\sleep(2);
// Create an index in each project
$index1 = $this->client->call(Client::METHOD_POST, '/databases/' . $database1['body']['$id'] . '/collections/' . $collection1['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
], [
'databaseId' => $database1['body']['$id'],
'collectionId' => $collection1['body']['$id'],
'key' => ID::unique(),
'type' => Database::INDEX_KEY,
'attributes' => [$attribute1['body']['key']],
]);
$index2 = $this->client->call(Client::METHOD_POST, '/databases/' . $database2['body']['$id'] . '/collections/' . $collection2['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
], [
'databaseId' => $database2['body']['$id'],
'collectionId' => $collection2['body']['$id'],
'key' => ID::unique(),
'type' => Database::INDEX_KEY,
'attributes' => [$attribute2['body']['key']],
]);
$index3 = $this->client->call(Client::METHOD_POST, '/databases/' . $database3['body']['$id'] . '/collections/' . $collection3['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
], [
'databaseId' => $database3['body']['$id'],
'collectionId' => $collection3['body']['$id'],
'key' => ID::unique(),
'type' => Database::INDEX_KEY,
'attributes' => [$attribute3['body']['key']],
]);
$index4 = $this->client->call(Client::METHOD_POST, '/databases/' . $database4['body']['$id'] . '/collections/' . $collection4['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
], [
'databaseId' => $database4['body']['$id'],
'collectionId' => $collection4['body']['$id'],
'key' => ID::unique(),
'type' => Database::INDEX_KEY,
'attributes' => [$attribute4['body']['key']],
]);
// Wait for indexes
\sleep(2);
// Assert that each project has only 1 database, 1 collection, 1 attribute and 1 index
$databasesProject1 = $this->client->call(Client::METHOD_GET, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
]);
$this->assertEquals(1, $databasesProject1['body']['total']);
$this->assertEquals(1, \count($databasesProject1['body']['databases']));
$databasesProject2 = $this->client->call(Client::METHOD_GET, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
]);
$this->assertEquals(1, $databasesProject2['body']['total']);
$this->assertEquals(1, \count($databasesProject2['body']['databases']));
$databasesProject3 = $this->client->call(Client::METHOD_GET, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
]);
$this->assertEquals(1, $databasesProject3['body']['total']);
$this->assertEquals(1, \count($databasesProject3['body']['databases']));
$databasesProject4 = $this->client->call(Client::METHOD_GET, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
]);
$this->assertEquals(1, $databasesProject4['body']['total']);
$this->assertEquals(1, \count($databasesProject4['body']['databases']));
$collectionsProject1 = $this->client->call(Client::METHOD_GET, '/databases/' . $database1['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
]);
$this->assertEquals(1, $collectionsProject1['body']['total']);
$this->assertEquals(1, \count($collectionsProject1['body']['collections']));
$collectionsProject2 = $this->client->call(Client::METHOD_GET, '/databases/' . $database2['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
]);
$this->assertEquals(1, $collectionsProject2['body']['total']);
$this->assertEquals(1, \count($collectionsProject2['body']['collections']));
$collectionsProject3 = $this->client->call(Client::METHOD_GET, '/databases/' . $database3['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
]);
$this->assertEquals(1, $collectionsProject3['body']['total']);
$this->assertEquals(1, \count($collectionsProject3['body']['collections']));
$collectionsProject4 = $this->client->call(Client::METHOD_GET, '/databases/' . $database4['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
]);
$this->assertEquals(1, $collectionsProject4['body']['total']);
$this->assertEquals(1, \count($collectionsProject4['body']['collections']));
$attributesProject1 = $this->client->call(Client::METHOD_GET, '/databases/' . $database1['body']['$id'] . '/collections/' . $collection1['body']['$id'] . '/attributes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
]);
$this->assertEquals(1, $attributesProject1['body']['total']);
$this->assertEquals(1, \count($attributesProject1['body']['attributes']));
$this->assertEquals('available', $attributesProject1['body']['attributes'][0]['status']);
$attributesProject2 = $this->client->call(Client::METHOD_GET, '/databases/' . $database2['body']['$id'] . '/collections/' . $collection2['body']['$id'] . '/attributes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
]);
$this->assertEquals(1, $attributesProject2['body']['total']);
$this->assertEquals(1, \count($attributesProject2['body']['attributes']));
$this->assertEquals('available', $attributesProject2['body']['attributes'][0]['status']);
$attributesProject3 = $this->client->call(Client::METHOD_GET, '/databases/' . $database3['body']['$id'] . '/collections/' . $collection3['body']['$id'] . '/attributes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
]);
$this->assertEquals(1, $attributesProject3['body']['total']);
$this->assertEquals(1, \count($attributesProject3['body']['attributes']));
$this->assertEquals('available', $attributesProject3['body']['attributes'][0]['status']);
$attributesProject4 = $this->client->call(Client::METHOD_GET, '/databases/' . $database4['body']['$id'] . '/collections/' . $collection4['body']['$id'] . '/attributes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
]);
$this->assertEquals(1, $attributesProject4['body']['total']);
$this->assertEquals(1, \count($attributesProject4['body']['attributes']));
$this->assertEquals('available', $attributesProject4['body']['attributes'][0]['status']);
$indexesProject1 = $this->client->call(Client::METHOD_GET, '/databases/' . $database1['body']['$id'] . '/collections/' . $collection1['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
]);
$this->assertEquals(1, $indexesProject1['body']['total']);
$this->assertEquals(1, \count($indexesProject1['body']['indexes']));
$indexesProject2 = $this->client->call(Client::METHOD_GET, '/databases/' . $database2['body']['$id'] . '/collections/' . $collection2['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
]);
$this->assertEquals(1, $indexesProject2['body']['total']);
$this->assertEquals(1, \count($indexesProject2['body']['indexes']));
$indexesProject3 = $this->client->call(Client::METHOD_GET, '/databases/' . $database3['body']['$id'] . '/collections/' . $collection3['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
]);
$this->assertEquals(1, $indexesProject3['body']['total']);
$this->assertEquals(1, \count($indexesProject3['body']['indexes']));
$indexesProject4 = $this->client->call(Client::METHOD_GET, '/databases/' . $database4['body']['$id'] . '/collections/' . $collection4['body']['$id'] . '/indexes', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
]);
$this->assertEquals(1, $indexesProject4['body']['total']);
$this->assertEquals(1, \count($indexesProject4['body']['indexes']));
// Attempt to read cross-type resources
$collectionProject2WithProject1Key = $this->client->call(Client::METHOD_GET, '/databases/' . $database2['body']['$id'] . '/collections/' . $collection2['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
]);
$this->assertEquals(404, $collectionProject2WithProject1Key['headers']['status-code']);
$collectionProject1WithProject2Key = $this->client->call(Client::METHOD_GET, '/databases/' . $database1['body']['$id'] . '/collections/' . $collection1['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
]);
$this->assertEquals(404, $collectionProject1WithProject2Key['headers']['status-code']);
// Attempt to read cross-tenant resources
$collectionProject3WithProject1Key = $this->client->call(Client::METHOD_GET, '/databases/' . $database3['body']['$id'] . '/collections/' . $collection3['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $project1['body']['$id'],
'x-appwrite-key' => $key1['body']['secret']
]);
$this->assertEquals(404, $collectionProject3WithProject1Key['headers']['status-code']);
$collectionProject1WithProject3Key = $this->client->call(Client::METHOD_GET, '/databases/' . $database1['body']['$id'] . '/collections/' . $collection1['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $project3['body']['$id'],
'x-appwrite-key' => $key3['body']['secret']
]);
$this->assertEquals(404, $collectionProject1WithProject3Key['headers']['status-code']);
// Assert that shared project resources can have the same ID as they're unique on tenant + ID not just ID
$collection5 = $this->client->call(Client::METHOD_POST, '/databases/' . $database2['body']['$id'] . '/collections', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
], [
'databaseId' => $database2['body']['$id'],
'collectionId' => $collection4['body']['$id'],
'name' => 'Amazing Collection',
]);
$this->assertEquals(201, $collection5['headers']['status-code']);
// Assert that users across projects on shared tables can have the same email as they're unique on tenant + email not just email
$user1 = $this->client->call(Client::METHOD_POST, '/users', [
'content-type' => 'application/json',
'x-appwrite-project' => $project2['body']['$id'],
'x-appwrite-key' => $key2['body']['secret']
], [
'userId' => 'user',
'email' => 'test@appwrite.io',
'password' => 'password',
'name' => 'Test User',
]);
$this->assertEquals(201, $user1['headers']['status-code']);
$user2 = $this->client->call(Client::METHOD_POST, '/users', [
'content-type' => 'application/json',
'x-appwrite-project' => $project4['body']['$id'],
'x-appwrite-key' => $key4['body']['secret']
], [
'userId' => 'user',
'email' => 'test@appwrite.io',
'password' => 'password',
'name' => 'Test User',
]);
$this->assertEquals(201, $user2['headers']['status-code']);
}
}
+1 -1
View File
@@ -225,7 +225,7 @@ trait StorageBase
'bucketId' => ID::unique(),
'name' => 'Test Bucket 2',
'fileSecurity' => true,
'maximumFileSize' => 200000000, //200MB
'maximumFileSize' => 6000000000, //6GB
'allowedFileExtensions' => ["jpg", "png"],
'permissions' => [
Permission::read(Role::any()),
+1 -1
View File
@@ -986,7 +986,7 @@ trait UsersBase
'password' => 'password'
]);
$this->assertEquals($session['headers']['status-code'], 401);
$this->assertEquals(401, $session['headers']['status-code']);
$user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/password', array_merge([
'content-type' => 'application/json',