diff --git a/.env.example b/.env.example index b9bedb501..2d2180caa 100644 --- a/.env.example +++ b/.env.example @@ -44,6 +44,9 @@ TWITTER_CONSUMER_SECRET= TWITTER_ACCESS_TOKEN= TWITTER_ACCESS_SECRET= +BLUESKY_USERNAME= +BLUESKY_PASSWORD= + TELEGRAM_BOT_TOKEN= TELEGRAM_CHANNEL= diff --git a/README.md b/README.md index 7fb644cb0..5d419200b 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ New threads will be automatically added to the index and threads which get updat php artisan scout:flush App\\Models\\Thread ``` -### X (Twitter) Sharing (optional) +### Social Media Sharing (optional) To enable published articles to be automatically shared on X, you'll need to [create an app](https://developer.x.com/apps/). Once the app has been created, update the below variables in your `.env` file. The consumer key and secret and access token and secret can be found in the `Keys and tokens` section of the X developers UI. @@ -103,6 +103,13 @@ TWITTER_ACCESS_TOKEN= TWITTER_ACCESS_SECRET= ``` +To do the same for Bluesky you simply need to set up the app keys with your login and password: + +``` +BLUESKY_USERNAME= +BLUESKY_PASSWORD= +``` + Approved articles are shared in the order they were submitted for approval. Articles are shared twice per day at 14:00 and 18:00 UTC. Once an article has been shared, it will not be shared again. ### Telegram Notifications (optional) diff --git a/app/Console/Commands/PostArticleToTwitter.php b/app/Console/Commands/PostArticleToSocialMedia.php similarity index 52% rename from app/Console/Commands/PostArticleToTwitter.php rename to app/Console/Commands/PostArticleToSocialMedia.php index fcb988346..7a198ed60 100644 --- a/app/Console/Commands/PostArticleToTwitter.php +++ b/app/Console/Commands/PostArticleToSocialMedia.php @@ -3,20 +3,22 @@ namespace App\Console\Commands; use App\Models\Article; -use App\Notifications\PostArticleToTwitter as PostArticleToTwitterNotification; +use App\Notifications\PostArticleToBluesky; +use App\Notifications\PostArticleToTwitter; use Illuminate\Console\Command; use Illuminate\Notifications\AnonymousNotifiable; -final class PostArticleToTwitter extends Command +final class PostArticleToSocialMedia extends Command { - protected $signature = 'lio:post-article-to-twitter'; + protected $signature = 'lio:post-article-to-social-media'; - protected $description = 'Posts the latest unshared article to X'; + protected $description = 'Posts the latest unshared article to social media'; public function handle(AnonymousNotifiable $notifiable): void { if ($article = Article::nextForSharing()) { - $notifiable->notify(new PostArticleToTwitterNotification($article)); + $notifiable->notify(new PostArticleToBluesky($article)); + $notifiable->notify(new PostArticleToTwitter($article)); $article->markAsShared(); } diff --git a/app/Http/Requests/UpdateProfileRequest.php b/app/Http/Requests/UpdateProfileRequest.php index 031ac123d..160e95df0 100644 --- a/app/Http/Requests/UpdateProfileRequest.php +++ b/app/Http/Requests/UpdateProfileRequest.php @@ -13,6 +13,7 @@ public function rules(): array 'email' => 'required|email|max:255|unique:users,email,'.Auth::id(), 'username' => 'required|alpha_dash|max:255|unique:users,username,'.Auth::id(), 'twitter' => 'max:255|nullable|unique:users,twitter,'.Auth::id(), + 'bluesky' => 'max:255|nullable|unique:users,bluesky,'.Auth::id(), 'website' => 'max:255|nullable|url', 'bio' => 'max:160', ]; @@ -43,6 +44,11 @@ public function twitter(): ?string return $this->get('twitter'); } + public function bluesky(): ?string + { + return $this->get('bluesky'); + } + public function website(): ?string { return $this->get('website'); diff --git a/app/Http/Resources/AuthorResource.php b/app/Http/Resources/AuthorResource.php index 23a1e27e2..86bbe5b6c 100644 --- a/app/Http/Resources/AuthorResource.php +++ b/app/Http/Resources/AuthorResource.php @@ -18,6 +18,7 @@ public function toArray($request): array 'name' => $this->name(), 'bio' => $this->bio(), 'twitter_handle' => $this->twitter(), + 'bluesky_handle' => $this->bluesky(), 'github_username' => $this->githubUsername(), ]; } diff --git a/app/Jobs/UpdateProfile.php b/app/Jobs/UpdateProfile.php index b620a61c6..45182bf12 100644 --- a/app/Jobs/UpdateProfile.php +++ b/app/Jobs/UpdateProfile.php @@ -16,7 +16,7 @@ public function __construct( array $attributes = [] ) { $this->attributes = Arr::only($attributes, [ - 'name', 'email', 'username', 'github_username', 'bio', 'twitter', 'website', + 'name', 'email', 'username', 'github_username', 'bio', 'twitter', 'bluesky', 'website', ]); } @@ -28,6 +28,7 @@ public static function fromRequest(User $user, UpdateProfileRequest $request): s 'username' => strtolower($request->username()), 'bio' => trim(strip_tags($request->bio())), 'twitter' => $request->twitter(), + 'bluesky' => $request->bluesky(), 'website' => $request->website(), ]); } diff --git a/app/Models/User.php b/app/Models/User.php index 3515d8420..10d41fb9a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -46,6 +46,7 @@ final class User extends Authenticatable implements MustVerifyEmail 'name', 'email', 'twitter', + 'bluesky', 'website', 'username', 'password', @@ -110,6 +111,11 @@ public function twitter(): ?string return $this->twitter; } + public function bluesky(): ?string + { + return $this->bluesky; + } + public function website(): ?string { return $this->website; @@ -120,6 +126,11 @@ public function hasTwitterAccount(): bool return ! empty($this->twitter()); } + public function hasBlueskyAccount(): bool + { + return ! empty($this->bluesky()); + } + public function hasWebsite(): bool { return ! empty($this->website()); diff --git a/app/Notifications/PostArticleToBluesky.php b/app/Notifications/PostArticleToBluesky.php new file mode 100644 index 000000000..fd0162570 --- /dev/null +++ b/app/Notifications/PostArticleToBluesky.php @@ -0,0 +1,42 @@ +text($this->generatePost()); + } + + public function generatePost(): string + { + $title = $this->article->title(); + $url = route('articles.show', $this->article->slug()); + $author = $this->article->author(); + $author = $author->bluesky() ? "@{$author->bluesky()}" : $author->name(); + + return "{$title} by {$author}\n\n{$url}"; + } + + public function article() + { + return $this->article; + } +} diff --git a/app/Notifications/PostArticleToTwitter.php b/app/Notifications/PostArticleToTwitter.php index 4cd1b96be..d2785fc5b 100644 --- a/app/Notifications/PostArticleToTwitter.php +++ b/app/Notifications/PostArticleToTwitter.php @@ -24,7 +24,7 @@ public function toTwitter($notifiable) return new TwitterStatusUpdate($this->generateTweet()); } - public function generateTweet() + public function generateTweet(): string { $title = $this->article->title(); $url = route('articles.show', $this->article->slug()); diff --git a/composer.json b/composer.json index ed0e9211e..2151c6622 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "blade-ui-kit/blade-zondicons": "^1.5", "codeat3/blade-simple-icons": "^5.0", "guzzlehttp/guzzle": "^7.2", + "innocenzi/bluesky-notification-channel": "^0.2.0", "intervention/image": "^2.7", "laravel-notification-channels/telegram": "^5.0", "laravel-notification-channels/twitter": "^8.1.1", diff --git a/composer.lock b/composer.lock index 18a30964b..65b6d0f9c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b73667ac3de654bc08e32d2b17c974b7", + "content-hash": "78099b0bf3f4baa0b5748d997e7add1c", "packages": [ { "name": "abraham/twitteroauth", @@ -1926,6 +1926,79 @@ ], "time": "2023-12-03T19:50:20+00:00" }, + { + "name": "innocenzi/bluesky-notification-channel", + "version": "v0.2.0", + "source": { + "type": "git", + "url": "https://github.com/innocenzi/bluesky-notification-channel.git", + "reference": "3f9076affc639d8e1f9bdfcaaf996c87626532ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/innocenzi/bluesky-notification-channel/zipball/3f9076affc639d8e1f9bdfcaaf996c87626532ef", + "reference": "3f9076affc639d8e1f9bdfcaaf996c87626532ef", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^11.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.16.5" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.64", + "guzzlehttp/guzzle": "^7.9.2", + "nunomaduro/collision": "^8.5", + "orchestra/testbench": "^9.5.2", + "pestphp/pest": "^3.5", + "pestphp/pest-plugin-arch": "^3.0", + "pestphp/pest-plugin-laravel": "^3.0", + "spatie/laravel-ray": "^1.37.1" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NotificationChannels\\Bluesky\\BlueskyServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "NotificationChannels\\Bluesky\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Enzo Innocenzi", + "email": "enzo@innocenzi.dev", + "role": "Developer" + } + ], + "description": "Bluesky notification channel for the Laravel framework", + "homepage": "https://github.com/innocenzi/bluesky-notification-channel", + "keywords": [ + "Enzo Innocenzi", + "bluesky", + "laravel", + "notification-channel" + ], + "support": { + "issues": "https://github.com/innocenzi/bluesky-notification-channel/issues", + "source": "https://github.com/innocenzi/bluesky-notification-channel/tree/v0.2.0" + }, + "funding": [ + { + "url": "https://github.com/Enzo Innocenzi", + "type": "github" + } + ], + "time": "2024-10-29T15:53:16+00:00" + }, { "name": "intervention/image", "version": "2.7.2", diff --git a/config/services.php b/config/services.php index 2a575db66..455d70c87 100644 --- a/config/services.php +++ b/config/services.php @@ -30,6 +30,11 @@ 'access_secret' => env('TWITTER_ACCESS_SECRET'), ], + 'bluesky' => [ + 'username' => env('BLUESKY_USERNAME'), + 'password' => env('BLUESKY_PASSWORD'), + ], + 'telegram-bot-api' => [ 'token' => env('TELEGRAM_BOT_TOKEN'), 'channel' => env('TELEGRAM_CHANNEL'), diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index f771f2cb9..f434385cc 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -24,6 +24,7 @@ public function definition(): array 'github_id' => $this->faker->unique()->numberBetween(10000, 99999), 'github_username' => $this->faker->unique()->userName(), 'twitter' => $this->faker->unique()->userName(), + 'bluesky' => $this->faker->unique()->userName(), 'website' => 'https://laravel.io', 'banned_at' => null, 'banned_reason' => null, diff --git a/database/migrations/2024_11_28_202608_add_bluesky_column_to_users.php b/database/migrations/2024_11_28_202608_add_bluesky_column_to_users.php new file mode 100644 index 000000000..36c32a503 --- /dev/null +++ b/database/migrations/2024_11_28_202608_add_bluesky_column_to_users.php @@ -0,0 +1,15 @@ +string('bluesky')->nullable()->after('twitter'); + }); + } +}; diff --git a/resources/svg/bluesky.svg b/resources/svg/bluesky.svg new file mode 100644 index 000000000..dfcf3b307 --- /dev/null +++ b/resources/svg/bluesky.svg @@ -0,0 +1,4 @@ + + Bluesky + + diff --git a/resources/views/articles/show.blade.php b/resources/views/articles/show.blade.php index ece6e8852..34d980704 100644 --- a/resources/views/articles/show.blade.php +++ b/resources/views/articles/show.blade.php @@ -172,6 +172,12 @@ class="prose prose-lg text-gray-800 prose-lio" @endif + @if ($article->author()->hasBlueskyAccount()) + + + + @endif + @if ($article->author()->hasWebsite()) diff --git a/resources/views/components/articles/form.blade.php b/resources/views/components/articles/form.blade.php index 8e5c6bbf3..e4229d806 100644 --- a/resources/views/components/articles/form.blade.php +++ b/resources/views/components/articles/form.blade.php @@ -146,10 +146,10 @@ class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:t - @unless (Auth::user()->twitter()) + @unless (Auth::user()->hasTwitterAccount() && Auth::user()->hasBlueskyAccount()) Articles will be shared on X (Twitter). - Add your X (Twitter) handle and we'll include that too. + Add your X (Twitter) and/or Bluesky handles and we'll include that too. @endunless diff --git a/resources/views/components/users/profile-block.blade.php b/resources/views/components/users/profile-block.blade.php index 0f82afa3a..c69785c7e 100644 --- a/resources/views/components/users/profile-block.blade.php +++ b/resources/views/components/users/profile-block.blade.php @@ -28,6 +28,12 @@ @endif + @if ($user->hasBlueskyAccount()) + + + + @endif + @if ($user->hasWebsite()) diff --git a/resources/views/layouts/_footer.blade.php b/resources/views/layouts/_footer.blade.php index b309e68b3..f42967e6a 100644 --- a/resources/views/layouts/_footer.blade.php +++ b/resources/views/layouts/_footer.blade.php @@ -46,6 +46,11 @@ (Twitter) + + + Bluesky + + GitHub diff --git a/resources/views/layouts/_nav.blade.php b/resources/views/layouts/_nav.blade.php index 6a8119589..4f6c0f841 100644 --- a/resources/views/layouts/_nav.blade.php +++ b/resources/views/layouts/_nav.blade.php @@ -9,14 +9,6 @@
- - - - - - - - @@ -141,14 +133,6 @@
- - - - diff --git a/resources/views/users/articles.blade.php b/resources/views/users/articles.blade.php index 51ce0d762..1cdd620e7 100644 --- a/resources/views/users/articles.blade.php +++ b/resources/views/users/articles.blade.php @@ -20,9 +20,9 @@ @section('content')
- @unless(Auth::user()->hasTwitterAccount()) + @unless(Auth::user()->hasTwitterAccount() && Auth::user()->hasBlueskyAccount()) - Set your X (Twitter) handle so we can link to your profile when we tweet out your article. + Set your X (Twitter) and/or Bluesky handles so we can link to your profiles when we tweet out your article. @endunless diff --git a/resources/views/users/profile.blade.php b/resources/views/users/profile.blade.php index 5568a31cf..c29d81e91 100644 --- a/resources/views/users/profile.blade.php +++ b/resources/views/users/profile.blade.php @@ -52,6 +52,12 @@ class="w-full bg-center bg-gray-800 h-60 container mx-auto" @endif + @if ($user->hasBlueskyAccount()) + + + + @endif + @if ($user->hasWebsite()) diff --git a/resources/views/users/settings/profile.blade.php b/resources/views/users/settings/profile.blade.php index 8d5fe287f..528750c9b 100644 --- a/resources/views/users/settings/profile.blade.php +++ b/resources/views/users/settings/profile.blade.php @@ -93,6 +93,16 @@ Enter your X (Twitter) handle without the leading @ symbol
+ +
+ Bluesky handle + + + + + Enter your Bluesky handle without the leading @ symbol + +
diff --git a/routes/console.php b/routes/console.php index 7af19abbe..b45ac35de 100644 --- a/routes/console.php +++ b/routes/console.php @@ -6,6 +6,6 @@ Schedule::command('schedule-monitor:sync')->dailyAt('04:56'); Schedule::command('model:prune', ['--model' => MonitoredScheduledTaskLogItem::class])->daily(); Schedule::command('horizon:snapshot')->everyFiveMinutes(); -Schedule::command('lio:post-article-to-twitter')->twiceDaily(14, 18); +Schedule::command('lio:post-article-to-social-media')->twiceDaily(14, 18); Schedule::command('lio:generate-sitemap')->daily()->graceTimeInMinutes(25); Schedule::command('lio:update-article-view-counts')->twiceDaily(); diff --git a/tests/Feature/ArticleTest.php b/tests/Feature/ArticleTest.php index 3ac0e4104..844cd24a3 100644 --- a/tests/Feature/ArticleTest.php +++ b/tests/Feature/ArticleTest.php @@ -489,16 +489,24 @@ $this->login(['twitter' => null]); $this->get('/articles/authored') - ->assertSeeText('X (Twitter) handle', '') - ->assertSee('so we can link to your profile when we tweet out your article.'); + ->assertSeeText('X (Twitter) and/or Bluesky handles', '') + ->assertSee('so we can link to your profiles when we tweet out your article.'); +}); + +test('user see a tip if they have not set the bluesky handle', function () { + $this->login(['bluesky' => null]); + + $this->get('/articles/authored') + ->assertSeeText('X (Twitter) and/or Bluesky handles', '') + ->assertSee('so we can link to your profiles when we tweet out your article.'); }); test('user do not see tip if they have set the twitter handle', function () { $this->login(); $this->get('/articles/authored') - ->assertDontSeeText('X (Twitter) handle', '') - ->assertDontSee('so we can link to your profile when we tweet out your article.'); + ->assertDontSeeText('X (Twitter) and/or Bluesky handles', '') + ->assertDontSee('so we can link to your profiles when we tweet out your article.'); }); test('loading page with invalid sort parameter defaults to recent', function () { diff --git a/tests/Feature/SettingsTest.php b/tests/Feature/SettingsTest.php index 81c314e5b..620282dd7 100644 --- a/tests/Feature/SettingsTest.php +++ b/tests/Feature/SettingsTest.php @@ -25,6 +25,7 @@ 'email' => 'freek@example.com', 'username' => 'freekmurze', 'twitter' => 'freektwitter', + 'bluesky' => 'driesbsky', 'website' => 'https://laravel.io', 'bio' => 'My bio', ]) @@ -34,6 +35,7 @@ ->assertSee('Freek Murze') ->assertSee('freekmurze') ->assertSee('freektwitter') + ->assertSee('driesbsky') ->assertSee('Settings successfully saved!') ->assertSee('My bio'); }); @@ -147,7 +149,11 @@ }); test('twitter is optional', function () { - $user = $this->createUser(['email' => 'freek@example.com', 'username' => 'freekmurze', 'twitter' => 'freektwitter']); + $user = $this->createUser([ + 'email' => 'freek@example.com', + 'username' => 'freekmurze', + 'twitter' => 'freektwitter', + ]); $this->loginAs($user); @@ -166,6 +172,30 @@ expect($user->fresh()->twitter())->toBeEmpty(); }); +test('bluesky is optional', function () { + $user = $this->createUser([ + 'email' => 'freek@example.com', + 'username' => 'freekmurze', + 'bluesky' => 'driesbsky', + ]); + + $this->loginAs($user); + + $response = $this->actingAs($user) + ->put('/settings', [ + 'name' => 'Freek Murze', + 'email' => 'freek@example.com', + 'username' => 'freekmurze', + 'bluesky' => '', + ]) + ->assertRedirect('/settings'); + + $this->followRedirects($response) + ->assertDontSee('driesbsky'); + + expect($user->fresh()->bluesky())->toBeEmpty(); +}); + test('website is optional', function () { $user = $this->createUser(['email' => 'freek@example.com', 'username' => 'freekmurze', 'twitter' => 'freektwitter', 'website' => 'https://laravel.io']); diff --git a/tests/Integration/Api/ArticleTest.php b/tests/Integration/Api/ArticleTest.php index 655f1d588..d2e9a8fd7 100644 --- a/tests/Integration/Api/ArticleTest.php +++ b/tests/Integration/Api/ArticleTest.php @@ -35,6 +35,7 @@ 'name' => $user->name(), 'bio' => $user->bio(), 'twitter_handle' => $user->twitter(), + 'bluesky_handle' => $user->bluesky(), 'github_username' => $user->githubUsername(), ], 'tags' => [[ @@ -80,6 +81,7 @@ 'name' => $user->name(), 'bio' => $user->bio(), 'twitter_handle' => $user->twitter(), + 'bluesky_handle' => $user->bluesky(), 'github_username' => $user->githubUsername(), ], 'tags' => [[ diff --git a/tests/Integration/Commands/PostArticleToTwitterTest.php b/tests/Integration/Commands/PostArticleToSocialMediaTest.php similarity index 57% rename from tests/Integration/Commands/PostArticleToTwitterTest.php rename to tests/Integration/Commands/PostArticleToSocialMediaTest.php index a9cbacd11..f519702cd 100644 --- a/tests/Integration/Commands/PostArticleToTwitterTest.php +++ b/tests/Integration/Commands/PostArticleToSocialMediaTest.php @@ -1,8 +1,9 @@ now(), ]); - (new PostArticleToTwitter)->handle(new AnonymousNotifiable); + (new PostArticleToSocialMedia)->handle(new AnonymousNotifiable); Notification::assertSentTo( new AnonymousNotifiable, - PostArticleToTwitterNotification::class, + PostArticleToBluesky::class, + function ($notification, $channels, $notifiable) use ($article) { + $post = $notification->generatePost(); + + return + Str::contains($post, 'My First Article') && + Str::contains($post, route('articles.show', $article->slug())); + }, + ); + + Notification::assertSentTo( + new AnonymousNotifiable, + PostArticleToTwitter::class, function ($notification, $channels, $notifiable) use ($article) { $tweet = $notification->generateTweet(); @@ -40,8 +53,9 @@ function ($notification, $channels, $notifiable) use ($article) { expect($article->fresh()->isShared())->toBeTrue(); }); -test('articles are shared with twitter handle', function () { +test('articles are shared with twitter and bluesky handles', function () { $user = $this->createUser([ + 'bluesky' => 'driesvints.com', 'twitter' => '_joedixon', ]); @@ -51,20 +65,28 @@ function ($notification, $channels, $notifiable) use ($article) { 'approved_at' => now(), ]); - (new PostArticleToTwitter)->handle(new AnonymousNotifiable); + (new PostArticleToSocialMedia)->handle(new AnonymousNotifiable); Notification::assertSentTo( new AnonymousNotifiable, - PostArticleToTwitterNotification::class, + PostArticleToBluesky::class, + function ($notification, $channels, $notifiable) { + return Str::contains($notification->generatePost(), '@driesvints.com'); + }, + ); + Notification::assertSentTo( + new AnonymousNotifiable, + PostArticleToTwitter::class, function ($notification, $channels, $notifiable) { return Str::contains($notification->generateTweet(), '@_joedixon'); }, ); }); -test('articles are shared with name when no twitter handle', function () { +test('articles are shared with name when no twitter or bluesky handles', function () { $user = $this->createUser([ 'name' => 'Joe Dixon', + 'bluesky' => null, 'twitter' => null, ]); @@ -74,11 +96,18 @@ function ($notification, $channels, $notifiable) { 'approved_at' => now(), ]); - (new PostArticleToTwitter)->handle(new AnonymousNotifiable); + (new PostArticleToSocialMedia)->handle(new AnonymousNotifiable); Notification::assertSentTo( new AnonymousNotifiable, - PostArticleToTwitterNotification::class, + PostArticleToBluesky::class, + function ($notification, $channels, $notifiable) { + return Str::contains($notification->generatePost(), 'Joe Dixon'); + }, + ); + Notification::assertSentTo( + new AnonymousNotifiable, + PostArticleToTwitter::class, function ($notification, $channels, $notifiable) { return Str::contains($notification->generateTweet(), 'Joe Dixon'); }, @@ -92,7 +121,7 @@ function ($notification, $channels, $notifiable) { 'shared_at' => now(), ]); - (new PostArticleToTwitter)->handle(new AnonymousNotifiable); + (new PostArticleToSocialMedia)->handle(new AnonymousNotifiable); Notification::assertNothingSent(); }); @@ -102,7 +131,7 @@ function ($notification, $channels, $notifiable) { 'submitted_at' => now(), ]); - (new PostArticleToTwitter)->handle(new AnonymousNotifiable); + (new PostArticleToSocialMedia)->handle(new AnonymousNotifiable); Notification::assertNothingSent(); }); @@ -110,7 +139,7 @@ function ($notification, $channels, $notifiable) { test('unsubmitted articles are not shared', function () { Article::factory()->create(); - (new PostArticleToTwitter)->handle(new AnonymousNotifiable); + (new PostArticleToSocialMedia)->handle(new AnonymousNotifiable); Notification::assertNothingSent(); });