project_directory/app/Http/Controllers/DashboardController.php

1055 lines
44 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\AksesFile;
use App\Models\AksesFileDetail;
use App\Models\FileDirectory;
use App\Models\LogActivity;
use App\Models\MasterKategori;
use App\Models\MasterKlasifikasi;
use App\Models\SubUnitKerja;
use App\Models\UnitKerja;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use setasign\Fpdi\Fpdi;
use ZipArchive;
use function PHPUnit\Framework\isEmpty;
class DashboardController extends Controller
{
public function index(){
$katDok = MasterKategori::where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
$klasifikasiDok = MasterKlasifikasi::where('statusenabled', true)->select('master_klasifikasi_directory_id', 'nama_klasifikasi_directory')->get();
$prefillFilter = session()->pull('dashboard_prefill');
$authMapping = auth()->user()?->dataUser?->mappingUnitKerjaPegawai[0];
$authUnitKerja = $authMapping->objectunitkerjapegawaifk;
$authSubUnitKerja = $authMapping->objectsubunitkerjapegawaifk;
$allAkses = AksesFile::where(['statusenabled' => true, 'pegawai_id' => auth()->user()?->dataUser->id])->first();
$payload = [
'title' => 'Dashboard',
'katDok' => $katDok,
'klasifikasiDok' => $klasifikasiDok,
'authUnitKerja' => $authUnitKerja,
'authSubUnitKerja' => $authSubUnitKerja,
'allAkses' => $allAkses ?? null,
'prefillFilter' => $prefillFilter
];
return view('dashboard.index', $payload);
}
public function setDashboardPrefill(Request $request)
{
$payload = [
'unitId' => (string) $request->input('unitId', ''),
'subId' => (string) $request->input('subId', ''),
'kategoriId' => (string) $request->input('kategoriId', ''),
'unitName' => (string) $request->input('unitName', ''),
'subName' => (string) $request->input('subName', ''),
'kategoriName' => (string) $request->input('kategoriName', ''),
];
session(['dashboard_prefill' => $payload]);
return response()->json([
'status' => true,
'message' => 'Prefill disimpan'
]);
}
public function dataUnitKerja(){
$user = auth()->user()?->dataUser;
$entryPegawaiId = auth()->user()?->objectpegawaifk;
$authMapping = $user?->mappingUnitKerjaPegawai[0] ?? null;
$authUnit = $authMapping?->objectunitkerjapegawaifk;
$authSub = $authMapping?->objectsubunitkerjapegawaifk;
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
$aksesAll = $akses?->akses ?? $akses?->all_akses ?? false;
$detailUnitIds = collect();
if ($akses?->akses_file_id) {
$detailUnitIds = AksesFileDetail::where('akses_file_id', $akses->akses_file_id)
->where('statusenabled', true)
->pluck('id_unit_kerja')
->unique()
->values();
}
$allowedUnitIds = null;
if (!$aksesAll) {
if ($detailUnitIds->isNotEmpty()) {
$allowedUnitIds = $detailUnitIds;
} elseif (!empty($akses?->unit_akses)) {
$allowedUnitIds = collect([$akses->unit_akses]);
}
}
$limitPrivateToSubUnit = false;
if (!$aksesAll && !$allowedUnitIds && $authUnit) {
$allowedUnitIds = collect([$authUnit]);
$limitPrivateToSubUnit = true;
}
$kategori = request('kategori');
$filterUnit = request('unitKerja');
$subUnit = request('subUnit');
$keyword = request('keyword');
$hasKeyword = !empty($keyword);
$subArray = $subUnit ? explode(',', $subUnit) : [];
$katArray = $kategori ? explode(',', $kategori) : [];
$katDok = MasterKategori::when($katArray, fn($q) => $q->whereIn('master_kategori_directory_id', $katArray))->where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
$applyFileFilters = function ($q) use ($keyword, $katArray, $subArray, $entryPegawaiId) {
$q->where(function($subQuery) use ($entryPegawaiId){
$subQuery->where('status_action', '!=', 'rejected')->whereNotNull('status_action');
})
->when($subArray, fn($sq) => $sq->whereIn('id_sub_unit_kerja', $subArray))
->when($katArray, fn($sq) => $sq->whereIn('master_kategori_directory_id', $katArray))
->when($keyword, fn($sq) =>
$sq->where(function ($query) use ($keyword) {
$query->where('file', 'ilike', "%{$keyword}%");
})
);
};
$applyAccessFilter = function ($q) use ($aksesAll, $allowedUnitIds, $limitPrivateToSubUnit, $authSub) {
if ($aksesAll) {
return;
}
$hasPrivateScope = ($allowedUnitIds && $allowedUnitIds->isNotEmpty())
|| ($limitPrivateToSubUnit && $authSub);
$q->where(function ($query) use ($allowedUnitIds, $limitPrivateToSubUnit, $authSub, $hasPrivateScope) {
$query->where('permission_file', true);
if ($hasPrivateScope) {
$query->orWhere(function ($sub) use ($allowedUnitIds, $limitPrivateToSubUnit, $authSub) {
$sub->where('permission_file', false);
if ($allowedUnitIds && $allowedUnitIds->isNotEmpty()) {
$sub->whereIn('id_unit_kerja', $allowedUnitIds);
}
if ($limitPrivateToSubUnit && $authSub) {
$sub->where('id_sub_unit_kerja', $authSub);
}
});
}
});
};
$applyFileQuery = function ($q) use ($applyFileFilters, $applyAccessFilter) {
$applyFileFilters($q);
$applyAccessFilter($q);
};
if ($katArray && $filterUnit && $subArray) {
/* mode pencarian lengkap */
$unitKerja = UnitKerja::where('statusenabled', true)
->where('id', $filterUnit)
->with(['subUnitKerja' => fn($q) => $q->whereIn('id', $subArray)
->whereHas('fileDirectory', fn($f) => $applyFileQuery($f))
->with(['fileDirectory' => fn($f) => $applyFileQuery($f)])
])
->select('id', 'name')
->get();
} elseif ($aksesAll) {
/* all akses */
$unitKerja = UnitKerja::where('statusenabled', true)
->when($hasKeyword, fn($q) => $q->whereHas('subUnitKerja.fileDirectory', fn($f) => $applyFileQuery($f)))
->with([ // muat relasi
'subUnitKerja' => fn($q) => $q
->when($hasKeyword, fn($sq) => $sq->whereHas('fileDirectory', fn($f) => $applyFileQuery($f)))
->with([ // sub-unit
'fileDirectory' => fn($f) => $applyFileQuery($f)
])
])
->select('id', 'name')
->get();
} elseif ($allowedUnitIds) {
$unitKerja = UnitKerja::where('statusenabled', true)
->when($hasKeyword, fn($q) => $q->whereHas('subUnitKerja.fileDirectory', fn($f) => $applyFileQuery($f)))
->where(function ($q) use ($allowedUnitIds, $applyFileQuery) {
if ($allowedUnitIds && $allowedUnitIds->isNotEmpty()) {
$q->whereIn('id', $allowedUnitIds);
}
$q->orWhereHas('subUnitKerja.fileDirectory', fn($f) => $applyFileQuery($f));
})
->with([
'subUnitKerja' => fn($q) => $q->whereHas('fileDirectory', fn($f) => $applyFileQuery($f))
->with(['fileDirectory' => fn($f) => $applyFileQuery($f)])
])
->select('id', 'name')
->get();
} else {
$unitKerja = UnitKerja::where('statusenabled', true)
->when($hasKeyword, fn($q) => $q->whereHas('subUnitKerja.fileDirectory', fn($f) => $applyFileQuery($f)))
->where(function ($q) use ($authUnit, $applyFileQuery) {
if ($authUnit) {
$q->where('id', $authUnit);
}
$q->orWhereHas('subUnitKerja.fileDirectory', fn($f) => $applyFileQuery($f));
})
->with([ // 1. sub-unit milik user
'subUnitKerja' => fn($q) => $q->where(function ($sq) use ($authSub, $applyFileQuery, $hasKeyword) {
if ($authSub && !$hasKeyword) {
$sq->where('id', $authSub);
}
$sq->orWhereHas('fileDirectory', fn($f) => $applyFileQuery($f));
})
->with([ // 2. file-directory + filter keyword
'fileDirectory' => fn($f) => $applyFileQuery($f)
])
])
->select('id', 'name')
->get();
}
$data = [
'unitKerja' => $unitKerja ?? null,
'katDok' => $katDok ?? null
];
return response()->json([
'status' => true,
'data' => $data,
], 200);
}
public function store(){
DB::connection('dbDirectory')->beginTransaction();
try {
$datas = request()->input('data');
$result = [];
foreach($datas as $index => $value){
$files = request()->file("data.fileUpload$index");
if(!empty($files)){
foreach ($files['file'] as $file) {
list($id_unit_kerja, $nama_unit_kerja) = explode('/', $value['id_unit_kerja'],2);
list($id_sub_unit_kerja, $nama_sub_unit_kerja) = explode('/', $value['id_sub_unit_kerja'],2);
list($master_kategori_directory_id, $nama_kategori) = explode('/', $value['master_kategori_directory_id'],2);
list($klasifikasi, $nama_klasifikasi) = explode('/', $value['klasifikasi'],2);
$payload = [
'master_klasifikasi_directory_id' => $klasifikasi,
'id_unit_kerja' => $id_unit_kerja,
'id_sub_unit_kerja' => $id_sub_unit_kerja,
'master_kategori_directory_id' => $master_kategori_directory_id,
'pegawai_id_entry' => auth()->user()->dataUser->id ?? 1,
'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap ?? 'tes',
];
if($file){
$imageName = $file->getClientOriginalName();
$path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}/{$nama_klasifikasi}";
$file->storeAs($path, $imageName, 'file_directory');
$payload['file'] =$path .'/' .$imageName;
}
$fd = FileDirectory::create($payload);
$payloadLog = [
'file_directory_id' => $fd->file_directory_id,
'pegawai_id_entry' => $fd->pegawai_id_entry,
'pegawai_nama_entry' => $fd->pegawai_nama_entry,
'entry_at' => Carbon::now(),
'action_type' => 'Upload Dokumen',
'statusenabled' => true,
'mod_change' => $fd->entry_at,
'id_unit_kerja' => $fd->id_unit_kerja,
'id_sub_unit_kerja' => $fd->id_sub_unit_kerja,
'file' => $fd->file,
'tanggal_terbit' => $fd->tanggal_terbit ?? null,
'no_dokumen' => $fd->no_dokumen ?? null,
'permission_file' => $fd->permission_file ?? null,
];
LogActivity::create($payloadLog);
}
}
}
DB::connection('dbDirectory')->commit();
return response()->json([
'status' => true,
'message' => 'Data berhasil disimpan',
'data' => count($result) == 1 ? $result[0] : $result
], 200);
} catch (\Throwable $th) {
DB::connection('dbDirectory')->rollBack();
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
public function OptionUnitKerja(){
$q = request()->get('q');
$query = UnitKerja::where('statusenabled', true);
$data = $query->when($q, function ($query, $q){
$query->where('name', 'ILIKE', '%' .$q . '%');
})
->select('id', 'name')->get();
return response()->json([
'status' => true,
'data' => $data
], 200);
}
public function deleteFile(string $id){
DB::connection('dbDirectory')->beginTransaction();
try {
$data = FileDirectory::where('file_directory_id', $id)->first();
if(!$data){
return response()->json([
'success' => false,
'message' => 'File tidak ditemukan'
]);
}
$oldPath= public_path('file/' . $data->file);
$fileInfo = pathinfo($data->file);
$newFileName = $fileInfo['filename'] . '_deleted.' . $fileInfo['extension'];
$newPath = public_path('file/' . $fileInfo['dirname'] . '/' . $newFileName);
if (file_exists($oldPath)) {
// pastikan folder tujuan ada
if (!is_dir(dirname($newPath))) {
mkdir(dirname($newPath), 0777, true);
}
rename($oldPath, $newPath);
}
$data->update(['statusenabled' => false, 'file' => $fileInfo['dirname'].'/'. $newFileName]);
$payloadLog = [
'file_directory_id' => $data->file_directory_id,
'pegawai_id_entry' => $data->pegawai_id_entry,
'pegawai_nama_entry' => $data->pegawai_nama_entry,
'entry_at' => $data->entry_at,
'action_type' => 'Hapus Dokumen',
'statusenabled' => true,
'mod_change' => $data->entry_at,
'id_unit_kerja' => $data->id_unit_kerja,
'id_sub_unit_kerja' => $data->id_sub_unit_kerja,
'file' => $data->file,
'tanggal_terbit' => $data->tanggal_terbit,
'no_dokumen' => $data->no_dokumen,
'permission_file' => $data->permission_file,
];
LogActivity::create($payloadLog);
DB::connection('dbDirectory')->commit();
return response()->json([
'success' => true,
'message' => 'Berhasil menghapus data'
]);
} catch (\Throwable $th) {
DB::connection('dbDirectory')->rollBack();
return response()->json([
'success' => false,
'message' => 'Gagal menghapus data'
]);
//throw $th;
}
}
public function optionSubUnitKerja(string $id){
$data = SubUnitKerja::where('statusenabled', true)->where('objectunitkerjapegawaifk', $id)->get();
return response()->json([
'status' => true,
'data' => $data,
]);
}
public function getFile($id_unit_kerja, $id_sub_unit_kerja, $master_kategori_directory_id){
$klasifikasi = request('klasifikasi');
$klaArray = explode(',', $klasifikasi);
$data = FileDirectory::where(['statusenabled' => true, 'id_unit_kerja' => $id_unit_kerja, 'id_sub_unit_kerja' => $id_sub_unit_kerja, 'master_kategori_directory_id' => $master_kategori_directory_id])->whereIn('master_klasifikasi_directory_id', $klaArray)->get();
return response()->json([
'data' => $data,
'status' => true,
]);
}
public function downloadDataMultiple(){
try {
$rows = request('ids', []); // [[unit_id=>u, sub_unit_id=>s], ...]
if (empty($rows)) {
return response()->json(['message' => 'Tidak ada data'], 422);
}
$paths = [];
foreach ($rows as $r) {
if(!empty($r['sub_unit_id'])){
$files = FileDirectory::where('id_sub_unit_kerja', $r['sub_unit_id'])->where('statusenabled', true)->where('status_action', 'approved')->pluck('file');
$paths = array_merge($paths, $files->toArray());
}
}
$paths = array_unique($paths);
if (empty($paths)) {
return response()->json(['message' => 'File tidak ditemukan'], 404);
}
$zipName = 'files_' . time() . '.zip';
$zipPath = public_path('zip/' . $zipName);
$zip = new ZipArchive;
$tempFiles = [];
if($zip->open($zipPath, ZipArchive::CREATE) === TRUE){
foreach ($paths as $path) {
$fullPath = public_path('file/' . $path);
if(!file_exists($fullPath)){
throw new \Exception("File tidak ditemukan: " . $path);
}
$relativePathInZip = $path;
$fileToAdd = $this->prepareFileWithWatermark($fullPath, $tempFiles);
$zip->addFile($fileToAdd, $relativePathInZip);
}
$zip->close();
}
$this->cleanupTempFiles($tempFiles);
return response()->download(public_path('zip/' . $zipName))->deleteFileAfterSend(true);
//code...
} catch (\Throwable $th) {
return response()->json([
'message' => 'Terjadi kesalahan',
'error' => $th->getMessage()
], 500);
}
}
public function downloadDataFolder(){
try {
$id = request('id');
$type = request('type');
if($type === "unit"){
$data = FileDirectory::where('id_unit_kerja', $id)->where('statusenabled', true)->where('status_action', 'approved')->pluck('file');
}else{
$data = FileDirectory::where('id_sub_unit_kerja', $id)->where('statusenabled', true)->where('status_action', 'approved')->pluck('file');
}
if (empty($data)) {
return response()->json(['message' => 'File tidak ditemukan'], 404);
}
$zipName = 'files_' . time() . '.zip';
$zipPath = public_path('zip/' . $zipName);
$zip = new ZipArchive;
$tempFiles = [];
if($zip->open($zipPath, ZipArchive::CREATE) === TRUE){
foreach ($data as $path) {
$fullPath = public_path('file/' . $path);
if(!file_exists($fullPath)){
throw new \Exception("File tidak ditemukan: " . $path);
}
$relativePathInZip = $path;
$fileToAdd = $this->prepareFileWithWatermark($fullPath, $tempFiles);
$zip->addFile($fileToAdd, $relativePathInZip);
}
$zip->close();
}
$this->cleanupTempFiles($tempFiles);
return response()->download(public_path('zip/' . $zipName))->deleteFileAfterSend(true);
} catch (\Throwable $th) {
return response()->json([
'message' => 'Terjadi kesalahan',
'error' => $th->getMessage()
], 500);
}
}
public function dashboardVersion2(){
$katDok = MasterKategori::where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
$authMapping = auth()->user()?->dataUser?->mappingUnitKerjaPegawai[0];
$authUnitKerja = $authMapping->objectunitkerjapegawaifk;
$authSubUnitKerja = $authMapping->objectsubunitkerjapegawaifk;
$data = [
'title' => 'Dashboard',
'katDok' => $katDok,
'authUnitKerja' => $authUnitKerja,
'authSubUnitKerja' => $authSubUnitKerja,
];
return view('dashboardV2.index', $data);
}
public function dataDocumentLast(){
$perPage = (int) request('per_page', 10);
$authUnitId = auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->objectunitkerjapegawaifk;
$user = auth()->user()?->dataUser;
$entryPegawaiId = auth()->user()?->objectpegawaifk;
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
$keyword = request('keyword');
$query = FileDirectory::where('statusenabled', true)
->where(function($subQuery){
$subQuery->where('status_action', '!=', 'rejected')->whereNotNull('status_action');
})->when($keyword, function ($q) use ($keyword) {
$q->where(function ($sub) use ($keyword) {
$sub->where('file', 'ILIKE', "%{$keyword}%")
->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%");
});
});
if($akses){
if(!$akses->all_akses){
$aksesFile = AksesFileDetail::where('akses_file_id', $akses->akses_file_id)->pluck('id_unit_kerja');
$query->where(function ($query) use ($authUnitId, $aksesFile) {
$query->where('permission_file', true)
->orWhere(function ($sub) use ($authUnitId, $aksesFile) {
$sub->where('permission_file', false)
->whereIn('id_unit_kerja', $aksesFile);
});
});
}else{
$query;
}
}else{
$query->where(function ($query) use ($authUnitId) {
$query->where('permission_file', true)
->orWhere(function ($sub) use ($authUnitId) {
$sub->where('permission_file', false)
->where('id_unit_kerja', $authUnitId);
});
});
}
$data = $query->orderBy('entry_at', 'desc')
->paginate($perPage);
$payload = [
'status' => true,
'message' => 'Berhasil mendapatkan data',
'data' => $data->items(),
'pagination' => [
'current_page' => $data->currentPage(),
'next_page' => $data->hasMorePages() ? $data->currentPage() + 1 : null,
'has_more' => $data->hasMorePages(),
'last_page' => $data->lastPage(),
'per_page' => $data->perPage(),
'total' => $data->total(),
]
];
return response()->json($payload);
}
public function storeVersion2(){
DB::connection('dbDirectory')->beginTransaction();
try {
$datas = request('data');
foreach ($datas as $index => $data) {
list($id_unit_kerja, $nama_unit_kerja) = explode('/', $data['id_unit_kerja'],2);
list($id_sub_unit_kerja, $nama_sub_unit_kerja) = explode('/', $data['id_sub_unit_kerja'],2);
list($master_kategori_directory_id, $nama_kategori) = explode('/', $data['master_kategori_directory_id'],2);
$uploadedFile = request()->file("data.$index.file");
if(!$uploadedFile){
throw new \RuntimeException('File wajib diunggah pada baris ke-' . ($index+1));
}
$unitPegawaiIds = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
$status = in_array($id_unit_kerja, $unitPegawaiIds)
? 'approved'
: null;
$payload = [
'id_unit_kerja' => $id_unit_kerja,
'id_sub_unit_kerja' => $id_sub_unit_kerja,
'master_kategori_directory_id' => $master_kategori_directory_id,
'pegawai_id_entry' => auth()->user()->dataUser->id ?? 1,
'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap ?? null,
'tanggal_terbit' => $data['date_active'] ?? null,
'no_dokumen' => $data['no_dokumen'] ?? null,
'permission_file' => ($data['is_permission'] ?? null) == "1",
'status_action' => $status,
'action_by' => $status === "approved" ? auth()->user()->objectpegawaifk : null,
'action_at' => $status === "approved" ? now() : null
];
$imageName = $uploadedFile->getClientOriginalName();
$path = "{$nama_unit_kerja}/{$nama_sub_unit_kerja}/{$nama_kategori}";
$uploadedFile->storeAs($path, $imageName, 'file_directory');
$payload['file'] =$path .'/' .$imageName;
$fd = FileDirectory::create($payload);
$payloadLog = [
'file_directory_id' => $fd->file_directory_id,
'pegawai_id_entry' => $fd->pegawai_id_entry,
'pegawai_nama_entry' => $fd->pegawai_nama_entry,
'entry_at' => now(),
'action_type' => 'Upload Dokumen',
'statusenabled' => true,
'mod_change' => $fd->entry_at,
'id_unit_kerja' => $fd->id_unit_kerja,
'id_sub_unit_kerja' => $fd->id_sub_unit_kerja,
'file' => $fd->file,
'tanggal_terbit' => $fd->tanggal_terbit,
'no_dokumen' => $fd->no_dokumen,
'permission_file' => $fd->permission_file,
];
LogActivity::create($payloadLog);
}
DB::connection('dbDirectory')->commit();
return response()->json([
'status' => true,
'message' => 'Data berhasil disimpan'
], 200);
} catch (\Throwable $th) {
DB::connection('dbDirectory')->rollback();
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
public function dataPdf($fileDirectoryId)
{
$data = FileDirectory::where('file_directory_id', $fileDirectoryId)->first();
$filePath = public_path('file/' . $data->file);
if (!file_exists($filePath)) {
abort(404, 'PDF Tidak ditemukan');
}
$stampFile = public_path('assets/copy.png');
if (!file_exists($stampFile)) {
// kalau watermark tidak ada, tampilkan file asli
return response()->file($filePath, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="preview.pdf"',
'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
]);
}
$tempConverted = storage_path('app/temp/' . uniqid('conv_') . '.pdf');
try {
// coba watermark langsung
return $this->watermarkCenterAndStream($filePath, $stampFile);
} catch (\Throwable $e) {
// kalau gagal (PDF modern) -> convert dulu
// dd($e);
$this->convertWithGhostscript($filePath, $tempConverted);
$resp = $this->watermarkCenterAndStream($tempConverted, $stampFile);
@unlink($tempConverted);
return $resp;
}
}
private function watermarkCenterAndStream(string $pdfPath, string $stampFile)
{
$pdf = new Fpdi();
$pageCount = $pdf->setSourceFile($pdfPath);
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
$tplId = $pdf->importPage($pageNo);
$size = $pdf->getTemplateSize($tplId);
$pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
$pdf->useTemplate($tplId);
// watermark tengah (skala adaptif)
$stampW = $size['width'] * 0.60;
$stampH = $stampW * 0.75; // sesuaikan rasio gambar kalau perlu
$x = ($size['width'] - $stampW) / 2;
$y = ($size['height'] - $stampH) / 2;
$pdf->Image($stampFile, $x, $y, $stampW, $stampH);
}
$output = $pdf->Output('S');
return response($output, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="preview.pdf"',
'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0',
]);
}
/**
* Generate watermarked PDF to temp file (or return original) for zipping.
*/
private function prepareFileWithWatermark(string $fullPath, array &$tempFiles = [])
{
$stampFile = public_path('assets/copy.png');
$ext = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION));
if ($ext !== 'pdf' || !file_exists($stampFile)) {
return $fullPath;
}
$tempDir = storage_path('app/temp');
if (!is_dir($tempDir)) {
@mkdir($tempDir, 0777, true);
}
$tempOut = $tempDir . '/' . uniqid('wm_') . '.pdf';
try {
$this->watermarkCenterToFile($fullPath, $stampFile, $tempOut);
} catch (\Throwable $e) {
// fallback convert then watermark
$converted = $tempDir . '/' . uniqid('conv_') . '.pdf';
$this->convertWithGhostscript($fullPath, $converted);
$this->watermarkCenterToFile($converted, $stampFile, $tempOut);
$tempFiles[] = $converted;
}
$tempFiles[] = $tempOut;
return $tempOut;
}
private function watermarkCenterToFile(string $pdfPath, string $stampFile, string $outputPath): void
{
$pdf = new Fpdi();
$pageCount = $pdf->setSourceFile($pdfPath);
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
$tplId = $pdf->importPage($pageNo);
$size = $pdf->getTemplateSize($tplId);
$pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
$pdf->useTemplate($tplId);
$stampW = $size['width'] * 0.60;
$stampH = $stampW * 0.75;
$x = ($size['width'] - $stampW) / 2;
$y = ($size['height'] - $stampH) / 2;
$pdf->Image($stampFile, $x, $y, $stampW, $stampH);
}
$pdf->Output($outputPath, 'F');
}
private function cleanupTempFiles(array $tempFiles): void
{
foreach ($tempFiles as $file) {
if (is_string($file) && file_exists($file)) {
@unlink($file);
}
}
}
private function convertWithGhostscript(string $inputPdf, string $outputPdf): void
{
$gs = config('services.ghostscript.path');
if (!$gs || !file_exists($gs)) {
throw new \RuntimeException('Ghostscript tidak ditemukan. Cek GHOSTSCRIPT_PATH di .env');
}
$cmd = "\"{$gs}\" -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/prepress "
. "-dNOPAUSE -dBATCH -dQUIET -sOutputFile=\"{$outputPdf}\" \"{$inputPdf}\"";
exec($cmd, $out, $code);
if ($code !== 0 || !file_exists($outputPdf)) {
throw new \RuntimeException('Convert Ghostscript gagal (code=' . $code . ')');
}
}
public function recapData(){
try {
$perPage = (int) request('per_page', 10);
$page = max(1, (int) request('page', 1));
$keyword = strtolower(request('keyword', ''));
$authUnit = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
$rows = FileDirectory::where('statusenabled', true)->whereNotNull('status_action')->whereIn('id_unit_kerja', $authUnit)->pluck('file');
$grouped = [];
foreach ($rows as $path) {
$parts = array_values(array_filter(explode('/', $path)));
if(count($parts) < 4){
continue;
}
$unit = $parts[0];
$folder = $parts[1]. '/' . $parts[2];
if($keyword){
$hit = str_contains(strtolower($unit), $keyword) || str_contains(strtolower($folder), $keyword);
if(!$hit) continue;
}
if(!isset($grouped[$unit])){
$grouped[$unit] = [];
}
if (!isset($grouped[$unit][$folder])) {
$grouped[$unit][$folder] = 0;
}
$grouped[$unit][$folder]++;
}
$result = [];
foreach ($grouped as $unitName => $folders) {
$data = [];
foreach ($folders as $folder => $count) {
$sliceText = array_values(array_filter(explode('/', $folder)));
$data[] = [
'subUnit' => $sliceText[0],
'folder'=> $sliceText[1],
'count' => $count,
];
}
usort($data, fn($a, $b) => $b['count'] <=> $a['count']);
$result[] = [
'unit' => $unitName,
'data' => $data,
];
}
// paginate manually
$total = count($result);
$chunks = array_chunk($result, $perPage);
$currentData = $chunks[$page-1] ?? [];
return response()->json([
'status' => true,
'data' => $currentData,
'message' => 'Berhasil mendapatkan data',
'pagination' => [
'current_page' => $page,
'per_page' => $perPage,
'total' => $total,
'last_page' => max(1, ceil($total / $perPage)),
'has_more' => $page < max(1, ceil($total / $perPage)),
]
]);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => 'Gagal! mendapatkan data'
]);
}
}
public function recapView(){
return view('dashboard.recap', ['title' => 'Rekap Dokumen']);
}
public function pendingFile(){
return view('pendingFile.index', ['title' => 'Data Pending']);
}
public function dataPendingFile(){
$perPage = (int) request('per_page', 10);
$keyword = request('keyword');
$start = request('start_date');
$end = request('end_date');
$authUnit = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
$query = FileDirectory::where('statusenabled', true)->where(function($q){
$q->where('status_action', '!=', 'approved')
->orWhereNull('status_action');
})->whereIn('id_unit_kerja', $authUnit)->orderBy('entry_at','desc');
if($keyword){
$query->where(function($q) use ($keyword){
$q->where('file', 'ILIKE', "%{$keyword}%")
->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%");
});
}
if($start){
$query->whereDate('entry_at','>=',$start);
}
if($end){
$query->whereDate('entry_at','<=',$end);
}
$paginated = $query->paginate($perPage);
$data = $paginated->getCollection()->map(function($item){
$dataSlice = array_values(array_filter(explode('/', $item->file)));
return [
'file_directory_id' => $item->file_directory_id,
'pegawai_nama_entry' => $item->pegawai_nama_entry,
'part' => $dataSlice[0] . '/' . $dataSlice[1],
'folder' => $dataSlice[2],
'fileName' =>$dataSlice[3],
'file' => $item->file,
'no_dokumen' => $item->no_dokumen,
'entry_at' => $item->entry_at,
'tanggal_terbit' => $item->tanggal_terbit,
'permission_file' => $item->permission_file,
'status_action' => $item->status_action
];
});
return response()->json([
'status' => true,
'data' => $data,
'pagination' => [
'current_page' => $paginated->currentPage(),
'next_page' => $paginated->hasMorePages() ? $paginated->currentPage() + 1 : null,
'has_more' => $paginated->hasMorePages(),
'last_page' => $paginated->lastPage(),
'per_page' => $paginated->perPage(),
'total' => $paginated->total(),
]
]);
}
public function approvePendingFile(string $id){
try {
$data = FileDirectory::where('file_directory_id', $id)->first();
if(!$data){
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
}
$data->update([
'status_action' => 'approved',
'action_at' => now(),
'action_by' => auth()->user()->dataUser->id,
]);
$payloadLog = [
'file_directory_id' => $data->file_directory_id,
'pegawai_id_entry' => $data->action_by,
'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap,
'entry_at' => $data->action_at,
'action_type' => 'Approval Dokumen',
'statusenabled' => true,
'mod_change' => $data->entry_at,
'id_unit_kerja' => $data->id_unit_kerja,
'id_sub_unit_kerja' => $data->id_sub_unit_kerja,
'file' => $data->file,
'tanggal_terbit' => $data->tanggal_terbit,
'no_dokumen' => $data->no_dokumen,
'permission_file' => $data->permission_file,
];
LogActivity::create($payloadLog);
return response()->json([
'status' => true,
'message' => 'File berhasil di-approve'
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
public function rejectPendingFile(string $id){
try {
$data = FileDirectory::where('file_directory_id', $id)->first();
if(!$data){
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
}
$data->update([
'status_action' => 'rejected',
'action_at' => now(),
'action_by' => auth()->user()->dataUser->id,
]);
$payloadLog = [
'file_directory_id' => $data->file_directory_id,
'pegawai_id_entry' => $data->action_by,
'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap,
'entry_at' => $data->action_at,
'action_type' => 'Reject Dokumen',
'statusenabled' => true,
'mod_change' => $data->entry_at,
'id_unit_kerja' => $data->id_unit_kerja,
'id_sub_unit_kerja' => $data->id_sub_unit_kerja,
'file' => $data->file,
'tanggal_terbit' => $data->tanggal_terbit,
'no_dokumen' => $data->no_dokumen,
'permission_file' => $data->permission_file,
];
LogActivity::create($payloadLog);
return response()->json([
'status' => true,
'message' => 'File berhasil di-reject'
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
public function countDataPending(){
try {
$query = FileDirectory::where('statusenabled', true)
->whereNull('status_action');
$authUnit = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
$count= $query->whereIn('id_unit_kerja', $authUnit)->count();
return response()->json([
'status' => true,
'count' => $count,
'message' => 'Berhasil mendapatkan data'
]);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => 'Terdapat kesalahan!'
]);
}
}
public function pengajuanFile(){
return view('pengajuanFile.index', ['title' => 'Data Pending']);
}
public function dataPengajuanFile(){
$perPage = (int) request('per_page', 10);
$keyword = request('keyword');
$start = request('start_date');
$end = request('end_date');
$query = FileDirectory::where('statusenabled', true)->where('pegawai_id_entry', auth()->user()->objectpegawaifk)
->where(function($q){
$q->where('status_action', '!=', 'approved')
->orWhereNull('status_action');
})->orderBy('entry_at','desc');
if($keyword){
$query->where(function($q) use ($keyword){
$q->where('file', 'ILIKE', "%{$keyword}%")
->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%");
});
}
if($start){
$query->whereDate('entry_at','>=',$start);
}
if($end){
$query->whereDate('entry_at','<=',$end);
}
$paginated = $query->paginate($perPage);
$data = $paginated->getCollection()->map(function($item){
$dataSlice = array_values(array_filter(explode('/', $item->file)));
return [
'file_directory_id' => $item->file_directory_id,
'pegawai_nama_entry' => $item->pegawai_nama_entry,
'part' => $dataSlice[0] . '/' . $dataSlice[1],
'folder' => $dataSlice[2],
'fileName' =>$dataSlice[3],
'file' => $item->file,
'no_dokumen' => $item->no_dokumen,
'entry_at' => $item->entry_at,
'tanggal_terbit' => $item->tanggal_terbit,
'permission_file' => $item->permission_file,
'status_action' => $item->status_action
];
});
return response()->json([
'status' => true,
'data' => $data,
'pagination' => [
'current_page' => $paginated->currentPage(),
'next_page' => $paginated->hasMorePages() ? $paginated->currentPage() + 1 : null,
'has_more' => $paginated->hasMorePages(),
'last_page' => $paginated->lastPage(),
'per_page' => $paginated->perPage(),
'total' => $paginated->total(),
]
]);
}
}