From b800c5d224c0fab0c3edc7ddc2d1134bc75096f7 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 1 Mar 2022 10:38:17 +0100 Subject: [PATCH 1/4] fix: migration memberships --- src/Appwrite/Migration/Version/V12.php | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Appwrite/Migration/Version/V12.php b/src/Appwrite/Migration/Version/V12.php index 73177b61fb..15b8f33cf9 100644 --- a/src/Appwrite/Migration/Version/V12.php +++ b/src/Appwrite/Migration/Version/V12.php @@ -96,21 +96,42 @@ class V12 extends Migration switch ($id) { case 'sessions': try { + /** + * Rename providerToken to providerAccessToken + */ $this->projectDB->renameAttribute($id, 'providerToken', 'providerAccessToken'); } catch (\Throwable $th) { Console::warning("'providerAccessToken' from {$id}: {$th->getMessage()}"); } try { + /** + * Create providerRefreshToken + */ $this->projectDB->createAttribute(collection: $id, id: 'providerRefreshToken', type: Database::VAR_STRING, size: 16384, signed: true, required: true, filters: ['encrypt']); } catch (\Throwable $th) { Console::warning("'providerRefreshToken' from {$id}: {$th->getMessage()}"); } try { + /** + * Create providerAccessTokenExpiry + */ $this->projectDB->createAttribute(collection: $id, id: 'providerAccessTokenExpiry', type: Database::VAR_INTEGER, size: 0, required: true); } catch (\Throwable $th) { Console::warning("'providerAccessTokenExpiry' from {$id}: {$th->getMessage()}"); } break; + + case 'memberships': + try { + /** + * Add search attribute and index to memberships. + */ + $this->projectDB->createAttribute(collection: $id, id: 'search', type: Database::VAR_STRING, size: 16384, required: false); + $this->projectDB->createIndex(collection: $id, id: '_key_search', type: Database::INDEX_FULLTEXT, attributes: ['search']); + } catch (\Throwable $th) { + Console::warning("'search' from {$id}: {$th->getMessage()}"); + } + break; } usleep(100000); } @@ -254,6 +275,16 @@ class V12 extends Migration break; + case 'memberships': + /** + * Populate search string. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'userId'], $document)); + } + + break; + case 'sessions': $document ->setAttribute('providerRefreshToken', '') From 24b29b86f81eeb816dbfbd6e035b6c1484446142 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 1 Mar 2022 16:51:45 +0100 Subject: [PATCH 2/4] fix: dirty migration --- app/init.php | 2 +- composer.lock | 42 ++--- src/Appwrite/Migration/Version/V12.php | 248 ++++++++++++++++++++++++- 3 files changed, 269 insertions(+), 23 deletions(-) diff --git a/app/init.php b/app/init.php index eef3f2042a..86d3e3da81 100644 --- a/app/init.php +++ b/app/init.php @@ -71,7 +71,7 @@ const APP_LIMIT_ENCRYPTION = 20000000; //20MB const APP_LIMIT_COMPRESSION = 20000000; //20MB const APP_LIMIT_PREVIEW = 10000000; //10MB file size limit for preview endpoint const APP_CACHE_BUSTER = 201; -const APP_VERSION_STABLE = '0.12.3'; +const APP_VERSION_STABLE = '0.13.0'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_IP = 'ip'; diff --git a/composer.lock b/composer.lock index dcf61a0783..92706a98ff 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": "318c53aaac3cdfbdb728acc5e59b8057", + "content-hash": "b7919cd5b669605d051fadd3818523a7", "packages": [ { "name": "adhocore/jwt", @@ -2129,16 +2129,16 @@ }, { "name": "utopia-php/database", - "version": "0.15.1", + "version": "0.15.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "eb4f61ec40d697acdfd574638ecd075e4f44b864" + "reference": "4ae9f1162d6640ccfe28afa0bbc60b907a7ad1c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/eb4f61ec40d697acdfd574638ecd075e4f44b864", - "reference": "eb4f61ec40d697acdfd574638ecd075e4f44b864", + "url": "https://api.github.com/repos/utopia-php/database/zipball/4ae9f1162d6640ccfe28afa0bbc60b907a7ad1c0", + "reference": "4ae9f1162d6640ccfe28afa0bbc60b907a7ad1c0", "shasum": "" }, "require": { @@ -2186,9 +2186,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.15.1" + "source": "https://github.com/utopia-php/database/tree/0.15.2" }, - "time": "2022-02-22T09:33:37+00:00" + "time": "2022-02-28T15:53:37+00:00" }, { "name": "utopia-php/domains", @@ -3075,7 +3075,7 @@ "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator", - "reference": "4a43aa70c2f0b243edfc689f618a85f7d0817287" + "reference": "3af54e71d0088b72b3223efc511b77e254fb7a1d" }, "require": { "ext-curl": "*", @@ -3110,7 +3110,7 @@ } ], "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", - "time": "2022-02-22T10:51:55+00:00" + "time": "2022-03-01T09:53:31+00:00" }, { "name": "composer/pcre", @@ -4226,16 +4226,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.13", + "version": "9.2.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "deac8540cb7bd40b2b8cfa679b76202834fd04e8" + "reference": "9f4d60b6afe5546421462b76cd4e633ebc364ab4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/deac8540cb7bd40b2b8cfa679b76202834fd04e8", - "reference": "deac8540cb7bd40b2b8cfa679b76202834fd04e8", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f4d60b6afe5546421462b76cd4e633ebc364ab4", + "reference": "9f4d60b6afe5546421462b76cd4e633ebc364ab4", "shasum": "" }, "require": { @@ -4291,7 +4291,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.13" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.14" }, "funding": [ { @@ -4299,7 +4299,7 @@ "type": "github" } ], - "time": "2022-02-23T17:02:38+00:00" + "time": "2022-02-28T12:38:02+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5706,16 +5706,16 @@ }, { "name": "symfony/console", - "version": "v6.0.3", + "version": "v6.0.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "22e8efd019c3270c4f79376234a3f8752cd25490" + "reference": "3bebf4108b9e07492a2a4057d207aa5a77d146b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/22e8efd019c3270c4f79376234a3f8752cd25490", - "reference": "22e8efd019c3270c4f79376234a3f8752cd25490", + "url": "https://api.github.com/repos/symfony/console/zipball/3bebf4108b9e07492a2a4057d207aa5a77d146b1", + "reference": "3bebf4108b9e07492a2a4057d207aa5a77d146b1", "shasum": "" }, "require": { @@ -5781,7 +5781,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.0.3" + "source": "https://github.com/symfony/console/tree/v6.0.5" }, "funding": [ { @@ -5797,7 +5797,7 @@ "type": "tidelift" } ], - "time": "2022-01-26T17:23:29+00:00" + "time": "2022-02-25T10:48:52+00:00" }, { "name": "symfony/polyfill-intl-grapheme", diff --git a/src/Appwrite/Migration/Version/V12.php b/src/Appwrite/Migration/Version/V12.php index 15b8f33cf9..2825849758 100644 --- a/src/Appwrite/Migration/Version/V12.php +++ b/src/Appwrite/Migration/Version/V12.php @@ -3,9 +3,11 @@ namespace Appwrite\Migration\Version; use Appwrite\Migration\Migration; +use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Query; class V12 extends Migration { @@ -35,6 +37,7 @@ class V12 extends Migration Console::info('Migrating Permissions'); $this->fixPermissions(); Console::info('Migrating Collections'); + $this->migrateCustomCollections(); $this->fixCollections(); Console::info('Migrating Documents'); $this->forEachDocument([$this, 'fixDocument']); @@ -54,7 +57,7 @@ class V12 extends Migration * Remove empty generated Console Project. */ if ($this->consoleDB->getNamespace() === '_project_console' && $projectId === 'console') { - $all = []; + $all = ['_console_bucket_1', '_console_bucket_1_perms']; foreach ($this->collections as $collection) { $all[] = "_{$projectId}_{$collection['$id']}"; $all[] = "_{$projectId}_{$collection['$id']}_perms"; @@ -69,6 +72,9 @@ class V12 extends Migration */ foreach ($this->collections as $collection) { $id = $collection['$id']; + if (in_array($id, ['buckets', 'deployments', 'builds'])) { + continue; + } $this->pdo->prepare("ALTER TABLE IF EXISTS _project_{$projectId}_{$id} RENAME TO _{$projectId}_{$id}")->execute(); $this->pdo->prepare("CREATE TABLE IF NOT EXISTS _{$projectId}_{$id}_perms ( @@ -92,6 +98,10 @@ class V12 extends Migration { foreach ($this->collections as $collection) { $id = $collection['$id']; + + if (in_array($id, ['buckets', 'deployments', 'builds'])) { + continue; + } Console::log("- {$id}"); switch ($id) { case 'sessions': @@ -132,11 +142,219 @@ class V12 extends Migration Console::warning("'search' from {$id}: {$th->getMessage()}"); } break; + + case 'files': + /** + * Create bucket table if not exists. + */ + $this->createCollection('buckets'); + + if (!$this->projectDB->findOne('buckets', [new Query('$id', Query::TYPE_EQUAL, ['default'])])) { + $this->projectDB->createDocument('buckets', new Document([ + '$id' => 'default', + '$collection' => 'buckets', + 'dateCreated' => \time(), + 'dateUpdated' => \time(), + 'name' => 'Default', + 'permission' => 'file', + 'maximumFileSize' => (int) App::getEnv('_APP_STORAGE_LIMIT', 0), // 10MB + 'allowedFileExtensions' => [], + 'enabled' => true, + 'encryption' => true, + 'antivirus' => true, + '$read' => ['role:all'], + '$write' => ['role:all'], + 'search' => 'buckets Default', + ])); + $this->createCollection('files', 'bucket_1'); + $nextDocument = null; + $path = "/storage/uploads/app-{$this->project->getId()}"; + + /** + * Rename folder on volumes. + */ + if (is_dir("{$path}/")) { + mkdir("/storage/uploads/app-{$this->project->getId()}/default"); + + foreach (new \DirectoryIterator($path) as $fileinfo) { + if ($fileinfo->isDir() && !$fileinfo->isDot() && $fileinfo->getFilename() !== 'default') { + rename("{$path}/{$fileinfo->getFilename()}", "{$path}/default/{$fileinfo->getFilename()}"); + } + } + } + + do { + $documents = $this->projectDB->find('files', limit: $this->limit, cursor: $nextDocument); + $count = count($documents); + \Co\run(function (array $documents) { + foreach ($documents as $document) { + go(function (Document $document) { + $path = "/storage/uploads/app-{$this->project->getId()}"; + $new = str_replace($path, "{$path}/default", $document->getAttribute('path')); + $document + ->setAttribute('bucketId', 'default') + ->setAttribute('path', $new); + $this->projectDB->createDocument('bucket_1', $document); + }, $document); + } + }, $documents); + + if ($count !== $this->limit) { + $nextDocument = null; + } else { + $nextDocument = end($documents); + } + } while (!is_null($nextDocument)); + } + + break; + + case 'functions': + /** + * Create deployments table if not exists. + */ + $this->createCollection('deployments'); + + /** + * Create builds table if not exists. + */ + $this->createCollection('builds'); + + break; } usleep(100000); } } + protected function createCollection(string $id, string $name = null) + { + $name ??= $id; + + if (!$this->projectDB->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), $name)) { + $attributes = []; + $indexes = []; + $collection = $this->collections[$id]; + + foreach ($collection['attributes'] as $attribute) { + $attributes[] = new Document([ + '$id' => $attribute['$id'], + 'type' => $attribute['type'], + 'size' => $attribute['size'], + 'required' => $attribute['required'], + 'signed' => $attribute['signed'], + 'array' => $attribute['array'], + 'filters' => $attribute['filters'], + ]); + } + + foreach ($collection['indexes'] as $index) { + $indexes[] = new Document([ + '$id' => $index['$id'], + 'type' => $index['type'], + 'attributes' => $index['attributes'], + 'lengths' => $index['lengths'], + 'orders' => $index['orders'], + ]); + } + + try { + $this->projectDB->createCollection($name, $attributes, $indexes); + } catch (\Throwable $th) { + throw $th; + } + } + } + + protected function migrateCustomCollections() + { + $nextCollection = null; + + do { + $documents = $this->projectDB->find('collections', limit: $this->limit, cursor: $nextCollection); + $count = count($documents); + + \Co\run(function (array $documents) { + foreach ($documents as $document) { + go(function (Document $collection) { + $id = $collection->getId(); + $projectId = $this->project->getId(); + $internalId = $collection->getInternalId(); + $this->pdo->prepare("ALTER TABLE IF EXISTS _project_{$projectId}_collection_{$id} RENAME TO _{$projectId}_collection_{$internalId}")->execute(); + $this->pdo->prepare("CREATE TABLE IF NOT EXISTS _{$projectId}_collection_{$internalId}_perms ( + `_id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `_type` VARCHAR(12) NOT NULL, + `_permission` VARCHAR(255) NOT NULL, + `_document` VARCHAR(255) NOT NULL, + PRIMARY KEY (`_id`), + UNIQUE INDEX `_index1` (`_type`,`_document`,`_permission`), + INDEX `_index2` (`_permission`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")->execute(); + + $this->pdo->prepare("UPDATE _{$projectId}__metadata + SET + _uid = 'collection_{$internalId}', + name = 'collection_{$internalId}' + WHERE _uid = 'collection_{$id}'; + ")->execute(); + + + $nextDocument = null; + + do { + $documents = $this->projectDB->find('collection_' . $internalId, limit: $this->limit, cursor: $nextDocument); + $count = count($documents); + + foreach ($documents as $document) { + go(function (Document $document, string $internalId) { + $sql = "SELECT _read, _write FROM `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_collection_{$internalId}` WHERE _uid = {$this->pdo->quote($document->getid())}"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(); + + $permissions = $stmt->fetch(); + + $read = json_decode($permissions['_read'] ?? null) ?? []; + $write = json_decode($permissions['_write'] ?? null) ?? []; + + $permissions = []; + foreach ($read as $permission) { + $permissions[] = "('read', '{$permission}', '{$document->getId()}')"; + } + + foreach ($write as $permission) { + $permissions[] = "('write', '{$permission}', '{$document->getId()}')"; + } + + if (!empty($permissions)) { + $queryPermissions = "INSERT IGNORE INTO `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_collection_{$internalId}_perms` (_type, _permission, _document) VALUES " . implode(', ', $permissions); + $stmtPermissions = $this->pdo->prepare($queryPermissions); + $stmtPermissions->execute(); + } + }, $document, $internalId); + } + + if ($count !== $this->limit) { + $nextDocument = null; + } else { + $nextDocument = end($documents); + } + } while (!is_null($nextDocument)); + + $this->pdo->prepare(" + ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_collection_{$internalId}` + DROP COLUMN _read, + DROP COLUMN _write + ")->execute(); + }, $document); + } + }, $documents); + + if ($count !== $this->limit) { + $nextCollection = null; + } else { + $nextCollection = end($documents); + } + } while (!is_null($nextCollection)); + } /** * Migrate all Permission to new System with dedicated Table. * @return void @@ -146,6 +364,28 @@ class V12 extends Migration { foreach ($this->collections as $collection) { $id = $collection['$id']; + + if (in_array($id, ['buckets', 'deployments', 'builds'])) { + continue; + } + /** + * Check if permissions have already been migrated. + */ + try { + $stmtCheck = $this->pdo->prepare("SHOW COLUMNS from `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$id}` LIKE '_read'"); + $stmtCheck->execute(); + + if (empty($stmtCheck->fetchAll())) { + continue; + } + } catch (\Throwable $th) { + if ($th->getCode() === "42S02") { + continue; + } + throw $th; + } + + Console::log("- {$collection['$id']}"); $nextDocument = null; @@ -189,6 +429,12 @@ class V12 extends Migration $nextDocument = end($documents); } } while (!is_null($nextDocument)); + + $this->pdo->prepare(" + ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$id}` + DROP COLUMN _read, + DROP COLUMN _write + ")->execute(); } /** From a9ba7331c4836817652fe90a3d7a99a131601b8d Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 1 Mar 2022 17:30:19 +0100 Subject: [PATCH 3/4] fix: cleanup migration --- src/Appwrite/Migration/Version/V12.php | 182 ++++++++++++++----------- 1 file changed, 99 insertions(+), 83 deletions(-) diff --git a/src/Appwrite/Migration/Version/V12.php b/src/Appwrite/Migration/Version/V12.php index 2825849758..d05d9b26ee 100644 --- a/src/Appwrite/Migration/Version/V12.php +++ b/src/Appwrite/Migration/Version/V12.php @@ -167,12 +167,12 @@ class V12 extends Migration 'search' => 'buckets Default', ])); $this->createCollection('files', 'bucket_1'); - $nextDocument = null; - $path = "/storage/uploads/app-{$this->project->getId()}"; /** * Rename folder on volumes. */ + $path = "/storage/uploads/app-{$this->project->getId()}"; + if (is_dir("{$path}/")) { mkdir("/storage/uploads/app-{$this->project->getId()}/default"); @@ -182,34 +182,20 @@ class V12 extends Migration } } } - - do { - $documents = $this->projectDB->find('files', limit: $this->limit, cursor: $nextDocument); - $count = count($documents); - \Co\run(function (array $documents) { - foreach ($documents as $document) { - go(function (Document $document) { - $path = "/storage/uploads/app-{$this->project->getId()}"; - $new = str_replace($path, "{$path}/default", $document->getAttribute('path')); - $document - ->setAttribute('bucketId', 'default') - ->setAttribute('path', $new); - $this->projectDB->createDocument('bucket_1', $document); - }, $document); - } - }, $documents); - - if ($count !== $this->limit) { - $nextDocument = null; - } else { - $nextDocument = end($documents); - } - } while (!is_null($nextDocument)); } break; case 'functions': + try { + /** + * Rename tag to deployment + */ + $this->projectDB->renameAttribute($id, 'tag', 'deployment'); + } catch (\Throwable $th) { + Console::warning("'deployment' from {$id}: {$th->getMessage()}"); + } + /** * Create deployments table if not exists. */ @@ -226,7 +212,15 @@ class V12 extends Migration } } - protected function createCollection(string $id, string $name = null) + /** + * Creates colletion from the config collection. + * + * @param string $id + * @param string|null $name + * @return void + * @throws \Throwable + */ + protected function createCollection(string $id, string $name = null): void { $name ??= $id; @@ -265,7 +259,48 @@ class V12 extends Migration } } - protected function migrateCustomCollections() + /** + * + * @param \Utopia\Database\Document $document + * @param string $internalId + * @return void + * @throws \Exception + * @throws \PDOException + */ + protected function migratePermissionsToDedicatedTable(string $collection, Document $document): void + { + $sql = "SELECT _read, _write FROM `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$collection}` WHERE _uid = {$this->pdo->quote($document->getid())}"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(); + + $permissions = $stmt->fetch(); + + $read = json_decode($permissions['_read'] ?? null) ?? []; + $write = json_decode($permissions['_write'] ?? null) ?? []; + + $permissions = []; + foreach ($read as $permission) { + $permissions[] = "('read', '{$permission}', '{$document->getId()}')"; + } + + foreach ($write as $permission) { + $permissions[] = "('write', '{$permission}', '{$document->getId()}')"; + } + + if (!empty($permissions)) { + $queryPermissions = "INSERT IGNORE INTO `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$collection}_perms` (_type, _permission, _document) VALUES " . implode(', ', $permissions); + $stmtPermissions = $this->pdo->prepare($queryPermissions); + $stmtPermissions->execute(); + } + } + + /** + * Migrates all user's database collections. + * + * @return void + * @throws \Exception + */ + protected function migrateCustomCollections(): void { $nextCollection = null; @@ -279,6 +314,10 @@ class V12 extends Migration $id = $collection->getId(); $projectId = $this->project->getId(); $internalId = $collection->getInternalId(); + + /** + * Rename user's colletion table schema + */ $this->pdo->prepare("ALTER TABLE IF EXISTS _project_{$projectId}_collection_{$id} RENAME TO _{$projectId}_collection_{$internalId}")->execute(); $this->pdo->prepare("CREATE TABLE IF NOT EXISTS _{$projectId}_collection_{$internalId}_perms ( `_id` int(11) unsigned NOT NULL AUTO_INCREMENT, @@ -306,29 +345,7 @@ class V12 extends Migration foreach ($documents as $document) { go(function (Document $document, string $internalId) { - $sql = "SELECT _read, _write FROM `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_collection_{$internalId}` WHERE _uid = {$this->pdo->quote($document->getid())}"; - $stmt = $this->pdo->prepare($sql); - $stmt->execute(); - - $permissions = $stmt->fetch(); - - $read = json_decode($permissions['_read'] ?? null) ?? []; - $write = json_decode($permissions['_write'] ?? null) ?? []; - - $permissions = []; - foreach ($read as $permission) { - $permissions[] = "('read', '{$permission}', '{$document->getId()}')"; - } - - foreach ($write as $permission) { - $permissions[] = "('write', '{$permission}', '{$document->getId()}')"; - } - - if (!empty($permissions)) { - $queryPermissions = "INSERT IGNORE INTO `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_collection_{$internalId}_perms` (_type, _permission, _document) VALUES " . implode(', ', $permissions); - $stmtPermissions = $this->pdo->prepare($queryPermissions); - $stmtPermissions->execute(); - } + $this->migratePermissionsToDedicatedTable("collection_{$internalId}", $document); }, $document, $internalId); } @@ -339,6 +356,9 @@ class V12 extends Migration } } while (!is_null($nextDocument)); + /** + * Remove _read and _write columns + */ $this->pdo->prepare(" ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_collection_{$internalId}` DROP COLUMN _read, @@ -355,8 +375,10 @@ class V12 extends Migration } } while (!is_null($nextCollection)); } + /** * Migrate all Permission to new System with dedicated Table. + * * @return void * @throws \Exception */ @@ -396,29 +418,7 @@ class V12 extends Migration \Co\run(function (array $documents) { foreach ($documents as $document) { go(function (Document $document) { - $sql = "SELECT _read, _write FROM `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$document->getCollection()}` WHERE _uid = {$this->pdo->quote($document->getid())}"; - $stmt = $this->pdo->prepare($sql); - $stmt->execute(); - - $permissions = $stmt->fetch(); - - $read = json_decode($permissions['_read'] ?? null) ?? []; - $write = json_decode($permissions['_write'] ?? null) ?? []; - - $permissions = []; - foreach ($read as $permission) { - $permissions[] = "('read', '{$permission}', '{$document->getId()}')"; - } - - foreach ($write as $permission) { - $permissions[] = "('write', '{$permission}', '{$document->getId()}')"; - } - - if (!empty($permissions)) { - $queryPermissions = "INSERT IGNORE INTO `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$document->getCollection()}_perms` (_type, _permission, _document) VALUES " . implode(', ', $permissions); - $stmtPermissions = $this->pdo->prepare($queryPermissions); - $stmtPermissions->execute(); - } + $this->migratePermissionsToDedicatedTable($document->getCollection(), $document); }, $document); } }, $documents); @@ -430,6 +430,9 @@ class V12 extends Migration } } while (!is_null($nextDocument)); + /** + * Remove _read and _write columns + */ $this->pdo->prepare(" ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`{$this->projectDB->getNamespace()}_{$id}` DROP COLUMN _read, @@ -443,6 +446,12 @@ class V12 extends Migration usleep(100000); } + /** + * Fix run on each document + * + * @param \Utopia\Database\Document $document + * @return \Utopia\Database\Document + */ protected function fixDocument(Document $document) { switch ($document->getCollection()) { @@ -472,6 +481,13 @@ class V12 extends Migration break; case 'teams': + /** + * Rename sum to total + */ + if (empty($document->getAttribute('total'))) { + $document->setAttribute('total', $document->getAttribute('sum')); + } + /** * Populate search string from Migration to 0.12. */ @@ -482,6 +498,14 @@ class V12 extends Migration break; case 'files': + /** + * Update File Path + */ + $path = "/storage/uploads/app-{$this->project->getId()}"; + $new = str_replace($path, "{$path}/default", $document->getAttribute('path')); + $document + ->setAttribute('bucketId', 'default') + ->setAttribute('path', $new); /** * Populate search string from Migration to 0.12. */ @@ -492,6 +516,8 @@ class V12 extends Migration break; case 'functions': + $document->setAttribute('deployment', null); + /** * Populate search string from Migration to 0.12. */ @@ -501,16 +527,6 @@ class V12 extends Migration break; - case 'tags': - /** - * Populate search string from Migration to 0.12. - */ - if (empty($document->getAttribute('search'))) { - $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'command'], $document)); - } - - break; - case 'executions': /** * Populate search string from Migration to 0.12. From 70909bad0c8c4f574226d6d0b598fc3da66e7d76 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 1 Mar 2022 18:03:39 +0100 Subject: [PATCH 4/4] fix: add more comments --- src/Appwrite/Migration/Version/V12.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Migration/Version/V12.php b/src/Appwrite/Migration/Version/V12.php index d05d9b26ee..3d56f36355 100644 --- a/src/Appwrite/Migration/Version/V12.php +++ b/src/Appwrite/Migration/Version/V12.php @@ -72,6 +72,10 @@ class V12 extends Migration */ foreach ($this->collections as $collection) { $id = $collection['$id']; + + /** + * Skip new tables that don't exists on old schema. + */ if (in_array($id, ['buckets', 'deployments', 'builds'])) { continue; } @@ -99,6 +103,9 @@ class V12 extends Migration foreach ($this->collections as $collection) { $id = $collection['$id']; + /** + * Skip new tables that don't exists on old schema. + */ if (in_array($id, ['buckets', 'deployments', 'builds'])) { continue; } @@ -260,7 +267,8 @@ class V12 extends Migration } /** - * + * Migrates permissions to dedicated table. + * * @param \Utopia\Database\Document $document * @param string $internalId * @return void @@ -329,6 +337,9 @@ class V12 extends Migration INDEX `_index2` (`_permission`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")->execute(); + /** + * Update metadata table. + */ $this->pdo->prepare("UPDATE _{$projectId}__metadata SET _uid = 'collection_{$internalId}', @@ -387,6 +398,9 @@ class V12 extends Migration foreach ($this->collections as $collection) { $id = $collection['$id']; + /** + * Skip new tables that don't exists on old schema. + */ if (in_array($id, ['buckets', 'deployments', 'builds'])) { continue; }