Skip to content

Commit

Permalink
Merge pull request #10261 from jonasraoni/bugfix-main-10249-fix-data-…
Browse files Browse the repository at this point in the history
…loss-on-settings

Bugfix main 10249 fix data loss on settings
  • Loading branch information
jonasraoni authored Jul 31, 2024
2 parents b906e39 + dda052b commit f04f202
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 12 deletions.
42 changes: 30 additions & 12 deletions classes/migration/upgrade/PKPv3_3_0UpgradeMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ function (Builder $q) use ($row, $lastInsertedFileId) {
DB::table('event_log_settings as els')
->join(
'event_log_settings as file_setting',
fn (JoinClause $join) =>
fn(JoinClause $join) =>
$join->on('file_setting.log_id', '=', 'els.log_id')
->where('file_setting.setting_name', '=', 'fileId')
->where('file_setting.setting_value', '=', (string) $row->file_id)
Expand Down Expand Up @@ -823,7 +823,7 @@ private function _settingsAsJSON()
error_log("Failed to migrate the settings entity \"{$tableName}\"\n" . $e);
continue;
}
$settings->each(fn ($row) => $this->_toJSON($row, $tableName, ['setting_name', 'locale'], 'setting_value'));
$settings->each(fn($row) => $this->_toJSON($row, $tableName, ['setting_name', 'locale'], 'setting_value'));
}
}

Expand Down Expand Up @@ -876,19 +876,37 @@ private function _toJSON($row, $tableName, $searchBy, $valueToConvert)
}
$newValue = json_encode($oldValue, JSON_UNESCAPED_UNICODE); // don't convert utf-8 characters to unicode escaped code

$id = array_key_first((array)$row); // get first/primary key column
// Ensure ID fields are included on the filter to avoid updating similar rows
$tableDetails = DB::connection()->getDoctrineSchemaManager()->listTableDetails($tableName);
$primaryKeys = [];
try {
$primaryKeys = $tableDetails->getPrimaryKeyColumns();
} catch (Exception $e) {
foreach ($tableDetails->getIndexes() as $index) {
if ($index->isPrimary() || $index->isUnique()) {
$primaryKeys = $index->getColumns();
break;
}
}
}

// Remove empty filters
$searchBy = array_filter($searchBy, function ($item) use ($row) {
if (empty($row->{$item})) {
return false;
if (!count($primaryKeys)) {
foreach (array_keys(get_object_vars($row)) as $column) {
if (substr($column, -3, '_id')) {
$primaryKeys[] = $column;
}
}
return true;
});
}

$searchBy = array_merge($searchBy, $primaryKeys);

$queryBuilder = DB::table($tableName)->where($id, $row->{$id});
foreach ($searchBy as $key => $column) {
$queryBuilder = $queryBuilder->where($column, $row->{$column});
$queryBuilder = DB::table($tableName);
foreach (array_unique($searchBy) as $column) {
if ($row->{$column} !== null) {
$queryBuilder->where($column, $row->{$column});
} else {
$queryBuilder->whereNull($column);
}
}
$queryBuilder->update([$valueToConvert => $newValue]);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

/**
* @file classes/migration/upgrade/v3_4_0/I10249_FixProfileImageDataLoss.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class I10249_FixProfileImageDataLoss
*
* @brief Fix data loss at the user profile image
*
* @see https://github.com/pkp/pkp-lib/issues/10249
*/

namespace PKP\migration\upgrade\v3_4_0;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use PKP\config\Config;
use PKP\install\DowngradeNotSupportedException;

class I10249_FixProfileImageDataLoss extends \PKP\migration\Migration
{
/**
* Runs the migration
*/
public function up(): void
{
$orderByModifiedDate = fn(string $a, string $b) => filemtime($a) - filemtime($b);
$publicFilesPath = Config::getVar('files', 'public_files_dir') . '/site';
DB::table('user_settings')
->where('setting_name', '=', 'profileImage')
->whereRaw("COALESCE(setting_value, '') <> ''")
->whereRaw("setting_value NOT LIKE CONCAT('%profileImage-', user_id, '.%')")
->select('user_id')
->chunkById(1000, function (Collection $rows) use ($publicFilesPath, $orderByModifiedDate) {
foreach ($rows as $row) {
$globPattern = "{$publicFilesPath}/profileImage-{$row->user_id}.*";
$candidates = glob($globPattern, GLOB_NOSORT);
if (empty($candidates)) {
$this->_installer->log("Failed to locate a profile image for the user ID {$row->user_id} at {$globPattern}, cleaning up the value");
DB::table('user_settings')
->where('user_id', $row->user_id)
->where('setting_name', 'profileImage')
->update(['setting_value' => null]);
continue;
}

if (count($candidates) > 1) {
usort($candidates, $orderByModifiedDate);
}

$filePath = array_pop($candidates);
$fileName = basename($filePath);
[$width, $height] = getimagesize($filePath) ?: [0, 0];
DB::table('user_settings')
->where('user_id', $row->user_id)
->where('setting_name', 'profileImage')
->update([
'setting_value' => json_encode([
'name' => $fileName,
'uploadName' => $fileName,
'width' => $width,
'height' => $height,
'dateUploaded' => date('Y-m-d H:i:s', filemtime($filePath))
]),
'setting_type' => 'object'
]);
}
}, 'user_id');
}

/**
* Reverses the migration
*/
public function down(): void
{
throw new DowngradeNotSupportedException();
}
}

0 comments on commit f04f202

Please sign in to comment.