Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 141 additions & 29 deletions app/Http/Controllers/Surat/PermohonanController.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,34 @@
use App\Models\DataDesa;
use App\Models\LogTte;
use App\Models\Surat;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\RoundBlockSizeMode;
use Endroid\QrCode\Writer\PngWriter;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Psr7;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
use setasign\Fpdi\Fpdi;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Yajra\DataTables\DataTables;

class PermohonanController extends Controller
{
public function index()
public function index(): View
{
// dd(!$this->isDatabaseGabungan(), DataDesa::pluck('desa_id'));
$page_title = 'Permohonan Surat';
$page_description = 'Daftar Permohonan Surat';

return view('surat.permohonan.index', compact('page_title', 'page_description'));
}

public function getData()
public function getData(): JsonResponse
{
$desa = request('kode_desa');

Expand Down Expand Up @@ -127,9 +135,8 @@ public function getData()
->rawColumns(['aksi', 'nama', 'log_verifikasi'])->make();
}

public function show($id)
public function show(Surat $surat): View
{
$surat = Surat::findOrFail($id);
$page_title = 'Detail Surat';
$page_description = "Detail Data Surat: {$surat->nama}";

Expand All @@ -153,27 +160,24 @@ public function show($id)
return view('surat.permohonan.show', compact('page_title', 'page_description', 'surat'));
}

public function download($id)
public function download(Surat $surat): BinaryFileResponse
{
try {
$surat = Surat::findOrFail($id);

return Storage::download('public/surat/' . $surat->file);
} catch (\Exception $e) {
Log::error('Permohonan Surat download failed', [
'error' => $e->getMessage(),
'user_id' => auth()->id(),
'surat_id' => $id,
'surat_id' => $surat->id,
]);

return back()->with('error', 'Dokumen tidak ditemukan');
}
}

public function setujui($id)
public function setujui(Surat $surat): JsonResponse
{
try {
$surat = Surat::findOrFail($id);
$log_sekarang = $surat->log_verifikasi;

if ($log_sekarang == LogVerifikasiSurat::Operator) {
Expand All @@ -193,35 +197,38 @@ public function setujui($id)
Log::error('Permohonan Surat approval failed', [
'error' => $e->getMessage(),
'user_id' => auth()->id(),
'surat_id' => $id,
'surat_id' => $surat->id,
]);
}

return response()->json();
}

public function tolak(Request $request, $id)
public function tolak(Request $request, Surat $surat): JsonResponse

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

masih belum menggunakan formRequest untuk validasi

{
try {
Surat::findOrFail($id)->update([
$request->validate(['keterangan' => 'required|string|max:500']);

$surat->update([
'log_verifikasi' => LogVerifikasiSurat::Ditolak,
'status' => StatusSurat::Ditolak,
'keterangan' => $request['keterangan'],
'keterangan' => $request->input('keterangan'),
]);
} catch (\Exception $e) {
Log::error('Permohonan Surat rejection failed', [
'error' => $e->getMessage(),
'user_id' => auth()->id(),
'surat_id' => $id,
'surat_id' => $surat->id,
]);
}

return response()->json();
}

public function passphrase(Request $request, $id)
public function passphrase(Request $request, Surat $surat): JsonResponse

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gunakan formRequest untuk validasi

{
$surat = Surat::findOrFail($id);
$request->validate(['passphrase' => 'required|string']);


DB::beginTransaction();

Expand All @@ -244,7 +251,7 @@ public function passphrase(Request $request, $id)
'multipart' => [
['name' => 'file', 'contents' => Psr7\Utils::tryFopen($file_path, 'r')],
['name' => 'nik', 'contents' => $surat->pengurus->nik],
['name' => 'passphrase', 'contents' => $request['passphrase']],
['name' => 'passphrase', 'contents' => $request->input('passphrase')],
['name' => 'tampilan', 'contents' => 'visible'],
['name' => 'linkQR', 'contents' => route('surat.arsip.qrcode', $surat->id)],
['name' => 'width', 'contents' => $width],
Expand All @@ -271,43 +278,148 @@ public function passphrase(Request $request, $id)
'status' => true,
'pesan_error' => 'success',
'jenis' => 'success',
]);
], $surat->id);
} catch (ClientException $e) {
Log::error('Permohonan Surat TTE signing failed', [
'error' => $e->getMessage(),
'user_id' => auth()->id(),
'surat_id' => $id,
'surat_id' => $surat->id,
]);

DB::rollback();

return $this->response([
'status' => false,
'pesan_error' => $e->getMessage(),
'pesan_error' => 'Terjadi kesalahan saat menandatangani surat.',
'jenis' => 'ClientException',
], $surat->id);
}
}

public function tandatanganQr(Surat $surat): JsonResponse

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tambahkan testing untuk method baru, lengkapi pada tests/Feature/PermohonanControllerTest.php

{
if ($surat->log_verifikasi != LogVerifikasiSurat::ProsesTTE) {
return response()->json(['status' => false, 'pesan_error' => 'Surat tidak dalam tahap penandatanganan.'], 400);
}

$user = auth()->user()->pengurus_id;
if ($user != $this->akun_camat->id) {
return response()->json(['status' => false, 'pesan_error' => 'Hanya camat yang dapat menandatangani surat.'], 403);
}

DB::beginTransaction();

try {
$file_path = public_path('storage/surat/' . basename($surat->file));
$file_info = pathinfo($file_path);
$signed_path = public_path('storage/surat/' . $file_info['filename'] . '_signed.pdf');

$verificationUrl = route('surat.arsip.qrcode', $surat->id);

$qrCode = Builder::create()
->writer(new PngWriter())
->data($verificationUrl)
->encoding(new Encoding('UTF-8'))
->errorCorrectionLevel(ErrorCorrectionLevel::High)
->size(200)
->margin(10)
->roundBlockSizeMode(RoundBlockSizeMode::Margin)
->build();

$qrTempPath = public_path('storage/surat/qr_temp_' . uniqid() . '_' . $surat->id . '.png');
$qrCode->saveToFile($qrTempPath);

$pdf = new Fpdi();
$pageCount = $pdf->setSourceFile($file_path);

for ($i = 1; $i <= $pageCount; $i++) {
$templateId = $pdf->importPage($i);
$size = $pdf->getTemplateSize($templateId);
$pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
$pdf->useTemplate($templateId);

if ($i === $pageCount) {
$qrSize = 40;
$margin = 10;
$pdf->Image($qrTempPath, $size['width'] - $qrSize - $margin, $size['height'] - $qrSize - $margin, $qrSize, $qrSize);
}
}

$pdf->Output('F', $signed_path);

if (file_exists($qrTempPath)) {
unlink($qrTempPath);
}

$fileHash = hash_file('sha256', $signed_path);

$surat->update([
'status' => StatusSurat::Arsip,
'log_verifikasi' => LogVerifikasiSurat::SudahTTE,
'file_hash' => $fileHash,
]);

DB::commit();

if (!rename($signed_path, $file_path)) {
throw new \RuntimeException('Gagal memindahkan file signed ke lokasi asal.');
}

LogTte::create([
'pesan_error' => 'success',
'jenis' => 'QRCode',
'surat_id' => $surat->id,
]);

return response()->json([
'status' => true,
'pesan_error' => 'success',
'jenis' => 'success',
]);
} catch (\Exception $e) {
DB::rollback();

if (isset($signed_path) && file_exists($signed_path)) {
unlink($signed_path);
}
if (isset($qrTempPath) && file_exists($qrTempPath)) {
unlink($qrTempPath);
}

Log::error('QR Code signing failed', [
'error' => $e->getMessage(),
'user_id' => auth()->id(),
'surat_id' => $surat->id,
]);

return response()->json([
'status' => false,
'pesan_error' => 'Terjadi kesalahan saat menandatangani surat.',
'jenis' => 'Exception',
]);
}
}

protected function response($notif = [])
protected function response(array $notif = [], $suratId = null): JsonResponse
{
LogTte::create([
'pesan_error' => $notif['pesan_error'],
'jenis' => $notif['jenis'],
]);
LogTte::create(array_filter([
'pesan_error' => $notif['pesan_error'] ?? '',
'jenis' => $notif['jenis'] ?? '',
'surat_id' => $suratId,
]));

return response()->json($notif);
}

public function ditolak()
public function ditolak(): View
{
$page_title = 'Permohonan Surat Ditolak';
$page_description = 'Daftar Permohonan Surat Ditolak';

return view('surat.permohonan.ditolak', compact('page_title', 'page_description'));
}

public function getDataDitolak()
public function getDataDitolak(): JsonResponse
{
$desa = request('kode_desa');
$surat = Surat::ditolak()
Expand Down
Loading
Loading