feat: integrate LinkedIn API for automated social media post publishing via service and console command

This commit is contained in:
Ümit Tunç
2026-08-07 23:43:38 +03:00
parent a51af8208d
commit 25cdfda897
11 changed files with 682 additions and 0 deletions
@@ -0,0 +1,214 @@
<?php
namespace App\Filament\Admin\Pages;
use App\Models\Setting;
use App\Services\LinkedInService;
use BackedEnum;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\Actions;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Section;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\HtmlString;
class LinkedInSettings extends Page implements HasForms
{
use InteractsWithForms;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedShare;
protected string $view = 'filament.admin.pages.linked-in-settings';
protected static ?int $navigationSort = 90;
protected static \UnitEnum|string|null $navigationGroup = 'Ayarlar';
public ?array $data = [];
public function mount(): void
{
$this->form->fill([
'autoPublishBlogs' => (bool) Setting::get('linkedin_auto_publish_blogs', '1'),
'autoPublishProducts' => (bool) Setting::get('linkedin_auto_publish_products', '1'),
'testTitle' => 'Truncgil Technology Paylaşım Testi',
'testText' => 'Truncgil Technology web sitemiz üzerinden LinkedIn entegrasyonumuz başarıyla tamamlanmıştır.',
'testUrl' => 'https://truncgil.com',
]);
}
public static function getNavigationLabel(): string
{
return 'LinkedIn Entegrasyonu';
}
public function getTitle(): string
{
return 'LinkedIn Entegrasyonu & Otomasyon';
}
public function form(Form $form): Form
{
$linkedInService = app(LinkedInService::class);
$status = $linkedInService->getTokenExpirationStatus();
$statusBadgeHtml = $status['is_valid']
? '<span class="inline-flex items-center gap-x-1.5 rounded-md bg-emerald-500/10 px-3 py-1.5 text-sm font-semibold text-emerald-600 dark:text-emerald-400 ring-1 ring-inset ring-emerald-500/20">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
Bağlı ve Aktif
</span>'
: '<span class="inline-flex items-center gap-x-1.5 rounded-md bg-rose-500/10 px-3 py-1.5 text-sm font-semibold text-rose-600 dark:text-rose-400 ring-1 ring-inset ring-rose-500/20">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
Bağlantı Yok / Süresi Dolmuş
</span>';
$statusDetailsHtml = '
<div class="mt-3 space-y-2 text-sm text-gray-600 dark:text-gray-300">
<div><strong>Açıklama:</strong> ' . e($status['message']) . '</div>
<div><strong>Client ID:</strong> <code class="rounded bg-gray-100 dark:bg-gray-800 px-2 py-0.5 text-xs font-mono">' . e(config('linkedin.client_id')) . '</code></div>
<div><strong>Organization ID:</strong> <code class="rounded bg-gray-100 dark:bg-gray-800 px-2 py-0.5 text-xs font-mono">' . e(config('linkedin.organization_id')) . '</code></div>
<div><strong>Redirect URI:</strong> <code class="rounded bg-gray-100 dark:bg-gray-800 px-2 py-0.5 text-xs font-mono">' . e(config('linkedin.redirect_uri')) . '</code></div>
</div>';
return $form->schema([
Grid::make(['default' => 1, 'md' => 2])
->schema([
Section::make('LinkedIn Sayfa Bağlantı Durumu')
->description('Truncgil Technology LinkedIn Şirket Sayfası (ID: ' . config('linkedin.organization_id') . ') Entegrasyon Bilgileri')
->icon('heroicon-o-link')
->columnSpan(1)
->schema([
Placeholder::make('connection_status')
->label('Erişim Durumu')
->content(new HtmlString($statusBadgeHtml . $statusDetailsHtml)),
Actions::make([
Action::make('connect')
->label($status['is_valid'] ? 'Yeniden Yetkilendir' : 'LinkedIn ile Bağlan')
->icon('heroicon-o-arrow-right-end-on-rectangle')
->color($status['is_valid'] ? 'gray' : 'primary')
->url(route('admin.linkedin.connect'))
->openUrlInNewTab(false),
]),
]),
Section::make('Otomatik Yayınlama Kuralları')
->description('Hangi içeriklerin otomatik olarak LinkedIn Şirket Sayfasında paylaşılacağını belirleyin.')
->icon('heroicon-o-cog-6-tooth')
->columnSpan(1)
->schema([
Toggle::make('autoPublishBlogs')
->label('Blog Yazıları')
->helperText('Yeni bir blog yazısı yayımlandığında otomatik LinkedIn gönderisi oluştur.')
->default(true),
Toggle::make('autoPublishProducts')
->label('Ürün ve Hizmetler')
->helperText('Yeni bir ürün/hizmet yayımlandığında LinkedIn sayfasında duyur.')
->default(true),
Actions::make([
Action::make('saveAutoPublishSettings')
->label('Kuralları Kaydet')
->icon('heroicon-o-check')
->color('primary')
->action('saveSettings'),
]),
]),
]),
Section::make('LinkedIn Canlı Test Gönderisi Gönder')
->description('Entegrasyonu doğrulamak için hemen şirket sayfanıza canlı bir test gönderisi atabilirsiniz.')
->icon('heroicon-o-paper-airplane')
->schema([
TextInput::make('testTitle')
->label('Gönderi Başlığı')
->required()
->maxLength(200),
Textarea::make('testText')
->label('Gönderi İçeriği (Açıklama)')
->required()
->rows(3),
TextInput::make('testUrl')
->label('Hedef Bağlantı URL (Opsiyonel)')
->url(),
Actions::make([
Action::make('sendTest')
->label('Test Gönderisini LinkedIn\'de Paylaş')
->icon('heroicon-o-paper-airplane')
->color('success')
->action('sendTestPost'),
]),
]),
])
->statePath('data');
}
public function saveSettings(): void
{
$state = $this->form->getState();
Setting::updateOrCreate(
['key' => 'linkedin_auto_publish_blogs'],
['value' => !empty($state['autoPublishBlogs']) ? '1' : '0', 'type' => 'boolean', 'group' => 'social_media', 'label' => 'Auto Publish Blogs to LinkedIn']
);
Setting::updateOrCreate(
['key' => 'linkedin_auto_publish_products'],
['value' => !empty($state['autoPublishProducts']) ? '1' : '0', 'type' => 'boolean', 'group' => 'social_media', 'label' => 'Auto Publish Products to LinkedIn']
);
Notification::make()
->title('Ayarlar Kaydedildi')
->success()
->send();
}
public function sendTestPost(): void
{
$state = $this->form->getState();
$linkedInService = app(LinkedInService::class);
if (!$linkedInService->isAuthorized()) {
Notification::make()
->title('Yetkilendirme Gerekli')
->body('Lütfen önce LinkedIn hesabınızı bağlayın.')
->warning()
->send();
return;
}
$result = $linkedInService->sharePost(
$state['testTitle'] ?? '',
$state['testText'] ?? '',
$state['testUrl'] ?? null
);
if ($result['success']) {
Notification::make()
->title('Başarılı!')
->body($result['message'])
->success()
->send();
} else {
Notification::make()
->title('Paylaşım Başarısız')
->body($result['message'])
->danger()
->send();
}
}
}