Merge pull request 'amalia/21-nov-25' (#34) from amalia/21-nov-25 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/34
This commit is contained in:
25
src/server/lib/detect-type-of-file.ts
Normal file
25
src/server/lib/detect-type-of-file.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
function getExtension(fileName: string): string | null {
|
||||
if (!fileName || typeof fileName !== "string") return null;
|
||||
|
||||
const parts = fileName.split(".");
|
||||
if (parts.length <= 1) return null;
|
||||
|
||||
return parts.pop()?.toLowerCase() || null;
|
||||
}
|
||||
|
||||
|
||||
export function detectFileType(fileName: string) {
|
||||
const ext = getExtension(fileName);
|
||||
|
||||
if (!ext) return { ext: null, type: "unknown" };
|
||||
|
||||
if (["jpg", "jpeg", "png", "gif", "webp", "bmp"].includes(ext)) {
|
||||
return { ext, type: "image" };
|
||||
}
|
||||
|
||||
if (ext === "pdf") {
|
||||
return { ext, type: "pdf" };
|
||||
}
|
||||
|
||||
return { ext, type: "other" };
|
||||
}
|
||||
@@ -94,7 +94,6 @@ export async function fetchWithAuth(config: Config, url: string, options: Reques
|
||||
} catch {
|
||||
console.error('🔍 Could not read response body');
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@@ -139,7 +138,7 @@ export async function catFile(config: Config, folder: string, fileName: string):
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export async function uploadFile(config: Config, file: File): Promise<string> {
|
||||
export async function uploadFile(config: Config, file: File, folder: string): Promise<string> {
|
||||
const remoteName = path.basename(file.name);
|
||||
|
||||
// 1. Dapatkan upload link (pakai Authorization)
|
||||
@@ -152,7 +151,7 @@ export async function uploadFile(config: Config, file: File): Promise<string> {
|
||||
// 2. Siapkan form-data
|
||||
const formData = new FormData();
|
||||
formData.append("parent_dir", "/");
|
||||
formData.append("relative_path", "syarat-dokumen"); // tanpa slash di akhir
|
||||
formData.append("relative_path", folder); // tanpa slash di akhir
|
||||
formData.append("file", file, remoteName); // file langsung, jangan pakai Blob
|
||||
|
||||
// 3. Upload file TANPA Authorization header, token di query param
|
||||
@@ -232,10 +231,10 @@ export async function uploadFileToFolder(config: Config, base64File: { name: str
|
||||
}
|
||||
|
||||
|
||||
export async function removeFile(config: Config, fileName: string, folder: string): Promise<string> {
|
||||
const res = await fetchWithAuth(config, `${config.URL}/${config.REPO}/file/?p=/${folder}/${fileName}`, { method: 'DELETE' });
|
||||
|
||||
|
||||
export async function removeFile(config: Config, fileName: string): Promise<string> {
|
||||
await fetchWithAuth(config, `${config.URL}/${config.REPO}/file/?p=/${fileName}`, { method: 'DELETE' });
|
||||
if (!res.ok) return 'gagal menghapus file';
|
||||
return `🗑️ Removed ${fileName}`
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { generateNoPengaduan } from "../lib/no-pengaduan"
|
||||
import { normalizePhoneNumber } from "../lib/normalizePhone"
|
||||
import { prisma } from "../lib/prisma"
|
||||
import { renameFile } from "../lib/rename-file"
|
||||
import { catFile, defaultConfigSF, uploadFile, uploadFileBase64 } from "../lib/seafile"
|
||||
import { catFile, defaultConfigSF, removeFile, uploadFile, uploadFileBase64 } from "../lib/seafile"
|
||||
|
||||
const PengaduanRoute = new Elysia({
|
||||
prefix: "pengaduan",
|
||||
@@ -176,7 +176,7 @@ const PengaduanRoute = new Elysia({
|
||||
title: judulPengaduan,
|
||||
detail: detailPengaduan,
|
||||
idCategory: idCategoryFix,
|
||||
idWarga: idWargaFix,
|
||||
idWarga: idWargaFix || "",
|
||||
location: lokasi,
|
||||
image: imageFix,
|
||||
noPengaduan,
|
||||
@@ -218,23 +218,20 @@ const PengaduanRoute = new Elysia({
|
||||
description: "Alamat atau titik lokasi pengaduan"
|
||||
}),
|
||||
|
||||
namaGambar: t.String({
|
||||
optional: true,
|
||||
namaGambar: t.Optional(t.String({
|
||||
examples: ["sampah.jpg"],
|
||||
description: "Nama file gambar yang telah diupload (opsional)"
|
||||
}),
|
||||
})),
|
||||
|
||||
kategoriId: t.String({
|
||||
optional: true,
|
||||
kategoriId: t.Optional(t.String({
|
||||
examples: ["kebersihan"],
|
||||
description: "ID atau nama kategori pengaduan (contoh: kebersihan, keamanan, lainnya)"
|
||||
}),
|
||||
})),
|
||||
|
||||
wargaId: t.String({
|
||||
optional: true,
|
||||
wargaId: t.Optional(t.String({
|
||||
examples: ["budiman"],
|
||||
description: "ID unik warga yang melapor (jika sudah terdaftar)"
|
||||
}),
|
||||
})),
|
||||
|
||||
noTelepon: t.String({
|
||||
error: "Nomor telepon harus diisi",
|
||||
@@ -517,7 +514,7 @@ Respon:
|
||||
}
|
||||
})
|
||||
.post("/upload", async ({ body }) => {
|
||||
const { file } = body;
|
||||
const { file, folder } = body;
|
||||
|
||||
// Validasi file
|
||||
if (!file) {
|
||||
@@ -530,7 +527,7 @@ Respon:
|
||||
|
||||
// Upload ke Seafile (pastikan uploadFile menerima Blob atau ArrayBuffer)
|
||||
// const buffer = await file.arrayBuffer();
|
||||
const result = await uploadFile(defaultConfigSF, renamedFile);
|
||||
const result = await uploadFile(defaultConfigSF, renamedFile, folder);
|
||||
if (result == 'gagal') {
|
||||
return { success: false, message: "Upload gagal" };
|
||||
}
|
||||
@@ -544,7 +541,8 @@ Respon:
|
||||
};
|
||||
}, {
|
||||
body: t.Object({
|
||||
file: t.Any()
|
||||
file: t.Any(),
|
||||
folder: t.String(),
|
||||
}),
|
||||
detail: {
|
||||
summary: "Upload File",
|
||||
@@ -728,12 +726,14 @@ Respon:
|
||||
const hasil = await catFile(defaultConfigSF, folder, fileName);
|
||||
|
||||
const ext = fileName.split(".").pop()?.toLowerCase();
|
||||
const mime =
|
||||
ext === "jpg" || ext === "jpeg"
|
||||
? "image/jpeg"
|
||||
: ext === "png"
|
||||
? "image/png"
|
||||
: "application/octet-stream";
|
||||
let mime = "application/octet-stream"; // default
|
||||
|
||||
if (["jpg", "jpeg"].includes(ext!)) mime = "image/jpeg";
|
||||
if (["png"].includes(ext!)) mime = "image/png";
|
||||
if (["gif"].includes(ext!)) mime = "image/gif";
|
||||
if (["webp"].includes(ext!)) mime = "image/webp";
|
||||
if (["svg"].includes(ext!)) mime = "image/svg+xml";
|
||||
if (["pdf"].includes(ext!)) mime = "application/pdf";
|
||||
|
||||
set.headers["Content-Type"] = mime;
|
||||
set.headers["Content-Length"] = hasil.byteLength.toString();
|
||||
@@ -749,6 +749,33 @@ Respon:
|
||||
description: "tool untuk mendapatkan gambar",
|
||||
}
|
||||
})
|
||||
.post("/delete-image", async ({ body }) => {
|
||||
const { file, folder } = body;
|
||||
|
||||
// Validasi file
|
||||
if (!file) {
|
||||
return { success: false, message: "File tidak ditemukan" };
|
||||
}
|
||||
|
||||
const result = await removeFile(defaultConfigSF, file, folder);
|
||||
if (result == 'gagal') {
|
||||
return { success: false, message: "Delete gagal" };
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Delete berhasil",
|
||||
};
|
||||
}, {
|
||||
body: t.Object({
|
||||
file: t.String(),
|
||||
folder: t.String(),
|
||||
}),
|
||||
detail: {
|
||||
summary: "Delete File",
|
||||
description: "Tool untuk delete file Seafile",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
;
|
||||
|
||||
@@ -21,6 +21,11 @@ const SuratRoute = new Elysia({
|
||||
select: {
|
||||
DataTextPelayanan: true,
|
||||
}
|
||||
},
|
||||
CategoryPelayanan: {
|
||||
select: {
|
||||
name: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -37,6 +42,7 @@ const SuratRoute = new Elysia({
|
||||
surat: {
|
||||
id: dataSurat?.id,
|
||||
idCategory: dataSurat?.idCategory,
|
||||
nameCategory: dataSurat?.CategoryPelayanan?.name,
|
||||
noSurat: dataSurat?.noSurat,
|
||||
dataText: dataSurat?.PelayananAjuan?.DataTextPelayanan,
|
||||
createdAt: dataSurat?.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
|
||||
|
||||
@@ -62,8 +62,8 @@ const WargaRoute = new Elysia({
|
||||
phone: t.String({ minLength: 1 })
|
||||
}),
|
||||
detail: {
|
||||
summary: "edit konfigurasi desa",
|
||||
description: `tool untuk edit konfigurasi desa`
|
||||
summary: "Edit Warga",
|
||||
description: `tool untuk edit warga`
|
||||
}
|
||||
})
|
||||
.get("/detail", async ({ query }) => {
|
||||
|
||||
Reference in New Issue
Block a user