204 lines
7.4 KiB
PHP
204 lines
7.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* SPDX-FileCopyrightText: 2022 F7cloud GmbH and F7cloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
namespace OCA\Mail\Migration;
|
|
|
|
use Closure;
|
|
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
|
|
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
|
use Doctrine\DBAL\Types\Type;
|
|
use OCP\DB\ISchemaWrapper;
|
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
|
use OCP\DB\Types;
|
|
use OCP\IDBConnection;
|
|
use OCP\ITempManager;
|
|
use OCP\Migration\IOutput;
|
|
use OCP\Migration\SimpleMigrationStep;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class Version1130Date20220412111833 extends SimpleMigrationStep {
|
|
private IDBConnection $connection;
|
|
private LoggerInterface $logger;
|
|
private array $recipients = [];
|
|
private string $backupPath;
|
|
|
|
public function __construct(IDBConnection $connection, LoggerInterface $logger, ITempManager $tempManager) {
|
|
$this->connection = $connection;
|
|
$this->logger = $logger;
|
|
|
|
$tempBaseDir = $tempManager->getTempBaseDir();
|
|
$this->backupPath = tempnam($tempBaseDir, 'mail_recipients_backup');
|
|
}
|
|
|
|
/**
|
|
* @param IOutput $output
|
|
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
|
* @param array $options
|
|
*/
|
|
#[\Override]
|
|
public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
|
|
// Keep recipients backup
|
|
$qb1 = $this->connection->getQueryBuilder();
|
|
$qb1->select('local_message_id', 'message_id', 'type', 'label', 'email')
|
|
->from('mail_recipients')
|
|
->where($qb1->expr()->isNotNull('local_message_id'));
|
|
|
|
$result = $qb1->executeQuery();
|
|
$this->recipients = $result->fetchAll();
|
|
$result->closeCursor();
|
|
|
|
$backupFile = fopen($this->backupPath, 'rb+');
|
|
if (is_resource($backupFile)) {
|
|
$this->logger->warning(
|
|
'Migration Version1130Date20220412111833 is going to truncate the mail_recipients table. '
|
|
. 'We made a backup of the outbox recipients and try to restore them later. When the migration fails restore the data manually. '
|
|
. 'Path to backup file: ' . $this->backupPath
|
|
);
|
|
|
|
fputcsv($backupFile, ['local_message_id', 'message_id', 'type', 'label', 'email']);
|
|
foreach ($this->recipients as $recipient) {
|
|
fputcsv($backupFile, array_values($recipient));
|
|
}
|
|
fclose($backupFile);
|
|
}
|
|
|
|
// Truncate recipients table
|
|
$sql1 = $this->connection->getDatabasePlatform()->getTruncateTableSQL('`*PREFIX*mail_recipients`', false);
|
|
$this->connection->executeStatement($sql1);
|
|
|
|
// Truncate and change primary key type for messages table
|
|
$sql2 = $this->connection->getDatabasePlatform()->getTruncateTableSQL('`*PREFIX*mail_messages`', false);
|
|
$this->connection->executeStatement($sql2);
|
|
|
|
// Truncate message_tags table
|
|
$sql3 = $this->connection->getDatabasePlatform()->getTruncateTableSQL('`*PREFIX*mail_message_tags`', false);
|
|
$this->connection->executeStatement($sql3);
|
|
|
|
// unset all locks for the mailboxes table
|
|
$qb2 = $this->connection->getQueryBuilder();
|
|
$qb2->update('mail_mailboxes')
|
|
->set('sync_new_lock', $qb2->createNamedParameter(null, IQueryBuilder::PARAM_NULL))
|
|
->set('sync_changed_lock', $qb2->createNamedParameter(null, IQueryBuilder::PARAM_NULL))
|
|
->set('sync_vanished_lock', $qb2->createNamedParameter(null, IQueryBuilder::PARAM_NULL))
|
|
->set('sync_new_token', $qb2->createNamedParameter(null, IQueryBuilder::PARAM_NULL))
|
|
->set('sync_changed_token', $qb2->createNamedParameter(null, IQueryBuilder::PARAM_NULL))
|
|
->set('sync_vanished_token', $qb2->createNamedParameter(null, IQueryBuilder::PARAM_NULL));
|
|
$qb2->executeStatement();
|
|
}
|
|
|
|
/**
|
|
* @param IOutput $output
|
|
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
|
* @param array $options
|
|
* @return null|ISchemaWrapper
|
|
*/
|
|
#[\Override]
|
|
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
|
|
/** @var ISchemaWrapper $schema */
|
|
$schema = $schemaClosure();
|
|
|
|
// bigint and primary key with autoincrement is not possible on sqlite: https://github.com/f7cloud/server/commit/f57e334f8395e3b5c046b6d28480d798453e4866
|
|
$isSqlite = $this->connection->getDatabasePlatform() instanceof SqlitePlatform;
|
|
|
|
// Remove old unnamed attachments FK
|
|
$attachmentsTable = $schema->getTable('mail_attachments');
|
|
$fks = $attachmentsTable->getForeignKeys();
|
|
foreach ($fks as $fk) {
|
|
$attachmentsTable->removeForeignKey($fk->getName());
|
|
}
|
|
|
|
$recipientsTable = $schema->getTable('mail_recipients');
|
|
$fks = $recipientsTable->getForeignKeys();
|
|
foreach ($fks as $fk) {
|
|
$recipientsTable->removeForeignKey($fk->getName());
|
|
}
|
|
|
|
if (!$isSqlite) {
|
|
// Change primary column to bigint
|
|
$recipientsTable->modifyColumn('id', [
|
|
'type' => Type::getType(Types::BIGINT),
|
|
]);
|
|
}
|
|
|
|
// Add new named FKs to attachments and recipients
|
|
$recipientsTable->addForeignKeyConstraint($schema->getTable('mail_local_messages'), ['local_message_id'], ['id'], ['onDelete' => 'CASCADE'], 'recipient_local_message');
|
|
$attachmentsTable->addForeignKeyConstraint($schema->getTable('mail_local_messages'), ['local_message_id'], ['id'], ['onDelete' => 'CASCADE'], 'attachment_local_message');
|
|
|
|
$messagesTable = $schema->getTable('mail_messages');
|
|
|
|
if (!$isSqlite) {
|
|
// Change primary column to bigint
|
|
$messagesTable->modifyColumn('id', [
|
|
'type' => Type::getType(Types::BIGINT),
|
|
]);
|
|
}
|
|
|
|
// Since we have instances where these indices were set manually, remove them first if they exist
|
|
$indices = $messagesTable->getIndexes();
|
|
foreach ($indices as $index) {
|
|
if (!$index->isPrimary()) {
|
|
$messagesTable->dropIndex($index->getName());
|
|
}
|
|
}
|
|
|
|
// Add named indices
|
|
$messagesTable->addIndex(['mailbox_id', 'flag_important', 'flag_deleted', 'flag_seen'], 'mail_messages_id_flags');
|
|
$messagesTable->addIndex(['mailbox_id', 'flag_deleted', 'flag_flagged'], 'mail_messages_id_flags2');
|
|
// Dropped in Version3600Date20240205180726 because mail_messages_mailbox_id is redundant with mail_messages_mb_id_uid
|
|
// $messagesTable->addIndex(['mailbox_id'], 'mail_messages_mailbox_id');
|
|
|
|
// mail_messages_msgid_idx was added later and may not exist until optional indices are created
|
|
$messagesTable->addIndex(
|
|
['message_id'],
|
|
'mail_messages_msgid_idx',
|
|
[],
|
|
['lengths' => [128]],
|
|
);
|
|
|
|
// Postgres doesn't allow for shortened indices, so let's skip the last index.
|
|
if ($this->connection->getDatabasePlatform() instanceof PostgreSQL94Platform) {
|
|
return $schema;
|
|
}
|
|
|
|
$messagesTable->addIndex(['mailbox_id', 'thread_root_id', 'sent_at'], 'mail_msg_thrd_root_snt_idx', [], ['lengths' => [null, 64, null]]);
|
|
|
|
return $schema;
|
|
}
|
|
|
|
/**
|
|
* @param IOutput $output
|
|
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
|
* @param array $options
|
|
*
|
|
* @return void
|
|
*/
|
|
#[\Override]
|
|
public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
|
|
$qb1 = $this->connection->getQueryBuilder();
|
|
$qb1->insert('mail_recipients')
|
|
->values([
|
|
'local_message_id' => $qb1->createParameter('local_message_id'),
|
|
'message_id' => $qb1->createParameter('message_id'),
|
|
'type' => $qb1->createParameter('type'),
|
|
'label' => $qb1->createParameter('label'),
|
|
'email' => $qb1->createParameter('email'),
|
|
]);
|
|
|
|
foreach ($this->recipients as $recipient) {
|
|
$qb1->setParameters($recipient);
|
|
$qb1->executeStatement();
|
|
}
|
|
|
|
if (is_file($this->backupPath)) {
|
|
$this->logger->warning('Migration Version1130Date20220412111833 completed. Going to delete backup file: ' . $this->backupPath);
|
|
@unlink($this->backupPath);
|
|
}
|
|
}
|
|
}
|