Skip to content

Commit

Permalink
daos/mysql: Add colors to tags without one
Browse files Browse the repository at this point in the history
When user specified a source tag with a same name but a different letter casing as another existing tag,
the MySQL backend would think the tag already exists and not create a color for it.
This would break, for example, OPML export, which expects every tag to have a color associated with it.

The bug has been fixed in the previous commit but there can still be such erroneously created tags from before.
Let’s go through all tags mentioned in the `source` table and ensure the `tags` table is up to date.
If a tag with a different casing and a color exists, let’s consider it the canonical casing and update the source tag to that.

Fixes: #1438
  • Loading branch information
jtojnar committed Jun 15, 2023
1 parent c1ecc5e commit f2fcaa8
Showing 1 changed file with 72 additions and 0 deletions.
72 changes: 72 additions & 0 deletions src/daos/mysql/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use daos\CommonSqlDatabase;
use helpers\DatabaseConnection;
use helpers\StringKeyedArray;
use Monolog\Logger;

/**
Expand Down Expand Up @@ -292,6 +293,77 @@ public function __construct(DatabaseConnection $connection, Logger $logger) {
$this->exec('INSERT INTO ' . $this->connection->getTableNamePrefix() . 'version (version) VALUES (14)');
$this->commit();
}
if ($version < 15) {
$this->logger->debug('Upgrading database schema to version 15 by ensuring all tags have colors');

$this->beginTransaction();

/** @var StringKeyedArray<bool> */
$coloredTags = new StringKeyedArray();
/** @var StringKeyedArray<string> */
$coloredTagsNormalised = new StringKeyedArray();
/** @var StringKeyedArray<string> */
$tagsWithoutColor = new StringKeyedArray();

$tags = $this->exec('SELECT tag, LOWER(tag) as normal FROM ' . $this->connection->getTableNamePrefix() . 'tags');
foreach ($tags as $tag) {
$coloredTags[$tag['tag']] = true;
$coloredTagsNormalised[$tag['normal']] = $tag['tag'];
}

$sources = $this->exec('SELECT id, tags, LOWER(tags) as normal FROM ' . $this->connection->getTableNamePrefix() . 'sources');
foreach ($sources as $source) {
if ($source['tags'] === '') {
continue;
}

$shouldUpdateSourceTags = false;

$sourceTags = explode(',', $source['tags']);
$sourceTagPairs = array_map(
null,
$sourceTags,
explode(',', $source['normal'])
);
foreach ($sourceTagPairs as $key => [$tag, $normal]) {
// If the tag does not have associated color:
if (!isset($coloredTags[$tag])) {
// Try to match it to a differently-cased tag.
if (isset($coloredTagsNormalised[$normal])) {
$sourceTags[$key] = $coloredTagsNormalised[$normal];
$shouldUpdateSourceTags = true;
} else {
// Otherwise mark it for assigning a color.
$tagsWithoutColor[$normal] = $tag;
}
}
}

if ($shouldUpdateSourceTags) {
$this->exec(
'UPDATE ' . $this->connection->getTableNamePrefix() . 'sources SET tags = :tags WHERE id = :id',
[
'id' => $source['id'],
'tags' => implode(',', $sourceTags),
]
);
}
}

// Add color to all tags without one.
foreach ($tagsWithoutColor as $tag) {
$this->exec(
'INSERT INTO ' . $this->connection->getTableNamePrefix() . 'tags(tag, color) VALUES (:tag, :color)',
[
'tag' => $tag,
'color' => '#df1818',
]
);
}

$this->exec('INSERT INTO ' . $this->connection->getTableNamePrefix() . 'version (version) VALUES (15)');
$this->commit();
}
}

/**
Expand Down

0 comments on commit f2fcaa8

Please sign in to comment.