diff --git a/Dockerfile b/Dockerfile index 2a3e176838..9736d29f74 100755 --- a/Dockerfile +++ b/Dockerfile @@ -41,6 +41,8 @@ COPY ./bin /usr/local/bin COPY ./docs /usr/src/code/docs COPY ./src /usr/src/code/src COPY ./dev /usr/src/code/dev +COPY ./mongo-init.js /usr/src/code/mongo-init.js +COPY ./mongo-entrypoint.sh /usr/src/code/mongo-entrypoint.sh # Set Volumes RUN mkdir -p /storage/uploads && \ diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 1e47364d03..4b717d5c0d 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -778,7 +778,6 @@ $dbService = $this->getParam('database'); - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_DB_ADAPTER - - _APP_DB_ADAPTER - _APP_DB_HOST - _APP_DB_PORT - _APP_DB_SCHEMA @@ -961,15 +960,16 @@ mariadb: mongodb: - image: mongo:latest + image: mongo:8.0.10 container_name: appwrite-mongodb <<: *x-logging networks: - appwrite volumes: - appwrite-mongodb:/data/db - # we need to run the mongo-init.js file to create the user and the database + - appwrite-mongodb-keyfile:/data/keyfile - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro + - ./mongo-entrypoint.sh:/mongo-entrypoint.sh:ro ports: - "27017:27017" environment: @@ -978,10 +978,20 @@ mariadb: - MONGO_INITDB_DATABASE=${_APP_DB_SCHEMA} - MONGO_INITDB_USERNAME=${_APP_DB_USER} - MONGO_INITDB_PASSWORD=${_APP_DB_PASS} + entrypoint: ["/bin/bash", "/mongo-entrypoint.sh"] healthcheck: - test: ["CMD", "mongosh", "--username", "root", "--password", "${_APP_DB_ROOT_PASS}", "--authenticationDatabase", "admin", "--eval", "db.adminCommand('ping')"] - interval: 1s - timeout: 5s + test: | + bash -c " + if mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval 'rs.status().ok' 2>/dev/null | grep -q 1; then + exit 0 + else + mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval \" + rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongodb:27017'}]}) + \" 2>/dev/null || exit 1 + fi + " + interval: 10s + timeout: 10s retries: 10 start_period: 30s @@ -1024,6 +1034,7 @@ volumes: appwrite-mariadb: appwrite-mongodb: + appwrite-mongodb-keyfile: appwrite-redis: appwrite-cache: diff --git a/composer.json b/composer.json index 19f2e1e81a..8b45b87fbb 100644 --- a/composer.json +++ b/composer.json @@ -91,7 +91,7 @@ }, "require-dev": { "ext-fileinfo": "*", - "appwrite/sdk-generator": "0.*.*", + "appwrite/sdk-generator": "*", "phpunit/phpunit": "9.*", "swoole/ide-helper": "5.1.2", "phpstan/phpstan": "1.8.*", diff --git a/composer.lock b/composer.lock index 78bca79454..875103b368 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "f0e24bac21a79de31c550b8f0ffa2405", + "content-hash": "d8c73d430473aac245545d3e27f1b45d", "packages": [ { "name": "adhocore/jwt", @@ -5274,16 +5274,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.41.31", + "version": "1.4.4", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "95d3dd7b925181acea89468e7f74e99b6832c3dc" + "reference": "a20b20cfd70a1879f0d0fb2b4f669aa5ed836c49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/95d3dd7b925181acea89468e7f74e99b6832c3dc", - "reference": "95d3dd7b925181acea89468e7f74e99b6832c3dc", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/a20b20cfd70a1879f0d0fb2b4f669aa5ed836c49", + "reference": "a20b20cfd70a1879f0d0fb2b4f669aa5ed836c49", "shasum": "" }, "require": { @@ -5319,9 +5319,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.41.31" + "source": "https://github.com/appwrite/sdk-generator/tree/1.4.4" }, - "time": "2025-08-19T18:03:34+00:00" + "time": "2025-10-13T09:20:49+00:00" }, { "name": "doctrine/annotations", diff --git a/mongo-entrypoint.sh b/mongo-entrypoint.sh index 7e136fa174..226b0777a4 100644 --- a/mongo-entrypoint.sh +++ b/mongo-entrypoint.sh @@ -14,4 +14,4 @@ chmod 400 "$KEYFILE_PATH" chown mongodb:mongodb "$KEYFILE_PATH" 2>/dev/null || chown 999:999 "$KEYFILE_PATH" # Use MongoDB's standard entrypoint with our command -exec docker-entrypoint.sh mongod --replSet rs0 --bind_ip_all --auth --keyFile "$KEYFILE_PATH" \ No newline at end of file +exec docker-entrypoint.sh mongod --replSet rs0 --bind_ip_all --auth --keyFile "$KEYFILE_PATH" diff --git a/mongo-init-replicaset.sh b/mongo-init-replicaset.sh index e6dbed8f60..f97689f073 100644 --- a/mongo-init-replicaset.sh +++ b/mongo-init-replicaset.sh @@ -48,4 +48,4 @@ if [ $COUNTER -eq $MAX_WAIT ]; then echo "MongoDB will continue initializing the replica set in the background" fi -echo "Replica set initialization complete!" \ No newline at end of file +echo "Replica set initialization complete!" diff --git a/mongo-keyfile b/mongo-keyfile index 47b0564520..554dbfee7a 100644 --- a/mongo-keyfile +++ b/mongo-keyfile @@ -13,4 +13,4 @@ x58DNwUQdegadSsyd2IPlWpUGIY1GJjTV+J9vEf79TQtnzYSFH5lmg3J08Cq64wg UAedRHUEnRHFlVfg4ZdkGTGL/2Q7l2Dk0jJQCFFq+tEFGncLgGlAJaWXkczaFaZy r9h12ulCUq6trZ1RGS1DlDxwQU2J6bSz0ZFwux/3W0YyIQyq4rWcoDjEG98DSE5n P3Qht2DsBjFkh55nfC0EgwXwnWzBTJiJo1GYf5RdEIVCmmWxmAfTfPYaKWOVcgGG -6QGX5TCPyI6+SZUT/qOfGxnIE/1R3N1wD+J1rORXwWucLOiR \ No newline at end of file +6QGX5TCPyI6+SZUT/qOfGxnIE/1R3N1wD+J1rORXwWucLOiR diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php index e48872aa7a..ccdc16032d 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Enum/Create.php @@ -61,9 +61,9 @@ class Create extends Action replaceWith: 'tablesDB.createEnumColumn', ), )) - ->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject']) - ->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject']) - ->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject']) + ->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', true, ['dbForProject']) + ->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', true, ['dbForProject']) + ->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', true, ['dbForProject']) ->param('elements', [], new ArrayList(new Text(Database::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of enum values.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php index 32e9920d23..19cd0bfd50 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Relationship/Update.php @@ -32,7 +32,8 @@ class Update extends Action { $this ->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH) - ->setHttpPath('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/relationship') + ->setHttpPath('/v1/databases/:databaseId/collections/:collectionId/attributes/relationship/:key') + ->httpAlias('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/relationship') ->desc('Update relationship attribute') ->groups(['api', 'database', 'schema']) ->label('scope', 'collections.write') diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php index c13becbad1..e52bd955a6 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php @@ -126,6 +126,7 @@ class XList extends Base } $this->applySelectQueries($request, $response, Response::MODEL_DEPLOYMENT); + $response->dynamic(new Document([ 'deployments' => $results, 'total' => $total, diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index c22c9585fd..1a269fecf7 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -231,6 +231,24 @@ class Install extends Action Console::exit(1); } + // Copy MongoDB initialization files for replica set setup + if ($database === 'mongodb') { + $mongoInitScript = __DIR__ . '/../../../../mongo-init.js'; + $mongoEntrypoint = __DIR__ . '/../../../../mongo-entrypoint.sh'; + + if (file_exists($mongoInitScript)) { + if (!copy($mongoInitScript, $this->path . '/mongo-init.js')) { + Console::warning('Failed to copy mongo-init.js'); + } + } + + if (file_exists($mongoEntrypoint)) { + if (!copy($mongoEntrypoint, $this->path . '/mongo-entrypoint.sh')) { + Console::warning('Failed to copy mongo-entrypoint.sh'); + } + } + } + $env = ''; $stdout = ''; $stderr = ''; diff --git a/tests/e2e/Services/Databases/Legacy/DatabasesBase.php b/tests/e2e/Services/Databases/Legacy/DatabasesBase.php index dc390aa7a8..5f7d203788 100644 --- a/tests/e2e/Services/Databases/Legacy/DatabasesBase.php +++ b/tests/e2e/Services/Databases/Legacy/DatabasesBase.php @@ -1510,6 +1510,7 @@ trait DatabasesBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]); + sleep(2); } $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [