Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework the tag system #654

Merged
merged 65 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
6939cba
Rework the tag system
BentiGorlich Apr 1, 2024
e076ca8
Fix error with creating Image and Link, linter
BentiGorlich Apr 1, 2024
0f81514
Fix unit test error
BentiGorlich Apr 1, 2024
2fe70e4
Fix linter
BentiGorlich Apr 1, 2024
f4dd75a
Little sql tuning
BentiGorlich Apr 1, 2024
66ab80a
Little sql tuning 2
BentiGorlich Apr 1, 2024
dfe7aa8
Make TagExtractor handle null values
BentiGorlich Apr 2, 2024
2dabcb9
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 3, 2024
4a0d2c6
Bring back the tag transformer
BentiGorlich Apr 3, 2024
e8fb274
Fix infinite scroll on tag overview
BentiGorlich Apr 3, 2024
6829fa1
Merge branch 'main' into rework/tag-system
Apr 3, 2024
c70f0f5
Merge branch 'main' into rework/tag-system
Apr 4, 2024
e188929
Merge branch 'main' into rework/tag-system
Apr 4, 2024
00110ea
Merge branch 'main' into rework/tag-system
Apr 5, 2024
9e12a55
Merge branch 'main' into rework/tag-system
Apr 6, 2024
04d0535
Merge branch 'main' into rework/tag-system
Apr 6, 2024
27a3751
Merge branch 'main' into rework/tag-system
Apr 6, 2024
756cfad
Merge branch 'main' into rework/tag-system
Apr 6, 2024
da8efa6
Merge branch 'main' into rework/tag-system
Apr 6, 2024
8a430a7
Merge branch 'main' into rework/tag-system
Apr 6, 2024
4fe3b2b
Merge branch 'main' into rework/tag-system
Apr 7, 2024
ada8a49
Fix a lot of API calls
BentiGorlich Apr 7, 2024
c789b74
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 7, 2024
a38b8fe
Merge branch 'main' into rework/tag-system
Apr 7, 2024
f2d9776
Merge branch 'main' into rework/tag-system
Apr 7, 2024
9cfc994
Better account for non-existent hashtags
BentiGorlich Apr 8, 2024
1747c61
Fix linter
BentiGorlich Apr 8, 2024
4cfc414
Account for non-existent hashtags while banning
BentiGorlich Apr 8, 2024
df5ab51
Merge branch 'main' into rework/tag-system
Apr 8, 2024
d774581
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 8, 2024
15756eb
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 8, 2024
031a2fb
Fix ap objects not showing up when searching for ap id
BentiGorlich Apr 8, 2024
6910fd3
Merge branch 'main' into rework/tag-system
Apr 8, 2024
11f6626
Merge branch 'main' into rework/tag-system
Apr 8, 2024
32f3b26
Merge branch 'main' into rework/tag-system
Apr 9, 2024
5303088
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 9, 2024
c3aac2f
Merge branch 'main' into rework/tag-system
Apr 10, 2024
0914080
Merge branch 'main' into rework/tag-system
Apr 10, 2024
261cdb2
Merge branch 'main' into rework/tag-system
Apr 11, 2024
411e887
Merge branch 'main' into rework/tag-system
Apr 12, 2024
d0253d6
Merge branch 'main' into rework/tag-system
Apr 13, 2024
5dbf9e7
Merge branch 'main' into rework/tag-system
Apr 13, 2024
3afb8a6
Merge branch 'main' into rework/tag-system
Apr 14, 2024
d6414fb
Fix the activity pub factories not getting tags
BentiGorlich Apr 18, 2024
412b77f
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 18, 2024
d0cf088
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 19, 2024
3664f51
Merge branch 'main' into rework/tag-system
Apr 21, 2024
48d8e1b
Merge branch 'main' into rework/tag-system
BentiGorlich Apr 24, 2024
02bb7de
Merge branch 'main' into rework/tag-system
Apr 25, 2024
b9968ff
Merge branch 'main' into rework/tag-system
Apr 27, 2024
f05de75
Merge branch 'main' into rework/tag-system
Apr 27, 2024
8e966cf
Merge branch 'main' into rework/tag-system
Apr 28, 2024
86176e5
Merge branch 'main' into rework/tag-system
melroy89 Apr 30, 2024
665e91c
Merge branch 'main' into rework/tag-system
May 1, 2024
6f7948a
Bring back the tags input when creating and editing entries
BentiGorlich May 2, 2024
e97f932
Merge branch 'main' into rework/tag-system
May 2, 2024
5d1d829
Merge branch 'main' into rework/tag-system
BentiGorlich May 3, 2024
b8c2e77
Merge branch 'main' into rework/tag-system
BentiGorlich May 3, 2024
60bc2dc
Merge branch 'main' into rework/tag-system
May 5, 2024
7063a5b
Merge branch 'main' into rework/tag-system
May 5, 2024
89d1f31
Merge branch 'main' into rework/tag-system
May 11, 2024
8236e8e
Merge branch 'main' into rework/tag-system
BentiGorlich May 11, 2024
f942214
Merge branch 'main' into rework/tag-system
BentiGorlich May 13, 2024
0b07eb7
Add specific message for banned hashtags, fix mapping error
BentiGorlich May 13, 2024
e4869c4
Fix lint
melroy89 May 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@
@import 'themes/default';
@import 'themes/solarized';
@import 'themes/tokyo-night';
@import 'components/tag';
21 changes: 21 additions & 0 deletions assets/styles/components/_tag.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.section.tag {
header {
text-align: center;

h4 {
font-size: 1.2rem;
margin-bottom: 0;
margin-top: .5rem;
}
}

.tag__actions {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
margin-top: 1rem;
margin-bottom: 2.5rem;
gap: .25rem;
}
}
10 changes: 10 additions & 0 deletions config/kbin_routes/tag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,13 @@ tag_people:
path: tag/{name}/people
methods: [GET]
requirements: { sortBy: "%front_sort_options%" }

tag_ban:
path: /tag/{name}/ban
methods: [POST]
controller: App\Controller\Tag\TagBanController::ban

tag_unban:
path: /tag/{name}/unban
methods: [POST]
controller: App\Controller\Tag\TagBanController::unban
3 changes: 3 additions & 0 deletions config/packages/doctrine.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
types:
citext: App\DoctrineExtensions\DBAL\Types\Citext
mapping_types:
user_type: string
citext: citext

# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
Expand Down
217 changes: 217 additions & 0 deletions migrations/Version20240330101300.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20240330101300 extends AbstractMigration
{
public function getDescription(): string
{
return 'This migration moves hashtags from the entry, entry_comment, post and post_comment table to its own table, while keeping the hashtag links alive';
}

public function up(Schema $schema): void
{
$this->addSql('CREATE EXTENSION IF NOT EXISTS citext');
$this->addSql('CREATE SEQUENCE hashtag_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE hashtag_link_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE hashtag (id INT NOT NULL, tag citext NOT NULL, banned BOOLEAN DEFAULT false NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_5AB52A61389B783 ON hashtag (tag)');
$this->addSql('CREATE TABLE hashtag_link (id INT NOT NULL, hashtag_id INT NOT NULL, entry_id INT DEFAULT NULL, entry_comment_id INT DEFAULT NULL, post_id INT DEFAULT NULL, post_comment_id INT DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_83957168FB34EF56 ON hashtag_link (hashtag_id)');
$this->addSql('CREATE INDEX IDX_83957168BA364942 ON hashtag_link (entry_id)');
$this->addSql('CREATE INDEX IDX_8395716860C33421 ON hashtag_link (entry_comment_id)');
$this->addSql('CREATE INDEX IDX_839571684B89032C ON hashtag_link (post_id)');
$this->addSql('CREATE INDEX IDX_83957168DB1174D2 ON hashtag_link (post_comment_id)');
$this->addSql('ALTER TABLE hashtag_link ADD CONSTRAINT FK_83957168FB34EF56 FOREIGN KEY (hashtag_id) REFERENCES hashtag (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE hashtag_link ADD CONSTRAINT FK_83957168BA364942 FOREIGN KEY (entry_id) REFERENCES entry (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE hashtag_link ADD CONSTRAINT FK_8395716860C33421 FOREIGN KEY (entry_comment_id) REFERENCES entry_comment (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE hashtag_link ADD CONSTRAINT FK_839571684B89032C FOREIGN KEY (post_id) REFERENCES post (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE hashtag_link ADD CONSTRAINT FK_83957168DB1174D2 FOREIGN KEY (post_comment_id) REFERENCES post_comment (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');

// migrate entry tags
$select = "SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM entry e
JOIN LATERAL (SELECT * FROM jsonb_array_elements_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'array'
UNION ALL
SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM entry e
JOIN LATERAL (SELECT * FROM jsonb_each_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'object'
ORDER BY created_at DESC";
$foreachStatement = "IF NOT EXISTS (SELECT id FROM hashtag WHERE hashtag.tag = temprow.hashtag) THEN
INSERT INTO hashtag(id, tag) VALUES(NEXTVAL('hashtag_id_seq'), temprow.hashtag);
END IF;
IF NOT EXISTS (SELECT l.id FROM hashtag_link l
INNER JOIN hashtag def ON def.id=l.hashtag_id
WHERE l.entry_id = temprow.id AND def.tag = temprow.hashtag)
THEN
INSERT INTO hashtag_link (id, entry_id, hashtag_id) VALUES (NEXTVAL('hashtag_link_id_seq'), temprow.id, (SELECT id FROM hashtag WHERE tag = temprow.hashtag));
END IF;";

$this->addSql('DO
$do$
declare temprow record;
BEGIN
FOR temprow IN
'.$select.'
LOOP
'.$foreachStatement.'
END LOOP;
END
$do$;');

// migrate entry comments tags
$select = "SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM entry_comment e
JOIN LATERAL (SELECT * FROM jsonb_array_elements_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'array'
UNION ALL
SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM entry_comment e
JOIN LATERAL (SELECT * FROM jsonb_each_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'object'
ORDER BY created_at DESC";
$foreachStatement = "IF NOT EXISTS (SELECT id FROM hashtag WHERE hashtag.tag = temprow.hashtag) THEN
INSERT INTO hashtag(id, tag) VALUES(NEXTVAL('hashtag_id_seq'), temprow.hashtag);
END IF;
IF NOT EXISTS (SELECT l.id FROM hashtag_link l
INNER JOIN hashtag def ON def.id=l.hashtag_id
WHERE l.entry_comment_id = temprow.id AND def.tag = temprow.hashtag)
THEN
INSERT INTO hashtag_link (id, entry_comment_id, hashtag_id) VALUES (NEXTVAL('hashtag_link_id_seq'), temprow.id, (SELECT id FROM hashtag WHERE tag=temprow.hashtag));
END IF;";

$this->addSql('DO
$do$
declare temprow record;
BEGIN
FOR temprow IN
'.$select.'
LOOP
'.$foreachStatement.'
END LOOP;
END
$do$;');

// migrate post tags
$select = "SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM post e
JOIN LATERAL (SELECT * FROM jsonb_array_elements_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'array'
UNION ALL
SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM post e
JOIN LATERAL (SELECT * FROM jsonb_each_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'object'
ORDER BY created_at DESC";
$foreachStatement = "IF NOT EXISTS (SELECT id FROM hashtag WHERE hashtag.tag = temprow.hashtag) THEN
INSERT INTO hashtag(id, tag) VALUES(NEXTVAL('hashtag_id_seq'), temprow.hashtag);
END IF;
IF NOT EXISTS (SELECT l.id FROM hashtag_link l
INNER JOIN hashtag def ON def.id=l.hashtag_id
WHERE l.post_id = temprow.id AND def.tag = temprow.hashtag)
THEN
INSERT INTO hashtag_link (id, post_id, hashtag_id) VALUES (NEXTVAL('hashtag_link_id_seq'), temprow.id, (SELECT id FROM hashtag WHERE tag=temprow.hashtag));
END IF;";

$this->addSql('DO
$do$
declare temprow record;
BEGIN
FOR temprow IN
'.$select.'
LOOP
'.$foreachStatement.'
END LOOP;
END
$do$;');
// migrate post comment tags
$select = "SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM post_comment e
JOIN LATERAL (SELECT * FROM jsonb_array_elements_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'array'
UNION ALL
SELECT e.id, e.tags, keys.value::CITEXT as hashtag, e.created_at FROM post_comment e
JOIN LATERAL (SELECT * FROM jsonb_each_text(e.tags)) as keys ON TRUE
WHERE e.tags IS NOT NULL AND jsonb_typeof(e.tags) = 'object'
ORDER BY created_at DESC";
$foreachStatement = "IF NOT EXISTS (SELECT id FROM hashtag WHERE hashtag.tag = temprow.hashtag) THEN
INSERT INTO hashtag(id, tag) VALUES(NEXTVAL('hashtag_id_seq'), temprow.hashtag);
END IF;
IF NOT EXISTS (SELECT l.id FROM hashtag_link l
INNER JOIN hashtag def ON def.id=l.hashtag_id
WHERE l.post_comment_id = temprow.id AND def.tag = temprow.hashtag)
THEN
INSERT INTO hashtag_link (id, post_comment_id, hashtag_id) VALUES (NEXTVAL('hashtag_link_id_seq'), temprow.id, (SELECT id FROM hashtag WHERE tag=temprow.hashtag));
END IF;";

$this->addSql('DO
$do$
declare temprow record;
BEGIN
FOR temprow IN
'.$select.'
LOOP
'.$foreachStatement.'
END LOOP;
END
$do$;');

$this->addSql('ALTER TABLE entry DROP COLUMN tags');
$this->addSql('ALTER TABLE entry_comment DROP COLUMN tags');
$this->addSql('ALTER TABLE post DROP COLUMN tags');
$this->addSql('ALTER TABLE post_comment DROP COLUMN tags');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE entry_comment ADD tags JSONB DEFAULT NULL');
$this->addSql('ALTER TABLE post_comment ADD tags JSONB DEFAULT NULL');
$this->addSql('ALTER TABLE post ADD tags JSONB DEFAULT NULL');
$this->addSql('ALTER TABLE entry ADD tags JSONB DEFAULT NULL');

$this->addSql('DO
$do$
declare temprow record;
BEGIN
FOR temprow IN
SELECT hl.entry_id, hl.entry_comment_id, hl.post_id, hl.post_comment_id, h.tag FROM hashtag_link hl INNER JOIN hashtag h ON h.id = hl.hashtag_id
LOOP
IF temprow.entry_id IS NOT NULL THEN
IF NOT EXISTS (SELECT id FROM entry e WHERE e.id = temprow.entry_id AND e.tags IS NOT NULL) THEN
UPDATE entry SET tags = \'[]\'::jsonb WHERE entry.id = temprow.entry_id;
END IF;
UPDATE entry SET tags = tags || to_jsonb(temprow.tag) WHERE entry.id = temprow.entry_id;
END IF;
IF temprow.entry_comment_id IS NOT NULL THEN
IF NOT EXISTS (SELECT id FROM entry_comment ec WHERE ec.id = temprow.entry_comment_id AND ec.tags IS NOT NULL) THEN
UPDATE entry_comment SET tags = \'[]\'::jsonb WHERE entry_comment.id = temprow.entry_comment_id;
END IF;
UPDATE entry_comment SET tags = tags || to_jsonb(temprow.tag) WHERE entry_comment.id = temprow.entry_comment_id;
END IF;
IF temprow.post_id IS NOT NULL THEN
IF NOT EXISTS (SELECT id FROM post p WHERE p.id = temprow.post_id AND p.tags IS NOT NULL) THEN
UPDATE post SET tags = \'[]\'::jsonb WHERE post.id = temprow.post_id;
END IF;
UPDATE post SET tags = tags || to_jsonb(temprow.tag) WHERE post.id = temprow.post_id;
END IF;
IF temprow.post_comment_id IS NOT NULL THEN
IF NOT EXISTS (SELECT id FROM post_comment pc WHERE pc.id = temprow.post_comment_id AND pc.tags IS NOT NULL) THEN
UPDATE post_comment SET tags = \'[]\'::jsonb WHERE post_comment.id = temprow.post_comment_id;
END IF;
UPDATE post_comment SET tags = tags || to_jsonb(temprow.tag) WHERE post_comment.id = temprow.post_comment_id;
END IF;
END LOOP;
END
$do$;');

$this->addSql('DROP SEQUENCE hashtag_id_seq CASCADE');
$this->addSql('DROP SEQUENCE hashtag_link_id_seq CASCADE');
$this->addSql('ALTER TABLE hashtag_link DROP CONSTRAINT FK_83957168FB34EF56');
$this->addSql('ALTER TABLE hashtag_link DROP CONSTRAINT FK_83957168BA364942');
$this->addSql('ALTER TABLE hashtag_link DROP CONSTRAINT FK_8395716860C33421');
$this->addSql('ALTER TABLE hashtag_link DROP CONSTRAINT FK_839571684B89032C');
$this->addSql('ALTER TABLE hashtag_link DROP CONSTRAINT FK_83957168DB1174D2');
$this->addSql('DROP TABLE hashtag');
$this->addSql('DROP TABLE hashtag_link');
}
}
12 changes: 7 additions & 5 deletions src/Command/MoveEntriesByTagCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::FAILURE;
}

$qb = $this->entryRepository->createQueryBuilder('e');

$qb->andWhere("JSONB_CONTAINS(e.tags, '\"".$tag."\"') = true");

$entries = $qb->getQuery()->getResult();
$entries = $this->entryRepository->createQueryBuilder('e')
->where('t.tag = :tag')
->join('e.hashtags', 'h')
->join('h.hashtag', 't')
->setParameter('tag', $tag)
->getQuery()
->getResult();

foreach ($entries as $entry) {
/*
Expand Down
5 changes: 4 additions & 1 deletion src/Command/MovePostsByTagCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$qb = $this->postRepository->createQueryBuilder('p');

$qb->andWhere("JSONB_CONTAINS(p.tags, '\"".$tag."\"') = true");
$qb->andWhere('t.tag = :tag')
->join('p.hashtags', 'h')
->join('h.hashtag', 't')
->setParameter('tag', $tag);

$posts = $qb->getQuery()->getResult();

Expand Down
8 changes: 4 additions & 4 deletions src/Command/PostMagazinesUpdateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Entity\Post;
use App\Repository\MagazineRepository;
use App\Repository\PostRepository;
use App\Repository\TagLinkRepository;
use App\Service\PostManager;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
Expand All @@ -22,6 +23,7 @@ class PostMagazinesUpdateCommand extends Command
public function __construct(
private readonly PostRepository $postRepository,
private readonly PostManager $postManager,
private readonly TagLinkRepository $tagLinkRepository,
private readonly MagazineRepository $magazineRepository
) {
parent::__construct();
Expand All @@ -39,12 +41,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int

private function handleMagazine(Post $post, OutputInterface $output): void
{
if (!$post->tags) {
return;
}
$tags = $this->tagLinkRepository->getTagsOfPost($post);

$output->writeln((string) $post->getId());
foreach ($post->tags as $tag) {
foreach ($tags as $tag) {
if ($magazine = $this->magazineRepository->findOneByName($tag)) {
$output->writeln($magazine->name);
$this->postManager->changeMagazine($post, $magazine);
Expand Down
52 changes: 0 additions & 52 deletions src/Command/Update/TagsToJsonbUpdateCommand.php

This file was deleted.

Loading
Loading