diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 8d8100ee74..0e7f95abd2 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -4,38 +4,83 @@ namespace Appwrite\Migration; use Appwrite\Database\Document; use Appwrite\Database\Database; +use Utopia\CLI\Console; +use Utopia\Exception; abstract class Migration { - protected \PDO $db; + protected \PDO $db; - protected int $limit = 30; - protected int $sum = 30; - protected int $offset = 0; - protected Document $project; - protected Database $projectDB; + protected int $limit = 30; + protected int $sum = 30; + protected int $offset = 0; + protected Document $project; + protected Database $projectDB; - /** - * Migration constructor. - */ - public function __construct(\PDO $db) - { - $this->db = $db; - } + /** + * Migration constructor. + */ + public function __construct(\PDO $db) + { + $this->db = $db; + } - /** - * Set project for migration. - */ - public function setProject(Document $project, Database $projectDB): Migration - { - $this->project = $project; - $this->projectDB = $projectDB; - $this->projectDB->setNamespace('app_'.$project->getId()); - return $this; - } + /** + * Set project for migration. + */ + public function setProject(Document $project, Database $projectDB): Migration + { + $this->project = $project; + $this->projectDB = $projectDB; + $this->projectDB->setNamespace('app_' . $project->getId()); + return $this; + } - /** - * Executes migration for set project. - */ - abstract public function execute(): void; + /** + * Iterates through every document. + * + * @param function(Document): Document $callback + */ + public function forEachDocument(callable $callback) + { + while ($this->sum >= 30) { + $all = $this->projectDB->getCollection([ + 'limit' => $this->limit, + 'offset' => $this->offset, + 'orderType' => 'DESC', + ]); + + $this->sum = \count($all); + + Console::log('Migrating: ' . $this->offset . ' / ' . $this->projectDB->getSum()); + + foreach ($all as $document) { + + $document = call_user_func($callback, $document); + + if (empty($document->getId())) { + throw new Exception('Missing ID'); + } + + try { + $new = $this->projectDB->overwriteDocument($document->getArrayCopy()); + } catch (\Throwable $th) { + var_dump($document); + Console::error('Failed to update document: ' . $th->getMessage()); + continue; + } + + if ($new->getId() !== $document->getId()) { + throw new Exception('Duplication Error'); + } + } + + $this->offset = $this->offset + $this->limit; + } + } + + /** + * Executes migration for set project. + */ + abstract public function execute(): void; } diff --git a/src/Appwrite/Migration/Version/V04.php b/src/Appwrite/Migration/Version/V04.php index f1f879d898..3b13d8920b 100644 --- a/src/Appwrite/Migration/Version/V04.php +++ b/src/Appwrite/Migration/Version/V04.php @@ -7,8 +7,8 @@ use Appwrite\Migration\Migration; class V04 extends Migration { - public function execute(): void - { - Console::log('I got nothing to do.'); - } + public function execute(): void + { + Console::log('I got nothing to do.'); + } } diff --git a/src/Appwrite/Migration/Version/V05.php b/src/Appwrite/Migration/Version/V05.php index e8e0d7b4bc..c79c059dbf 100644 --- a/src/Appwrite/Migration/Version/V05.php +++ b/src/Appwrite/Migration/Version/V05.php @@ -5,63 +5,25 @@ namespace Appwrite\Migration\Version; use Appwrite\Migration\Migration; use Utopia\Config\Config; use Utopia\CLI\Console; -use Utopia\Exception; use Appwrite\Database\Database; use Appwrite\Database\Document; class V05 extends Migration { - public function execute(): void - { - $db = $this->db; - $project = $this->project; - $projectDB = $this->projectDB; - Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); + public function execute(): void + { + $db = $this->db; + $project = $this->project; + Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - // Update all documents $uid -> $id + // Update all documents $uid -> $id - $limit = 30; - $sum = 30; - $offset = 0; + $this->forEachDocument([$this, 'fixDocument']); - while ($sum >= 30) { - $all = $projectDB->getCollection([ - 'limit' => $limit, - 'offset' => $offset, - 'orderType' => 'DESC', - ]); - - $sum = \count($all); - - Console::log('Migrating: ' . $offset . ' / ' . $projectDB->getSum()); - - foreach ($all as $document) { - $document = $this->fixDocument($document); - - if (empty($document->getId())) { - throw new Exception('Missing ID'); - } + $schema = $_SERVER['_APP_DB_SCHEMA'] ?? ''; try { - $new = $projectDB->overwriteDocument($document->getArrayCopy()); - } catch (\Throwable $th) { - var_dump($document); - Console::error('Failed to update document: ' . $th->getMessage()); - continue; - } - - if ($new->getId() !== $document->getId()) { - throw new Exception('Duplication Error'); - } - } - - $offset = $offset + $limit; - } - - $schema = $_SERVER['_APP_DB_SCHEMA'] ?? ''; - - try { - $statement = $db->prepare(" + $statement = $db->prepare(" CREATE TABLE IF NOT EXISTS `template.database.unique` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, @@ -76,89 +38,89 @@ class V05 extends Migration ALTER TABLE `{$schema}`.`app_{$project->getId()}.audit.audit` ADD INDEX IF NOT EXISTS `index_1` (`userId` ASC); "); - $statement->closeCursor(); + $statement->closeCursor(); - $statement->execute(); - } catch (\Exception $e) { - Console::error('Failed to alter table for project: ' . $project->getId() . ' with message: ' . $e->getMessage() . '/'); - } - } - - private function fixDocument(Document $document) - { - $providers = Config::getParam('providers'); - - switch ($document->getAttribute('$collection')) { - case Database::SYSTEM_COLLECTION_PROJECTS: - foreach ($providers as $key => $provider) { - if (!empty($document->getAttribute('usersOauth' . \ucfirst($key) . 'Appid'))) { - $document - ->setAttribute('usersOauth2' . \ucfirst($key) . 'Appid', $document->getAttribute('usersOauth' . \ucfirst($key) . 'Appid', '')) - ->removeAttribute('usersOauth' . \ucfirst($key) . 'Appid'); - } - - if (!empty($document->getAttribute('usersOauth' . \ucfirst($key) . 'Secret'))) { - $document - ->setAttribute('usersOauth2' . \ucfirst($key) . 'Secret', $document->getAttribute('usersOauth' . \ucfirst($key) . 'Secret', '')) - ->removeAttribute('usersOauth' . \ucfirst($key) . 'Secret'); - } + $statement->execute(); + } catch (\Exception $e) { + Console::error('Failed to alter table for project: ' . $project->getId() . ' with message: ' . $e->getMessage() . '/'); } - break; - - case Database::SYSTEM_COLLECTION_PROJECTS: - case Database::SYSTEM_COLLECTION_TASKS: - $document->setAttribute('security', ($document->getAttribute('security')) ? true : false); - break; - - case Database::SYSTEM_COLLECTION_USERS: - foreach ($providers as $key => $provider) { - if (!empty($document->getAttribute('oauth' . \ucfirst($key)))) { - $document - ->setAttribute('oauth2' . \ucfirst($key), $document->getAttribute('oauth' . \ucfirst($key), '')) - ->removeAttribute('oauth' . \ucfirst($key)); - } - - if (!empty($document->getAttribute('oauth' . \ucfirst($key) . 'AccessToken'))) { - $document - ->setAttribute('oauth2' . \ucfirst($key) . 'AccessToken', $document->getAttribute('oauth' . \ucfirst($key) . 'AccessToken', '')) - ->removeAttribute('oauth' . \ucfirst($key) . 'AccessToken'); - } - } - - if ($document->getAttribute('confirm', null) !== null) { - $document - ->setAttribute('emailVerification', $document->getAttribute('confirm', $document->getAttribute('emailVerification', false))) - ->removeAttribute('confirm'); - } - break; - - case Database::SYSTEM_COLLECTION_PLATFORMS: - if ($document->getAttribute('url', null) !== null) { - $document - ->setAttribute('hostname', \parse_url($document->getAttribute('url', $document->getAttribute('hostname', '')), PHP_URL_HOST)) - ->removeAttribute('url'); - } - break; } - $document - ->setAttribute('$id', $document->getAttribute('$uid', $document->getAttribute('$id'))) - ->removeAttribute('$uid'); + protected function fixDocument(Document $document) + { + $providers = Config::getParam('providers'); - foreach ($document as &$attr) { // Handle child documents - if ($attr instanceof Document) { - $attr = $this->fixDocument($attr); - } + switch ($document->getAttribute('$collection')) { + case Database::SYSTEM_COLLECTION_PROJECTS: + foreach ($providers as $key => $provider) { + if (!empty($document->getAttribute('usersOauth' . \ucfirst($key) . 'Appid'))) { + $document + ->setAttribute('usersOauth2' . \ucfirst($key) . 'Appid', $document->getAttribute('usersOauth' . \ucfirst($key) . 'Appid', '')) + ->removeAttribute('usersOauth' . \ucfirst($key) . 'Appid'); + } - if (\is_array($attr)) { - foreach ($attr as &$child) { - if ($child instanceof Document) { - $child = $this->fixDocument($child); - } + if (!empty($document->getAttribute('usersOauth' . \ucfirst($key) . 'Secret'))) { + $document + ->setAttribute('usersOauth2' . \ucfirst($key) . 'Secret', $document->getAttribute('usersOauth' . \ucfirst($key) . 'Secret', '')) + ->removeAttribute('usersOauth' . \ucfirst($key) . 'Secret'); + } + } + break; + + case Database::SYSTEM_COLLECTION_PROJECTS: + case Database::SYSTEM_COLLECTION_TASKS: + $document->setAttribute('security', ($document->getAttribute('security')) ? true : false); + break; + + case Database::SYSTEM_COLLECTION_USERS: + foreach ($providers as $key => $provider) { + if (!empty($document->getAttribute('oauth' . \ucfirst($key)))) { + $document + ->setAttribute('oauth2' . \ucfirst($key), $document->getAttribute('oauth' . \ucfirst($key), '')) + ->removeAttribute('oauth' . \ucfirst($key)); + } + + if (!empty($document->getAttribute('oauth' . \ucfirst($key) . 'AccessToken'))) { + $document + ->setAttribute('oauth2' . \ucfirst($key) . 'AccessToken', $document->getAttribute('oauth' . \ucfirst($key) . 'AccessToken', '')) + ->removeAttribute('oauth' . \ucfirst($key) . 'AccessToken'); + } + } + + if ($document->getAttribute('confirm', null) !== null) { + $document + ->setAttribute('emailVerification', $document->getAttribute('confirm', $document->getAttribute('emailVerification', false))) + ->removeAttribute('confirm'); + } + break; + + case Database::SYSTEM_COLLECTION_PLATFORMS: + if ($document->getAttribute('url', null) !== null) { + $document + ->setAttribute('hostname', \parse_url($document->getAttribute('url', $document->getAttribute('hostname', '')), PHP_URL_HOST)) + ->removeAttribute('url'); + } + break; } - } - } - return $document; - } + $document + ->setAttribute('$id', $document->getAttribute('$uid', $document->getAttribute('$id'))) + ->removeAttribute('$uid'); + + foreach ($document as &$attr) { // Handle child documents + if ($attr instanceof Document) { + $attr = $this->fixDocument($attr); + } + + if (\is_array($attr)) { + foreach ($attr as &$child) { + if ($child instanceof Document) { + $child = $this->fixDocument($child); + } + } + } + } + + return $document; + } } diff --git a/src/Appwrite/Migration/Version/V06.php b/src/Appwrite/Migration/Version/V06.php index 33ddafe814..d28d3b652b 100644 --- a/src/Appwrite/Migration/Version/V06.php +++ b/src/Appwrite/Migration/Version/V06.php @@ -3,15 +3,31 @@ namespace Appwrite\Migration\Version; use Utopia\CLI\Console; +use Appwrite\Database\Database; +use Appwrite\Database\Document; use Appwrite\Migration\Migration; class V06 extends Migration { - public function execute(): void - { - Console::log('I got nothing to do. Yet.'); + public function execute(): void + { + Console::log('I got nothing to do. Yet.'); - //TODO: migrate new `filter` property + //TODO: migrate new `filter` property + $this->forEachDocument([$this, 'fixDocument']); + } - } + protected function fixDocument(Document $document) + { + switch ($document->getAttribute('$collection')) { + case Database::SYSTEM_COLLECTION_USERS: + if ($document->getAttribute('password-update', null)) { + $document + ->setAttribute('passwordUpdate', $document->getAttribute('password-update', $document->getAttribute('passwordUpdate', ''))) + ->removeAttribute('password-update'); + } + break; + } + return $document; + } }