Skip to content

Commit

Permalink
Implement Bluesky
Browse files Browse the repository at this point in the history
  • Loading branch information
driesvints committed Nov 28, 2024
1 parent 1018668 commit 0765fdd
Show file tree
Hide file tree
Showing 28 changed files with 306 additions and 48 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ TWITTER_CONSUMER_SECRET=
TWITTER_ACCESS_TOKEN=
TWITTER_ACCESS_SECRET=

BLUESKY_USERNAME=
BLUESKY_PASSWORD=

TELEGRAM_BOT_TOKEN=
TELEGRAM_CHANNEL=

Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
6 changes: 6 additions & 0 deletions app/Http/Requests/UpdateProfileRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
];
Expand Down Expand Up @@ -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');
Expand Down
1 change: 1 addition & 0 deletions app/Http/Resources/AuthorResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
];
}
Expand Down
3 changes: 2 additions & 1 deletion app/Jobs/UpdateProfile.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
]);
}

Expand All @@ -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(),
]);
}
Expand Down
11 changes: 11 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ final class User extends Authenticatable implements MustVerifyEmail
'name',
'email',
'twitter',
'bluesky',
'website',
'username',
'password',
Expand Down Expand Up @@ -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;
Expand All @@ -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());
Expand Down
42 changes: 42 additions & 0 deletions app/Notifications/PostArticleToBluesky.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace App\Notifications;

use App\Models\Article;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use NotificationChannels\Bluesky\BlueskyChannel;
use NotificationChannels\Bluesky\BlueskyPost;

class PostArticleToBluesky extends Notification
{
use Queueable;

public function __construct(private Article $article) {}

public function via($notifiable): array
{
return [BlueskyChannel::class];
}

public function toBluesky($notifiable)
{
return BlueskyPost::make()
->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;
}
}
2 changes: 1 addition & 1 deletion app/Notifications/PostArticleToTwitter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
75 changes: 74 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
1 change: 1 addition & 0 deletions database/factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('bluesky')->nullable()->after('twitter');
});
}
};
4 changes: 4 additions & 0 deletions resources/svg/bluesky.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions resources/views/articles/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ class="prose prose-lg text-gray-800 prose-lio"
</a>
@endif

@if ($article->author()->hasBlueskyAccount())
<a href="https://bsky.app/profile/{{ $article->author()->bluesky() }}" class="text-twitter">
<x-icon-bluesky class="w-6 h-6" />
</a>
@endif

@if ($article->author()->hasWebsite())
<a href="{{ $article->author()->website() }}">
<x-heroicon-o-globe-alt class="w-6 h-6" />
Expand Down
4 changes: 2 additions & 2 deletions resources/views/components/articles/form.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:t
</div>
</div>

@unless (Auth::user()->twitter())
@unless (Auth::user()->hasTwitterAccount() && Auth::user()->hasBlueskyAccount())
<span class="text-gray-600 text-sm mt-4 block">
Articles will be shared on X (Twitter).
<a href="{{ route('settings.profile') }}" class="text-green-darker">Add your X (Twitter) handle</a> and we'll include that too.
<a href="{{ route('settings.profile') }}" class="text-green-darker">Add your X (Twitter) and/or Bluesky handles</a> and we'll include that too.
</span>
@endunless
</div>
Expand Down
6 changes: 6 additions & 0 deletions resources/views/components/users/profile-block.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
</a>
@endif

@if ($user->hasBluesky())
<a href="https://bsky.app/{{ $user->bluesky() }}" class="text-twitter">
<x-icon-bluesky class="w-6 h-6" />
</a>
@endif

@if ($user->hasWebsite())
<a href="{{ $user->website() }}">
<x-heroicon-o-globe-alt class="w-6 h-6" />
Expand Down
5 changes: 5 additions & 0 deletions resources/views/layouts/_footer.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
(Twitter)
</a>

<a href="https://bsky.app/profile/laravel.io" class="w-1/2 text-gray-400 mb-4 hover:text-gray-200 lg:mb-6 whitespace-nowrap">
<x-icon-bluesky class="text-white w-4 h-4 inline mr-2"/>
Bluesky
</a>

<a href="https://github.com/laravelio" class="w-1/2 text-gray-400 mb-4 hover:text-gray-200 lg:mb-6 whitespace-nowrap">
<x-icon-github class="text-white w-4 h-4 inline mr-2"/>
GitHub
Expand Down
Loading

0 comments on commit 0765fdd

Please sign in to comment.