127 lines
4.3 KiB
PHP
127 lines
4.3 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Web\Admin;
|
||
|
||
use App\Http\Controllers\Controller;
|
||
use App\Models\ReplicationLog;
|
||
use App\Models\ReplicationSchedule;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Http;
|
||
use Illuminate\Support\Facades\Log;
|
||
use Inertia\Inertia;
|
||
|
||
class ReplicationController extends Controller
|
||
{
|
||
public function index()
|
||
{
|
||
abort_unless(auth()->user()->isAdmin(), 403);
|
||
|
||
$logs = ReplicationLog::query()
|
||
->latest('id')
|
||
->limit(50)
|
||
->get()
|
||
->map(fn (ReplicationLog $l) => [
|
||
'id' => $l->id,
|
||
'status' => $l->status,
|
||
'schedule_id' => $l->schedule_id,
|
||
'tables_success' => $l->tables_success,
|
||
'tables_failed' => $l->tables_failed,
|
||
'errors' => $l->errors,
|
||
'received_at' => optional($l->received_at)->toIso8601String(),
|
||
]);
|
||
|
||
$schedules = ReplicationSchedule::orderBy('name')->get()->map(fn (ReplicationSchedule $s) => [
|
||
'id' => $s->id,
|
||
'schedule_id' => $s->schedule_id,
|
||
'name' => $s->name,
|
||
'is_active' => $s->is_active,
|
||
]);
|
||
|
||
return Inertia::render('Admin/Replication/Index', [
|
||
'logs' => $logs,
|
||
'schedules' => $schedules,
|
||
'configured' => (bool) config('services.syncio.base_url'),
|
||
]);
|
||
}
|
||
|
||
public function storeSchedule(Request $request)
|
||
{
|
||
abort_unless(auth()->user()->isAdmin(), 403);
|
||
|
||
$data = $request->validate([
|
||
'schedule_id' => ['required', 'string', 'max:255', 'unique:replication_schedules,schedule_id'],
|
||
'name' => ['nullable', 'string', 'max:255'],
|
||
]);
|
||
|
||
ReplicationSchedule::create([
|
||
'schedule_id' => $data['schedule_id'],
|
||
'name' => $data['name'] ?? null,
|
||
'is_active' => true,
|
||
]);
|
||
|
||
return back()->with('success', 'Расписание добавлено.');
|
||
}
|
||
|
||
public function updateSchedule(Request $request, ReplicationSchedule $schedule)
|
||
{
|
||
abort_unless(auth()->user()->isAdmin(), 403);
|
||
|
||
$data = $request->validate([
|
||
'name' => ['nullable', 'string', 'max:255'],
|
||
'is_active' => ['required', 'boolean'],
|
||
]);
|
||
|
||
$schedule->update($data);
|
||
|
||
return back()->with('success', 'Расписание обновлено.');
|
||
}
|
||
|
||
public function destroySchedule(ReplicationSchedule $schedule)
|
||
{
|
||
abort_unless(auth()->user()->isAdmin(), 403);
|
||
|
||
$schedule->delete();
|
||
|
||
return back()->with('success', 'Расписание удалено.');
|
||
}
|
||
|
||
public function run(Request $request)
|
||
{
|
||
abort_unless(auth()->user()->isAdmin(), 403);
|
||
|
||
$data = $request->validate([
|
||
'schedule_id' => ['required', 'string', 'max:255'],
|
||
]);
|
||
|
||
$baseUrl = rtrim((string) config('services.syncio.base_url'), '/');
|
||
if ($baseUrl === '') {
|
||
return back()->with('error', 'Не задан SYNCIO_BASE_URL — запуск репликации недоступен.');
|
||
}
|
||
|
||
$scheduleId = $data['schedule_id'];
|
||
$url = "{$baseUrl}/migrations/schedules/{$scheduleId}/run";
|
||
|
||
try {
|
||
$response = Http::acceptJson()
|
||
->when(
|
||
config('services.syncio.token'),
|
||
fn ($http) => $http->withToken(config('services.syncio.token'))
|
||
)
|
||
->timeout(30)
|
||
->post($url);
|
||
|
||
if ($response->failed()) {
|
||
Log::warning('Syncio run failed', ['status' => $response->status(), 'body' => $response->body()]);
|
||
|
||
return back()->with('error', "Репликатор вернул ошибку ({$response->status()}).");
|
||
}
|
||
|
||
return back()->with('success', 'Репликация запущена. Результат придёт по вебхуку.');
|
||
} catch (\Throwable $e) {
|
||
Log::error('Syncio run exception', ['message' => $e->getMessage()]);
|
||
|
||
return back()->with('error', 'Не удалось связаться с репликатором: '.$e->getMessage());
|
||
}
|
||
}
|
||
}
|