From 05c63b241d27a4929ce37f852165e6a88bb5b570 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Sun, 19 Nov 2023 17:22:02 +0000 Subject: [PATCH] feat: Refactor mention rendering and generator classes - Add support for Mastodon username mentions - Add test for parsing Mastodon usernames in notes - Modify namespace and class imports for `MentionGenerator` and `MentionRenderer` in `Note.php` - Rename `ContactMentionGenerator.php` to `MentionGenerator.php` --- ...tionGenerator.php => MentionGenerator.php} | 2 +- .../Renderers/ContactMentionRenderer.php | 24 ------------ app/CommonMark/Renderers/MentionRenderer.php | 37 +++++++++++++++++++ app/Models/Note.php | 12 +++--- tests/Unit/NotesTest.php | 11 ++++++ 5 files changed, 55 insertions(+), 31 deletions(-) rename app/CommonMark/Generators/{ContactMentionGenerator.php => MentionGenerator.php} (84%) delete mode 100644 app/CommonMark/Renderers/ContactMentionRenderer.php create mode 100644 app/CommonMark/Renderers/MentionRenderer.php diff --git a/app/CommonMark/Generators/ContactMentionGenerator.php b/app/CommonMark/Generators/MentionGenerator.php similarity index 84% rename from app/CommonMark/Generators/ContactMentionGenerator.php rename to app/CommonMark/Generators/MentionGenerator.php index 507f2a0f..2ac1a797 100644 --- a/app/CommonMark/Generators/ContactMentionGenerator.php +++ b/app/CommonMark/Generators/MentionGenerator.php @@ -8,7 +8,7 @@ use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface; use League\CommonMark\Extension\Mention\Mention; use League\CommonMark\Node\Inline\AbstractInline; -class ContactMentionGenerator implements MentionGeneratorInterface +class MentionGenerator implements MentionGeneratorInterface { public function generateMention(Mention $mention): ?AbstractInline { diff --git a/app/CommonMark/Renderers/ContactMentionRenderer.php b/app/CommonMark/Renderers/ContactMentionRenderer.php deleted file mode 100644 index f227f121..00000000 --- a/app/CommonMark/Renderers/ContactMentionRenderer.php +++ /dev/null @@ -1,24 +0,0 @@ -getIdentifier())->first(); - - if ($contact === null) { - return '@' . $node->getIdentifier() . ''; - } - - return trim(view('templates.mini-hcard', ['contact' => $contact])->render()); - } -} diff --git a/app/CommonMark/Renderers/MentionRenderer.php b/app/CommonMark/Renderers/MentionRenderer.php new file mode 100644 index 00000000..d970fac8 --- /dev/null +++ b/app/CommonMark/Renderers/MentionRenderer.php @@ -0,0 +1,37 @@ +getIdentifier())->first(); + + // If we have a contact, render a mini-hcard + if ($contact) { + // rendering a blade template to a string, so can’t be an HtmlElement + return trim(view('templates.mini-hcard', ['contact' => $contact])->render()); + } + + // Otherwise, check the link is to the Mastodon profile + $mentionText = $node->getIdentifier(); + $parts = explode('@', $mentionText); + + // This is not [@]handle@instance, so return a Twitter link + if (count($parts) === 1) { + return new HtmlElement('a', ['href' => 'https://twitter.com/' . $parts[0]], '@' . $mentionText); + } + + // Render the Mastodon profile link + return new HtmlElement('a', ['href' => 'https://' . $parts[1] . '/@' . $parts[0]], '@' . $mentionText); + } +} diff --git a/app/Models/Note.php b/app/Models/Note.php index 99f2e193..39d0c5e1 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -4,8 +4,8 @@ declare(strict_types=1); namespace App\Models; -use App\CommonMark\Generators\ContactMentionGenerator; -use App\CommonMark\Renderers\ContactMentionRenderer; +use App\CommonMark\Generators\MentionGenerator; +use App\CommonMark\Renderers\MentionRenderer; use Codebird\Codebird; use Exception; use GuzzleHttp\Client; @@ -385,10 +385,10 @@ class Note extends Model { $config = [ 'mentions' => [ - 'contacts_handle' => [ + 'mentions_handle' => [ 'prefix' => '@', - 'pattern' => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)', - 'generator' => new ContactMentionGenerator(), + 'pattern' => '([\w@.])+(\b)', + 'generator' => new MentionGenerator(), ], ], ]; @@ -397,7 +397,7 @@ class Note extends Model $environment->addExtension(new CommonMarkCoreExtension()); $environment->addExtension(new AutolinkExtension()); $environment->addExtension(new MentionExtension()); - $environment->addRenderer(Mention::class, new ContactMentionRenderer()); + $environment->addRenderer(Mention::class, new MentionRenderer()); $environment->addRenderer(FencedCode::class, new FencedCodeRenderer()); $environment->addRenderer(IndentedCode::class, new IndentedCodeRenderer()); $markdownConverter = new MarkdownConverter($environment); diff --git a/tests/Unit/NotesTest.php b/tests/Unit/NotesTest.php index 990fe076..b252f416 100644 --- a/tests/Unit/NotesTest.php +++ b/tests/Unit/NotesTest.php @@ -437,4 +437,15 @@ class NotesTest extends TestCase $this->assertSame('Antarctica', $note->address); } + + /** @test */ + public function mastodonUsernamesAreParsedCorrectly(): void + { + $expected = '

Hi @freekmurze@phpc.social how are you?

' . PHP_EOL; + $note = Note::factory()->create([ + 'note' => 'Hi @freekmurze@phpc.social how are you?', + ]); + + $this->assertSame($expected, $note->note); + } }