From 72cb4fd7eb3ed2a148679c538ea517fcd42a56b1 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Fri, 4 Nov 2022 15:23:31 +0000 Subject: [PATCH] Allow notes to be syndicated to Mastodon --- .env.example | 2 + app/Jobs/SyndicateNoteToMastodon.php | 66 +++++++++++++++++++ app/Services/NoteService.php | 8 +++ config/bridgy.php | 18 +++++ ...26_180903_add_mastodon_syndication_url.php | 32 +++++++++ database/seeders/NotesTableSeeder.php | 1 + resources/views/templates/note.blade.php | 4 +- .../views/templates/social-links.blade.php | 12 ++++ tests/Feature/MicropubControllerTest.php | 19 +++++- .../Jobs/SyndicateNoteToMastodonJobTest.php | 39 +++++++++++ tests/Unit/NotesTest.php | 4 +- 11 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 app/Jobs/SyndicateNoteToMastodon.php create mode 100644 config/bridgy.php create mode 100644 database/migrations/2022_10_26_180903_add_mastodon_syndication_url.php create mode 100644 tests/Unit/Jobs/SyndicateNoteToMastodonJobTest.php diff --git a/.env.example b/.env.example index 114a68a0..d1a26e82 100644 --- a/.env.example +++ b/.env.example @@ -66,3 +66,5 @@ SECURE_SESSION_COOKIE=true LOG_SLACK_WEBHOOK_URL= FONT_LINK= + +BRIDGY_MASTODON_TOKEN= diff --git a/app/Jobs/SyndicateNoteToMastodon.php b/app/Jobs/SyndicateNoteToMastodon.php new file mode 100644 index 00000000..8c75f52e --- /dev/null +++ b/app/Jobs/SyndicateNoteToMastodon.php @@ -0,0 +1,66 @@ +request( + 'POST', + 'https://brid.gy/micropub', + [ + 'headers' => [ + 'Authorization' => 'Bearer ' . config('bridgy.mastodon_token'), + ], + 'json' => [ + 'type' => ['h-entry'], + 'properties' => [ + 'content' => [$this->note->note], + ], + ], + ] + ); + + // Parse for syndication URL + if ($response->getStatusCode() === 201) { + $mastodonUrl = $response->getHeader('Location')[0]; + $this->note->mastodon_url = $mastodonUrl; + $this->note->save(); + } + } +} diff --git a/app/Services/NoteService.php b/app/Services/NoteService.php index 57458389..156acbfb 100644 --- a/app/Services/NoteService.php +++ b/app/Services/NoteService.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Services; use App\Jobs\SendWebMentions; +use App\Jobs\SyndicateNoteToMastodon; use App\Jobs\SyndicateNoteToTwitter; use App\Models\Media; use App\Models\Note; @@ -58,6 +59,10 @@ class NoteService dispatch(new SyndicateNoteToTwitter($note)); } + if (in_array('mastodon', $this->getSyndicationTargets($request), true)) { + dispatch(new SyndicateNoteToMastodon($note)); + } + return $note; } @@ -212,6 +217,9 @@ class NoteService if ($target && $target->service_name === 'Twitter') { $syndication[] = 'twitter'; } + if ($target && $target->service_name === 'Mastodon') { + $syndication[] = 'mastodon'; + } } return $syndication; diff --git a/config/bridgy.php b/config/bridgy.php new file mode 100644 index 00000000..9717625f --- /dev/null +++ b/config/bridgy.php @@ -0,0 +1,18 @@ + env('BRIDGY_MASTODON_TOKEN'), + +]; diff --git a/database/migrations/2022_10_26_180903_add_mastodon_syndication_url.php b/database/migrations/2022_10_26_180903_add_mastodon_syndication_url.php new file mode 100644 index 00000000..48c4403e --- /dev/null +++ b/database/migrations/2022_10_26_180903_add_mastodon_syndication_url.php @@ -0,0 +1,32 @@ +string('mastodon_url')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('notes', function (Blueprint $table) { + $table->dropColumn('mastodon_url'); + }); + } +}; diff --git a/database/seeders/NotesTableSeeder.php b/database/seeders/NotesTableSeeder.php index 2bf9a82a..4a0a0bec 100644 --- a/database/seeders/NotesTableSeeder.php +++ b/database/seeders/NotesTableSeeder.php @@ -137,6 +137,7 @@ class NotesTableSeeder extends Seeder $noteSyndicated->facebook_url = 'https://www.facebook.com/post/12345789'; $noteSyndicated->swarm_url = 'https://www.swarmapp.com/checking/123456789'; $noteSyndicated->instagram_url = 'https://www.instagram.com/p/aWsEd123Jh'; + $noteSyndicated->mastodon_url = 'https://mastodon.social/@jonnybarnes/123456789'; $noteSyndicated->save(); DB::table('notes') ->where('id', $noteSyndicated->id) diff --git a/resources/views/templates/note.blade.php b/resources/views/templates/note.blade.php index 20309057..ebb2cbe4 100644 --- a/resources/views/templates/note.blade.php +++ b/resources/views/templates/note.blade.php @@ -33,12 +33,14 @@ $note->tweet_id || $note->facebook_url || $note->swarm_url || - $note->instagram_url) + $note->instagram_url || + $note->mastodon_url) @include('templates.social-links', [ 'tweet_id' => $note->tweet_id, 'facebook_url' => $note->facebook_url, 'swarm_url' => $note->swarm_url, 'instagram_url' => $note->instagram_url, + 'mastodon_url' => $note->mastodon_url, ]) @endif diff --git a/resources/views/templates/social-links.blade.php b/resources/views/templates/social-links.blade.php index 99e16753..cdfeb619 100644 --- a/resources/views/templates/social-links.blade.php +++ b/resources/views/templates/social-links.blade.php @@ -27,3 +27,15 @@ @endif +@if($mastodon_url !== null) + + + + + + + + + + +@endif diff --git a/tests/Feature/MicropubControllerTest.php b/tests/Feature/MicropubControllerTest.php index 12604ad3..aa42b0a6 100644 --- a/tests/Feature/MicropubControllerTest.php +++ b/tests/Feature/MicropubControllerTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Tests\Feature; use App\Jobs\SendWebMentions; +use App\Jobs\SyndicateNoteToMastodon; use App\Jobs\SyndicateNoteToTwitter; use App\Models\Media; use App\Models\Note; @@ -123,7 +124,7 @@ class MicropubControllerTest extends TestCase } /** @test */ - public function micropubClientCanRequestTheNewNoteIsSyndicatedToTwitter(): void + public function micropubClientCanRequestTheNewNoteIsSyndicatedToTwitterAndMastodon(): void { Queue::fake(); @@ -131,6 +132,10 @@ class MicropubControllerTest extends TestCase 'uid' => 'https://twitter.com/jonnybarnes', 'service_name' => 'Twitter', ]); + SyndicationTarget::factory()->create([ + 'uid' => 'https://mastodon.social/@jonnybarnes', + 'service_name' => 'Mastodon', + ]); $faker = Factory::create(); $note = $faker->text; @@ -139,13 +144,17 @@ class MicropubControllerTest extends TestCase [ 'h' => 'entry', 'content' => $note, - 'mp-syndicate-to' => 'https://twitter.com/jonnybarnes', + 'mp-syndicate-to' => [ + 'https://twitter.com/jonnybarnes', + 'https://mastodon.social/@jonnybarnes', + ], ], ['HTTP_Authorization' => 'Bearer ' . $this->getToken()] ); $response->assertJson(['response' => 'created']); $this->assertDatabaseHas('notes', ['note' => $note]); Queue::assertPushed(SyndicateNoteToTwitter::class); + Queue::assertPushed(SyndicateNoteToMastodon::class); } /** @test */ @@ -243,6 +252,10 @@ class MicropubControllerTest extends TestCase 'uid' => 'https://twitter.com/jonnybarnes', 'service_name' => 'Twitter', ]); + SyndicationTarget::factory()->create([ + 'uid' => 'https://mastodon.social/@jonnybarnes', + 'service_name' => 'Mastodon', + ]); $faker = Factory::create(); $note = $faker->text; @@ -255,6 +268,7 @@ class MicropubControllerTest extends TestCase 'in-reply-to' => ['https://aaronpk.localhost'], 'mp-syndicate-to' => [ 'https://twitter.com/jonnybarnes', + 'https://mastodon.social/@jonnybarnes', ], 'photo' => [config('filesystems.disks.s3.url') . '/test-photo.jpg'], ], @@ -266,6 +280,7 @@ class MicropubControllerTest extends TestCase ->assertJson(['response' => 'created']); Queue::assertPushed(SendWebMentions::class); Queue::assertPushed(SyndicateNoteToTwitter::class); + Queue::assertPushed(SyndicateNoteToMastodon::class); } /** diff --git a/tests/Unit/Jobs/SyndicateNoteToMastodonJobTest.php b/tests/Unit/Jobs/SyndicateNoteToMastodonJobTest.php new file mode 100644 index 00000000..be7bf6d2 --- /dev/null +++ b/tests/Unit/Jobs/SyndicateNoteToMastodonJobTest.php @@ -0,0 +1,39 @@ + 'test']); + $faker = Factory::create(); + $randomNumber = $faker->randomNumber(); + $mock = new MockHandler([ + new Response(201, ['Location' => 'https://mastodon.example/@jonny/' . $randomNumber]), + ]); + $handler = HandlerStack::create($mock); + $client = new Client(['handler' => $handler]); + + $note = Note::factory()->create(); + $job = new SyndicateNoteToMastodon($note); + $job->handle($client); + + $this->assertDatabaseHas('notes', [ + 'mastodon_url' => 'https://mastodon.example/@jonny/' . $randomNumber, + ]); + } +} diff --git a/tests/Unit/NotesTest.php b/tests/Unit/NotesTest.php index 489673c2..098516b9 100644 --- a/tests/Unit/NotesTest.php +++ b/tests/Unit/NotesTest.php @@ -113,8 +113,8 @@ class NotesTest extends TestCase /** @test */ public function shorturlMethodReturnsExpectedValue(): void { - Note::factory(14)->create(); - $note = Note::find(14); + $note = Note::factory()->make(); + $note->id = 14; $this->assertEquals(config('app.shorturl') . '/notes/E', $note->shorturl); }