matab-panel/app/Filament/Pages/SyncPage.php

173 lines
4.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Filament\Pages;
use App\Models\SyncLog;
use App\Services\OsurgImportService;
use App\Services\SyncService;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Livewire\WithFileUploads;
use Morilog\Jalali\Jalalian;
class SyncPage extends Page
{
use WithFileUploads;
protected string $view = 'filament.pages.sync-page';
protected static ?int $navigationSort = 99;
public static function canAccess(): bool
{
return auth()->user()->can('View:SyncPage');
}
public static function shouldRegisterNavigation(): bool
{
return false;
}
public static function getNavigationIcon(): \BackedEnum|string|null
{
return 'heroicon-o-arrows-right-left';
}
public static function getNavigationGroup(): ?string
{
return __('navigation.groups.system');
}
public string $report = '';
public string $importReport = '';
public bool $importing = false;
public $sqlFile = null;
public static function getNavigationLabel(): string
{
return __('navigation.sync.label');
}
public function getTitle(): string
{
return __('navigation.sync.title');
}
public function getPendingCount(): int
{
return SyncLog::changesSince(SyncLog::lastSyncId())->count();
}
public function getLastSyncTime(): string
{
$last = SyncLog::where('action', 'synced')->latest('id')->first();
if (! $last) {
return __('navigation.sync.never');
}
return Jalalian::fromCarbon($last->datetime->timezone('Asia/Tehran'))->format('Y/m/d H:i:s');
}
protected function rules(): array
{
return [
'sqlFile' => ['required', 'file', 'max:307200'],
];
}
protected function getHeaderActions(): array
{
return [
Action::make('sync')
->label(__('navigation.sync.sync_with_peer'))
->icon('heroicon-o-arrows-right-left')
->color('primary')
->requiresConfirmation()
->modalHeading(__('navigation.sync.confirm_heading'))
->modalDescription(__('navigation.sync.confirm_description'))
->modalSubmitActionLabel(__('navigation.sync.confirm_button'))
->action('runSync'),
Action::make('backup')
->label(__('navigation.backup.label'))
->icon('heroicon-o-arrow-down-tray')
->color('success')
->action('downloadBackup'),
];
}
public function runSync(): void
{
$service = SyncService::fromConfig();
if (! $service->isConfigured()) {
Notification::make()
->title(__('navigation.sync.error_title'))
->body(__('navigation.sync.error_not_configured'))
->danger()
->send();
return;
}
$result = $service->sync();
$this->report = implode("\n", $result['report']);
Notification::make()
->title($result['success'] ? __('navigation.sync.success') : __('navigation.sync.failed'))
->body(__('navigation.sync.see_report'))
->color($result['success'] ? 'success' : 'warning')
->send();
}
public function startImport(): void
{
$this->validate();
$this->importing = true;
try {
@set_time_limit(600);
$tmpPath = $this->sqlFile->getRealPath();
$service = new OsurgImportService();
$result = $service->import($tmpPath);
$this->importReport = implode("\n", $result['report']);
Notification::make()
->title($result['success']
? __('navigation.import.success')
: __('navigation.import.failed'))
->body(__('navigation.sync.see_report'))
->color($result['success'] ? 'success' : 'danger')
->send();
} finally {
$this->sqlFile = null;
$this->importing = false;
}
}
public function downloadBackup(): \Symfony\Component\HttpFoundation\StreamedResponse
{
$data = [
'exported_at' => now()->toDateTimeString(),
'last_sync_id' => SyncLog::lastSyncId(),
'changes' => SyncLog::all()->toArray(),
];
$filename = 'matab-backup-' . now()->format('Y-m-d_H-i-s') . '.json';
return response()->streamDownload(function () use ($data) {
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}, $filename, ['Content-Type' => 'application/json']);
}
}