fix: tampilkan token Kesiswaan + test koneksi
- Token Database Kesiswaan ditampilkan sebagai text (bisa copy) - Tambah tombol 'Test Koneksi' yang ping endpoint /api/integration/students dan tampilkan status - Status indikator: abu=belum, hijau=terhubung, merah=gagal
This commit is contained in:
@@ -50,6 +50,41 @@ class SyncController extends Controller
|
|||||||
return view('settings.sync', compact('baseUrl', 'savedToken', 'hasToken', 'studentCount', 'ejurnalToken', 'hasEjurnalToken'));
|
return view('settings.sync', compact('baseUrl', 'savedToken', 'hasToken', 'studentCount', 'ejurnalToken', 'hasEjurnalToken'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testKesiswaanConnection(Request $request): \Illuminate\Http\JsonResponse
|
||||||
|
{
|
||||||
|
$url = $request->input('base_url', Setting::getValue('kesiswaan_base_url', ''));
|
||||||
|
$token = $request->input('token', Setting::getValue('kesiswaan_token', ''));
|
||||||
|
|
||||||
|
if (empty($url) || empty($token)) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'URL atau token belum diisi.'], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = \Illuminate\Support\Facades\Http::acceptJson()
|
||||||
|
->withToken($token)
|
||||||
|
->timeout(10)
|
||||||
|
->get(rtrim($url, '/') . '/api/integration/students?per_page=1');
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$data = $response->json();
|
||||||
|
$count = $data['meta']['total'] ?? count($data['data'] ?? []);
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Koneksi berhasil.',
|
||||||
|
'data' => [
|
||||||
|
'students' => $count,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
} elseif ($response->status() === 401) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Token tidak valid (401).'], 422);
|
||||||
|
} else {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Respon server: ' . $response->status()], 422);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Tidak dapat terhubung: ' . $e->getMessage()], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function syncNow(Request $request): RedirectResponse
|
public function syncNow(Request $request): RedirectResponse
|
||||||
{
|
{
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
|
|||||||
@@ -29,30 +29,28 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Token --}}
|
{{-- Token display --}}
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1.5">Token Sinkronisasi</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1.5">Token Sinkronisasi</label>
|
||||||
<div class="relative">
|
|
||||||
<input type="password" name="token" value="{{ old('token', $hasToken ? '********' : '') }}"
|
|
||||||
placeholder="Masukkan token akses"
|
|
||||||
class="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition pr-24"
|
|
||||||
id="tokenInput"
|
|
||||||
@if($hasToken) readonly onfocus="this.removeAttribute('readonly'); this.value=''; this.type='password';" @endif>
|
|
||||||
@if($hasToken)
|
@if($hasToken)
|
||||||
<button type="button" onclick="document.getElementById('tokenInput').removeAttribute('readonly'); document.getElementById('tokenInput').value=''; document.getElementById('tokenInput').focus();"
|
<div class="flex items-center gap-2">
|
||||||
class="absolute right-2 top-1/2 -translate-y-1/2 px-3 py-1 text-xs font-medium text-blue-600 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 transition">
|
<code class="flex-1 block bg-gray-50 border border-gray-200 rounded-lg px-3 py-2.5 text-sm font-mono text-gray-800 select-all" id="kesiswaanTokenDisplay">{{ $savedToken }}</code>
|
||||||
Ganti
|
<button type="button" onclick="copyKesiswaanToken()"
|
||||||
|
class="shrink-0 px-3 py-2 text-xs font-medium text-blue-600 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 transition">
|
||||||
|
<i class="fa-regular fa-copy"></i> Salin
|
||||||
</button>
|
</button>
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
@error('token') <p class="mt-1 text-sm text-blue-600">{{ $message }}</p> @enderror
|
<input type="hidden" name="token" value="{{ $savedToken }}">
|
||||||
@if($hasToken)
|
|
||||||
<p class="mt-1.5 text-xs text-green-600 flex items-center">
|
<p class="mt-1.5 text-xs text-green-600 flex items-center">
|
||||||
<i class="fa-solid fa-check"></i>
|
<i class="fa-solid fa-check"></i>
|
||||||
Token sudah tersimpan. Klik <strong>"Ganti"</strong> untuk memperbarui.
|
Token tersimpan. Ganti dengan mengisi form di bawah jika diperlukan.
|
||||||
</p>
|
</p>
|
||||||
@else
|
@else
|
||||||
<p class="mt-1 text-xs text-gray-500">Token didapatkan dari menu Pengaturan → Sync Tokens di Database Kesiswaan.</p>
|
<input type="password" name="token" value=""
|
||||||
|
placeholder="Masukkan token akses"
|
||||||
|
class="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition"
|
||||||
|
id="tokenInput">
|
||||||
|
<p class="mt-1 text-xs text-gray-500">Token didapatkan dari menu Pengaturan Database Kesiswaan.</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -68,6 +66,26 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
{{-- Status + Test Connection --}}
|
||||||
|
@if($hasToken && $baseUrl)
|
||||||
|
<div id="kesiswaan-status" class="p-4 bg-slate-50 border border-slate-200 rounded-xl" data-saved-url="{{ $baseUrl }}" data-saved-token="{{ $savedToken }}">
|
||||||
|
<div class="flex items-start justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span id="kesiswaan-status-dot" class="inline-block w-2.5 h-2.5 rounded-full bg-slate-300"></span>
|
||||||
|
<span id="kesiswaan-status-text" class="text-sm font-semibold text-slate-500">Belum dites</span>
|
||||||
|
</div>
|
||||||
|
<p id="kesiswaan-status-detail" class="mt-1 text-xs text-slate-400">Klik "Test Koneksi" untuk verifikasi.</p>
|
||||||
|
</div>
|
||||||
|
<button type="button" id="test-kesiswaan-btn"
|
||||||
|
class="shrink-0 inline-flex items-center gap-1.5 rounded-lg border border-blue-200 bg-blue-50 px-4 py-2 text-xs font-semibold text-blue-700 hover:bg-blue-100 transition">
|
||||||
|
<i class="fa-solid fa-plug"></i>
|
||||||
|
Test Koneksi
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
{{-- Tombol --}}
|
{{-- Tombol --}}
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="w-full px-4 py-3 text-sm font-medium text-white bg-blue-600 rounded-xl hover:bg-blue-700 transition shadow-sm flex items-center justify-center space-x-2">
|
class="w-full px-4 py-3 text-sm font-medium text-white bg-blue-600 rounded-xl hover:bg-blue-700 transition shadow-sm flex items-center justify-center space-x-2">
|
||||||
@@ -146,6 +164,73 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function copyKesiswaanToken() {
|
||||||
|
const el = document.getElementById('kesiswaanTokenDisplay');
|
||||||
|
if (!el) return;
|
||||||
|
navigator.clipboard.writeText(el.textContent).then(() => {
|
||||||
|
const btn = el.nextElementSibling;
|
||||||
|
if (btn) {
|
||||||
|
btn.innerHTML = '<i class="fa-regular fa-check"></i> Tersalin';
|
||||||
|
setTimeout(() => { btn.innerHTML = '<i class="fa-regular fa-copy"></i> Salin'; }, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const testBtn = document.getElementById('test-kesiswaan-btn');
|
||||||
|
const st = document.getElementById('kesiswaan-status');
|
||||||
|
const dot = document.getElementById('kesiswaan-status-dot');
|
||||||
|
const txt = document.getElementById('kesiswaan-status-text');
|
||||||
|
const det = document.getElementById('kesiswaan-status-detail');
|
||||||
|
|
||||||
|
if (testBtn && st && dot && txt && det) {
|
||||||
|
testBtn.addEventListener('click', async function () {
|
||||||
|
const url = (st.dataset.savedUrl || '').replace(/\/+$/, '');
|
||||||
|
const token = st.dataset.savedToken || '';
|
||||||
|
|
||||||
|
testBtn.disabled = true;
|
||||||
|
testBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Testing...';
|
||||||
|
st.className = 'p-4 bg-slate-50 border border-slate-200 rounded-xl';
|
||||||
|
dot.className = 'inline-block w-2.5 h-2.5 rounded-full bg-slate-300';
|
||||||
|
txt.className = 'text-sm font-semibold text-slate-500';
|
||||||
|
txt.textContent = 'Menguji koneksi...';
|
||||||
|
det.textContent = 'Menghubungi ' + url + '...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp = await fetch('{{ route('settings.sync.test') }}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'),
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ base_url: url, token: token }),
|
||||||
|
});
|
||||||
|
const data = await resp.json();
|
||||||
|
|
||||||
|
if (resp.ok && data.success) {
|
||||||
|
st.className = 'p-4 bg-emerald-50 border border-emerald-200 rounded-xl';
|
||||||
|
dot.className = 'inline-block w-2.5 h-2.5 rounded-full bg-emerald-500';
|
||||||
|
txt.className = 'text-sm font-semibold text-emerald-800';
|
||||||
|
txt.textContent = '✅ Terhubung';
|
||||||
|
det.innerHTML = 'Data siswa: ' + (data.data?.students || '?') + ' siswa terdeteksi';
|
||||||
|
} else {
|
||||||
|
throw new Error(data.message || 'Koneksi gagal');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
st.className = 'p-4 bg-red-50 border border-red-200 rounded-xl';
|
||||||
|
dot.className = 'inline-block w-2.5 h-2.5 rounded-full bg-red-500';
|
||||||
|
txt.className = 'text-sm font-semibold text-red-800';
|
||||||
|
txt.textContent = '❌ Tidak Terhubung';
|
||||||
|
det.textContent = err.message;
|
||||||
|
} finally {
|
||||||
|
testBtn.disabled = false;
|
||||||
|
testBtn.innerHTML = '<i class="fa-solid fa-plug"></i> Test Koneksi';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
@@ -127,6 +127,7 @@ Route::middleware('auth')->group(function () {
|
|||||||
Route::middleware('permission:sync-data')->group(function () {
|
Route::middleware('permission:sync-data')->group(function () {
|
||||||
Route::get('/settings/sync', [SyncController::class, 'index'])->name('settings.sync');
|
Route::get('/settings/sync', [SyncController::class, 'index'])->name('settings.sync');
|
||||||
Route::post('/settings/sync', [SyncController::class, 'syncNow'])->name('settings.sync.run');
|
Route::post('/settings/sync', [SyncController::class, 'syncNow'])->name('settings.sync.run');
|
||||||
|
Route::post('/settings/sync/test', [SyncController::class, 'testKesiswaanConnection'])->name('settings.sync.test');
|
||||||
Route::post('/settings/sync/ejurnal-token', [SyncController::class, 'saveEjurnalToken'])->name('settings.sync.ejurnal-token');
|
Route::post('/settings/sync/ejurnal-token', [SyncController::class, 'saveEjurnalToken'])->name('settings.sync.ejurnal-token');
|
||||||
Route::post('/settings/sync/ejurnal-token/generate', [SyncController::class, 'generateEjurnalToken'])->name('settings.sync.ejurnal-token.generate');
|
Route::post('/settings/sync/ejurnal-token/generate', [SyncController::class, 'generateEjurnalToken'])->name('settings.sync.ejurnal-token.generate');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user