Files
nextcloud-forum/lib/Migration/Version7Date20251124120000.php
2025-12-31 17:52:11 +02:00

189 lines
6.3 KiB
PHP

<?php
declare(strict_types=1);
// SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
// SPDX-License-Identifier: AGPL-3.0-or-later
namespace OCA\Forum\Migration;
use Closure;
use OCA\Forum\Db\Role;
use OCP\DB\ISchemaWrapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
class Version7Date20251124120000 extends SimpleMigrationStep {
public function __construct(
private IDBConnection $db,
private \OCP\IConfig $systemConfig,
private \OCP\AppFramework\Services\IAppConfig $appConfig,
) {
}
/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
*/
public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
}
/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
// Add role columns to forum_roles table
if ($schema->hasTable('forum_roles')) {
$table = $schema->getTable('forum_roles');
if (!$table->hasColumn('is_system_role')) {
$table->addColumn('is_system_role', 'boolean', [
'notnull' => false,
'default' => null,
]);
}
if (!$table->hasColumn('role_type')) {
$table->addColumn('role_type', 'string', [
'notnull' => false,
'default' => 'custom',
'length' => 20,
]);
}
// Add index on role_type column to optimize findByRoleType() lookups
// This is frequently called for guest user access checks
if (!$table->hasIndex('forum_roles_role_type_idx')) {
$table->addIndex(['role_type'], 'forum_roles_role_type_idx');
}
}
return $schema;
}
/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
*/
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
$this->migrateConfigValues($output);
$this->updateExistingRoleFlags($output);
}
/**
* Migrate config values from system config to app config
* Previous versions used IConfig (system config), now using IAppConfig (app config)
*/
private function migrateConfigValues(IOutput $output): void {
$configKeys = ['title', 'subtitle'];
$migrated = 0;
foreach ($configKeys as $key) {
// Check if value exists in system config
$systemValue = $this->systemConfig->getSystemValue($key, null);
// Only migrate if:
// 1. System config has a value
// 2. App config doesn't have a value yet (to avoid overwriting)
if ($systemValue !== null) {
try {
$appValue = $this->appConfig->getAppValueString($key, '', true);
// If app config is empty or default, migrate from system config
if ($appValue === '') {
$this->appConfig->setAppValueString($key, $systemValue, true);
// Delete the old system config value after successful migration
$this->systemConfig->deleteSystemValue($key);
$migrated++;
$output->info("Migrated forum '$key' from system config to app config and removed old value");
}
} catch (\Exception $e) {
$output->warning("Failed to migrate config '$key': " . $e->getMessage());
}
}
}
if ($migrated === 0) {
$output->info('No forum config values needed migration');
}
}
/**
* Update existing system roles with appropriate flags
* This runs BEFORE seeding to ensure existing roles have role_type set
*/
private function updateExistingRoleFlags(IOutput $output): void {
// First, set defaults for all existing roles that don't have role_type set
$qb = $this->db->getQueryBuilder();
$qb->update('forum_roles')
->set('is_system_role', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
->set('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_CUSTOM, IQueryBuilder::PARAM_STR))
->where($qb->expr()->isNull('role_type'));
$updated = $qb->executeStatement();
if ($updated > 0) {
$output->info("Set defaults for $updated existing roles");
}
// Now update the three original system roles (Admin, Moderator, User) with their specific values
// Only updates roles that exist and have role_type='custom' (just set above)
// Set role_type='admin' for role 1 (Admin) if it exists
$qb = $this->db->getQueryBuilder();
$qb->update('forum_roles')
->set('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_ADMIN, IQueryBuilder::PARAM_STR))
->set('is_system_role', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
->where(
$qb->expr()->eq('id', $qb->createNamedParameter(1, IQueryBuilder::PARAM_INT))
)
->andWhere(
$qb->expr()->eq('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_CUSTOM, IQueryBuilder::PARAM_STR))
);
$updated = $qb->executeStatement();
if ($updated > 0) {
$output->info("Set role_type='" . Role::ROLE_TYPE_ADMIN . "' for role 1 (Admin)");
}
// Set role_type='moderator' for role 2 (Moderator) if it exists
$qb = $this->db->getQueryBuilder();
$qb->update('forum_roles')
->set('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_MODERATOR, IQueryBuilder::PARAM_STR))
->set('is_system_role', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
->where(
$qb->expr()->eq('id', $qb->createNamedParameter(2, IQueryBuilder::PARAM_INT))
)
->andWhere(
$qb->expr()->eq('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_CUSTOM, IQueryBuilder::PARAM_STR))
);
$updated = $qb->executeStatement();
if ($updated > 0) {
$output->info("Set role_type='" . Role::ROLE_TYPE_MODERATOR . "' for role 2 (Moderator)");
}
// Set role_type='default' for role 3 (User) if it exists
$qb = $this->db->getQueryBuilder();
$qb->update('forum_roles')
->set('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_DEFAULT, IQueryBuilder::PARAM_STR))
->set('is_system_role', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
->where(
$qb->expr()->eq('id', $qb->createNamedParameter(3, IQueryBuilder::PARAM_INT))
)
->andWhere(
$qb->expr()->eq('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_CUSTOM, IQueryBuilder::PARAM_STR))
);
$updated = $qb->executeStatement();
if ($updated > 0) {
$output->info("Set role_type='" . Role::ROLE_TYPE_DEFAULT . "' for role 3 (User)");
}
}
}