update
This commit is contained in:
@ -22,6 +22,7 @@
|
|||||||
"author": "STS",
|
"author": "STS",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^1.17.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"compression": "^1.7.5",
|
"compression": "^1.7.5",
|
||||||
"config": "^3.3.12",
|
"config": "^3.3.12",
|
||||||
|
|||||||
@ -1,223 +1,171 @@
|
|||||||
import { Response, NextFunction } from "express";
|
import { NextFunction, Response } from "express";
|
||||||
import { Request } from "express-jwt";
|
import { Request } from "express-jwt";
|
||||||
import { ReturnHelper } from "../../helpers/express/return";
|
import { UploadedFile } from "express-fileupload";
|
||||||
|
import fs from "fs"; // Import fs module to check if directory exists
|
||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import { ILogObj, Logger } from "tslog";
|
import { ILogObj, Logger } from "tslog";
|
||||||
|
import CommonHelper from "../../helpers/common";
|
||||||
|
import { ReturnHelper } from "../../helpers/express/return";
|
||||||
import { Language } from "../../langs/lang";
|
import { Language } from "../../langs/lang";
|
||||||
import fileUpload from "express-fileupload";
|
import config from "config";
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import Thirdparty from "../../helpers/thirdparty";
|
||||||
import fs from "fs";
|
import JwtHelper from "../../helpers/jwt";
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
const log: Logger<ILogObj> = new Logger({ name: '[FileController]', type: 'pretty' });
|
const log: Logger<ILogObj> = new Logger({
|
||||||
const STORAGE_DIR = 'assets/saude/';
|
name: "[FileController]",
|
||||||
|
type: "pretty",
|
||||||
|
});
|
||||||
|
|
||||||
export class FileController {
|
export class FileController {
|
||||||
static async upload(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
static async upload(req: Request, res: Response, next: NextFunction): Promise<void | Response> {
|
||||||
/* #swagger.tags = ['Handle File']
|
/*
|
||||||
#swagger.security = [{ "bearerAuth": [] }]
|
#swagger.tags = ['File']
|
||||||
#swagger.consumes = ['multipart/form-data']
|
#swagger.security = [{
|
||||||
#swagger.requestBody = {
|
"bearerAuth": []
|
||||||
required: true,
|
}]
|
||||||
content: {
|
#swagger.requestBody = {
|
||||||
"multipart/form-data": {
|
required: true,
|
||||||
schema: {
|
content: {
|
||||||
type: "object",
|
"multipart/form-data": {
|
||||||
properties: {
|
schema: {
|
||||||
file: {
|
type: "object",
|
||||||
type: "string",
|
properties: {
|
||||||
format: "binary",
|
file: {
|
||||||
description: "Image file (max 1MB, jpg/png/webp)"
|
type: "string",
|
||||||
},
|
format: "binary"
|
||||||
},
|
}
|
||||||
required: ["file"]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
// Check if file exists
|
|
||||||
if (!req.files || !req.files.file) {
|
|
||||||
return ReturnHelper.errorResponse(res, 400, 404, Language.lang.failed_insert, "File not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = req.files.file as fileUpload.UploadedFile;
|
|
||||||
|
|
||||||
// Validate file size (max 1MB)
|
|
||||||
const maxSize = 10 * 1024 * 1024; // 10MB
|
|
||||||
if (file.size > maxSize) {
|
|
||||||
return ReturnHelper.errorResponse(
|
|
||||||
res,
|
|
||||||
400,
|
|
||||||
400,
|
|
||||||
Language.lang.failed_insert,
|
|
||||||
"File size exceeds 10MB limit"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate file type
|
|
||||||
const allowedMimes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/svg+xml', 'image/svg'];
|
|
||||||
if (!allowedMimes.includes(file.mimetype)) {
|
|
||||||
return ReturnHelper.errorResponse(res, 400, 400, Language.lang.failed_insert, "Invalid file type. Only JPG, PNG, WEBP, and SVG are allowed");
|
|
||||||
}
|
|
||||||
const ext = file.name.split('.');
|
|
||||||
const name = uuidv4() + '.' + ext[ext.length - 1];
|
|
||||||
|
|
||||||
const result: { file: string } = {
|
|
||||||
file: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
const folder_path = STORAGE_DIR;
|
|
||||||
const file_path = path.join(folder_path, name);
|
|
||||||
|
|
||||||
// Create directory if it doesn't exist
|
|
||||||
if (!fs.existsSync(folder_path)) {
|
|
||||||
fs.mkdirSync(folder_path, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move file to destination
|
|
||||||
await file.mv(file_path);
|
|
||||||
|
|
||||||
result.file = name;
|
|
||||||
|
|
||||||
log.info(`File uploaded successfully: ${file_path}`);
|
|
||||||
|
|
||||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_insert, result);
|
|
||||||
|
|
||||||
} catch (e: unknown) {
|
|
||||||
// Proper error logging to avoid tslog serialization issues
|
|
||||||
if (e instanceof Error) {
|
|
||||||
log.error("File upload failed:", {
|
|
||||||
message: e.message,
|
|
||||||
stack: e.stack,
|
|
||||||
name: e.name
|
|
||||||
});
|
|
||||||
return ReturnHelper.errorResponse(res, 500, 500, Language.lang.failed_insert, e.message);
|
|
||||||
} else {
|
|
||||||
log.error("File upload failed with unknown error:", String(e));
|
|
||||||
return ReturnHelper.errorResponse(res, 500, 500, Language.lang.failed_insert, "Unknown error occurred");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
|
try {
|
||||||
|
const uploadedFile: UploadedFile | any = req.files.file;
|
||||||
|
|
||||||
static async delete(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
const schema = Joi.object({
|
||||||
/*
|
file: Joi.object({
|
||||||
#swagger.tags = ['Handle File']
|
name: Joi.string().label("File Name"),
|
||||||
#swagger.security = [{ "bearerAuth": [] }]
|
mimetype: Joi.string()
|
||||||
#swagger.requestBody = {
|
.valid(
|
||||||
required: true,
|
"image/jpeg",
|
||||||
content: {
|
"image/png",
|
||||||
"application/json": {
|
"application/pdf",
|
||||||
schema: {
|
"application/vnd.ms-excel", // ✅ .xls
|
||||||
type: "object",
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // ✅ .xlsx
|
||||||
properties: {
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
file_name: { type: "string", description: "File name to delete" }
|
"text/csv", // csv
|
||||||
},
|
)
|
||||||
required: ["file_name"]
|
.optional()
|
||||||
}
|
.label("File Type"),
|
||||||
}
|
size: Joi.number()
|
||||||
}
|
.max(10 * 1024 * 1024)
|
||||||
}
|
.optional()
|
||||||
*/
|
.label("File Size"),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.label("File"),
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
const fileData = {
|
||||||
const schema = Joi.object().keys({
|
name: uploadedFile.name,
|
||||||
file_name: Joi.string().required().label('File Name'),
|
mimetype: uploadedFile.mimetype,
|
||||||
});
|
size: uploadedFile.size,
|
||||||
|
};
|
||||||
|
|
||||||
const param: { file_name: string } = await schema.validateAsync(req.body);
|
let body = await schema.validateAsync({ file: fileData });
|
||||||
|
|
||||||
if (param.file_name.includes('..') || param.file_name.includes('/') || param.file_name.includes('\\')) {
|
const field = {
|
||||||
return ReturnHelper.errorResponse(res, 400, 400, Language.lang.failed_delete, "Invalid file name");
|
file: uploadedFile,
|
||||||
}
|
application: "saude",
|
||||||
|
};
|
||||||
|
|
||||||
const file_path = path.join(STORAGE_DIR, param.file_name);
|
let url = config.get("service.file") + "upload";
|
||||||
|
let result = await Thirdparty.UploadFile(url, field, JwtHelper.token(req.auth.data));
|
||||||
|
console.log("result :", result);
|
||||||
|
|
||||||
// Check if file exists
|
let data = { file: result.data.file };
|
||||||
if (!fs.existsSync(file_path)) {
|
return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
|
||||||
return ReturnHelper.errorResponse(res, 404, 404, Language.lang.failed_not_found, "File not found");
|
} catch (e: unknown) {
|
||||||
}
|
log.error(e);
|
||||||
|
const err = e as Error;
|
||||||
|
|
||||||
// Delete file
|
return ReturnHelper.errorResponse(res, 400, 401, Language.lang.failed_view, err.message);
|
||||||
fs.unlinkSync(file_path);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_delete, {});
|
static async download(req: Request, res: Response, next: NextFunction): Promise<void | Response> {
|
||||||
} catch (e: unknown) {
|
/*
|
||||||
log.error(e);
|
#swagger.tags = ['File']
|
||||||
const err = e as Error;
|
#swagger.security = [{
|
||||||
|
"bearerAuth": []
|
||||||
return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_delete, err.message);
|
}]
|
||||||
|
#swagger.parameters['name'] = {
|
||||||
|
in: 'query',
|
||||||
|
type: 'string'
|
||||||
}
|
}
|
||||||
}
|
#swagger.parameters['token'] = {
|
||||||
|
in: 'query',
|
||||||
static async download(req: Request, res: Response, next: NextFunction): Promise<void | Response> {
|
required: true,
|
||||||
/*
|
type: 'string'
|
||||||
#swagger.tags = ['Handle File']
|
|
||||||
#swagger.security = [{ "bearerAuth": [] }]
|
|
||||||
#swagger.parameters['name'] = {
|
|
||||||
in: 'query',
|
|
||||||
required: true,
|
|
||||||
type: 'string',
|
|
||||||
description: 'File name'
|
|
||||||
}
|
|
||||||
#swagger.parameters['token'] = {
|
|
||||||
in: 'query',
|
|
||||||
required: true,
|
|
||||||
type: 'string',
|
|
||||||
description: 'Token'
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
const schema = Joi.object({
|
|
||||||
name: Joi.string().required().label("File Name"),
|
|
||||||
token: Joi.string().required().label("Token"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const param: { name: string } = await schema.validateAsync(req.query);
|
|
||||||
|
|
||||||
if (param.name.includes('..') || param.name.includes('/') || param.name.includes('\\')) {
|
|
||||||
return ReturnHelper.errorResponse(res, 400, 400, Language.lang.failed_not_found, "Invalid file name");
|
|
||||||
}
|
|
||||||
|
|
||||||
const file_path = path.join(STORAGE_DIR, param.name);
|
|
||||||
|
|
||||||
if (!fs.existsSync(file_path)) {
|
|
||||||
return ReturnHelper.errorResponse(res, 404, 404, Language.lang.failed_not_found, "File not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const buffer = fs.readFileSync(file_path);
|
|
||||||
const fileName = param.name;
|
|
||||||
const ext = fileName.split(".").pop()?.toLowerCase();
|
|
||||||
|
|
||||||
const mimeMap: Record<string, string> = {
|
|
||||||
jpg: "image/jpeg",
|
|
||||||
jpeg: "image/jpeg",
|
|
||||||
png: "image/png",
|
|
||||||
webp: "image/webp",
|
|
||||||
gif: "image/gif",
|
|
||||||
pdf: "application/pdf",
|
|
||||||
svg: "image/svg+xml",
|
|
||||||
};
|
|
||||||
|
|
||||||
const contentType = mimeMap[ext ?? ""] ?? "application/octet-stream";
|
|
||||||
|
|
||||||
res.setHeader("Content-Type", contentType);
|
|
||||||
res.setHeader("Content-Length", buffer.length);
|
|
||||||
|
|
||||||
const isInline = contentType.startsWith("image/") || contentType === "application/pdf";
|
|
||||||
|
|
||||||
if (isInline) {
|
|
||||||
res.setHeader("Content-Disposition", `inline; filename="${encodeURIComponent(fileName)}"`);
|
|
||||||
} else {
|
|
||||||
res.setHeader("Content-Disposition", `attachment; filename="${encodeURIComponent(fileName)}"`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.end(buffer);
|
|
||||||
} catch (e: unknown) {
|
|
||||||
log.error(e);
|
|
||||||
const err = e as Error;
|
|
||||||
return ReturnHelper.errorResponse(res, 400, 401, Language.lang.failed_not_found, err.message);
|
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
}
|
try {
|
||||||
|
// 1️⃣ Validasi parameter
|
||||||
|
const schema = Joi.object({
|
||||||
|
name: Joi.string().required().label("File Name"),
|
||||||
|
token: Joi.string().required().label("Token"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const param = await schema.validateAsync(req.query);
|
||||||
|
|
||||||
|
// 2️⃣ Ambil file dari service-file via SFTP (bukan static URL /file/ yang diarahkan ke frontend)
|
||||||
|
const url = config.get("service.file") + "download";
|
||||||
|
const buffer = await Thirdparty.DownloadFile(url, { file: param.name, application: "saude" }, param.token);
|
||||||
|
|
||||||
|
// 3️⃣ Deteksi ekstensi & MIME type
|
||||||
|
const fileName = param.name;
|
||||||
|
const ext = fileName.split(".").pop()?.toLowerCase();
|
||||||
|
|
||||||
|
const mimeMap: Record<string, string> = {
|
||||||
|
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
xls: "application/vnd.ms-excel",
|
||||||
|
csv: "text/csv",
|
||||||
|
pdf: "application/pdf",
|
||||||
|
jpg: "image/jpeg",
|
||||||
|
jpeg: "image/jpeg",
|
||||||
|
png: "image/png",
|
||||||
|
gif: "image/gif",
|
||||||
|
doc: "application/msword",
|
||||||
|
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
zip: "application/zip",
|
||||||
|
txt: "text/plain",
|
||||||
|
};
|
||||||
|
|
||||||
|
const contentType = mimeMap[ext ?? ""] ?? "application/octet-stream";
|
||||||
|
|
||||||
|
// 4️⃣ Set header tipe file
|
||||||
|
res.setHeader("Content-Type", contentType);
|
||||||
|
res.setHeader("Content-Length", buffer.length);
|
||||||
|
|
||||||
|
// 5️⃣ Tentukan apakah file perlu auto download
|
||||||
|
const isInline = contentType.startsWith("image/") || contentType === "application/pdf";
|
||||||
|
|
||||||
|
// 🟢 Kalau image/pdf → tampil di browser
|
||||||
|
// 🔵 Kalau file lain → download otomatis
|
||||||
|
if (isInline) {
|
||||||
|
res.setHeader("Content-Disposition", `inline; filename="${encodeURIComponent(fileName)}"`);
|
||||||
|
} else {
|
||||||
|
res.setHeader("Content-Disposition", `attachment; filename="${encodeURIComponent(fileName)}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6️⃣ Kirim file ke browser
|
||||||
|
return res.end(buffer);
|
||||||
|
} catch (e: unknown) {
|
||||||
|
log.error(e);
|
||||||
|
const err = e as Error;
|
||||||
|
return ReturnHelper.errorResponse(res, 400, 401, Language.lang.failed_not_found, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,51 +1,69 @@
|
|||||||
import { NextFunction, Response } from 'express';
|
import { NextFunction, Response } from "express";
|
||||||
import { Logger, ILogObj } from 'tslog';
|
import { Logger, ILogObj } from "tslog";
|
||||||
import { Request, expressjwt } from "express-jwt";
|
import { Request, expressjwt } from "express-jwt";
|
||||||
import fs from 'fs';
|
import fs from "fs";
|
||||||
import { Language } from '../langs/lang';
|
import { Language } from "../langs/lang";
|
||||||
import { ReturnHelper } from './express/return';
|
import { ReturnHelper } from "./express/return";
|
||||||
import express from 'express';
|
import express from "express";
|
||||||
|
import config from "config";
|
||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
|
||||||
const log: Logger<ILogObj> = new Logger({ name: '[JwtHelper]', type: 'pretty' });
|
const log: Logger<ILogObj> = new Logger({ name: "[JwtHelper]", type: "pretty" });
|
||||||
|
|
||||||
export default class JwtHelper {
|
export default class JwtHelper {
|
||||||
static secure = (app: express.Application) => {
|
static secure = (app: express.Application) => {
|
||||||
|
var publicKey = fs.readFileSync("src/helpers/key/public.key");
|
||||||
|
|
||||||
var publicKey = fs.readFileSync("src/helpers/key/public.key");
|
app.use(
|
||||||
|
expressjwt({
|
||||||
|
secret: publicKey,
|
||||||
|
algorithms: ["RS256"],
|
||||||
|
getToken: function fromHeaderOrQuerystring(req): any {
|
||||||
|
if (req.headers.authorization && req.headers.authorization.split(" ")[0] === "Bearer") {
|
||||||
|
return req.headers.authorization.split(" ")[1];
|
||||||
|
} else if (req.query && req.query.token) {
|
||||||
|
return req.query.token;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}).unless({
|
||||||
|
path: [
|
||||||
|
"/token",
|
||||||
|
/^\/uploads\/.*/, // ⚠️ TAMBAHKAN INI - exclude semua path /uploads/
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
function (req: Request, res: Response, next: NextFunction) {
|
||||||
|
if (!req.auth?.data.id) {
|
||||||
|
return ReturnHelper.errorResponse(res, 403, 666, Language.lang.failed_access);
|
||||||
|
}
|
||||||
|
|
||||||
app.use(
|
return next();
|
||||||
expressjwt({
|
},
|
||||||
secret: publicKey, algorithms: ["RS256"],
|
);
|
||||||
getToken: function fromHeaderOrQuerystring(req): any {
|
|
||||||
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
|
|
||||||
return req.headers.authorization.split(' ')[1];
|
|
||||||
} else if (req.query && req.query.token) {
|
|
||||||
return req.query.token;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
}).unless({
|
|
||||||
path: [
|
|
||||||
"/token",
|
|
||||||
/^\/uploads\/.*/ // ⚠️ TAMBAHKAN INI - exclude semua path /uploads/
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
function (req: Request, res: Response, next: NextFunction) {
|
|
||||||
if (!req.auth?.data.id) {
|
|
||||||
return ReturnHelper.errorResponse(res, 403, 666, Language.lang.failed_access);
|
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
app.use(function (err: any, req: Request, res: Response, next: NextFunction) {
|
||||||
}
|
if (err.name === "UnauthorizedError") {
|
||||||
)
|
return ReturnHelper.errorResponse(res, 403, 666, Language.lang.failed_access);
|
||||||
|
}
|
||||||
|
|
||||||
app.use(function (err: any, req: Request, res: Response, next: NextFunction) {
|
return next();
|
||||||
if (err.name === 'UnauthorizedError') {
|
});
|
||||||
return ReturnHelper.errorResponse(res, 403, 666, Language.lang.failed_access);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
static token = (user: { id: string; username: string; name: string }) => {
|
||||||
});
|
var privateKey = fs.readFileSync("src/helpers/key/private.key");
|
||||||
|
var token = jwt.sign(
|
||||||
}
|
{
|
||||||
}
|
exp: Math.floor(Date.now() / 1000) + Number(config.get("auth.access_token_lifetime")),
|
||||||
|
data: {
|
||||||
|
id: user.id,
|
||||||
|
username: user.username,
|
||||||
|
name: user.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
privateKey,
|
||||||
|
{ algorithm: "RS256" },
|
||||||
|
);
|
||||||
|
return token;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
108
src/helpers/thirdparty.ts
Normal file
108
src/helpers/thirdparty.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default class Thirdparty {
|
||||||
|
static async GetData(url: string, field: any, token?: string) {
|
||||||
|
try {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (token) {
|
||||||
|
headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.get(url, { params: field, headers });
|
||||||
|
const result = response.data;
|
||||||
|
|
||||||
|
if (result.status) {
|
||||||
|
return { status: true, message: "Success fetch data", data: result.data };
|
||||||
|
} else {
|
||||||
|
// Add a default return for falsy result.status
|
||||||
|
return { status: false, message: "Unexpected response status", data: null };
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
const { response } = error;
|
||||||
|
return {
|
||||||
|
status: false,
|
||||||
|
message: response?.data?.error ?? response?.data?.message ?? "Unknown error",
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async PostData(url: string, field: any, token?: string) {
|
||||||
|
try {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (token) {
|
||||||
|
headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
const response = await axios.post(url, field, { headers });
|
||||||
|
const result = response.data;
|
||||||
|
return result;
|
||||||
|
} catch (error: any) {
|
||||||
|
const { response } = error;
|
||||||
|
return { status: false, message: response?.data?.error ?? response?.data?.message ?? "Unknown error" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UploadFile(url: string, field: any, token?: string) {
|
||||||
|
try {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (token) {
|
||||||
|
headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
|
||||||
|
// Append the file and other fields to FormData
|
||||||
|
for (const key in field) {
|
||||||
|
if (field.hasOwnProperty(key)) {
|
||||||
|
const value = field[key];
|
||||||
|
|
||||||
|
if (value instanceof Object && value.data && value.mimetype) {
|
||||||
|
// Convert file-like object to a Blob
|
||||||
|
const blob = new Blob([value.data], { type: value.mimetype });
|
||||||
|
formData.append(key, blob, value.name); // Use name as filename
|
||||||
|
} else {
|
||||||
|
formData.append(key, value); // Append non-file fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post(url, formData, {
|
||||||
|
headers: { ...headers, "Content-Type": "multipart/form-data" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = response.data;
|
||||||
|
|
||||||
|
if (!result.status) throw response;
|
||||||
|
return result;
|
||||||
|
} catch (error: any) {
|
||||||
|
const { response } = error;
|
||||||
|
|
||||||
|
throw {
|
||||||
|
status: false,
|
||||||
|
message: response?.data?.error ?? response?.data?.message ?? "Unknown error",
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async DownloadFile(url: string, field: any, token?: string) {
|
||||||
|
try {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (token) {
|
||||||
|
headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.get(url, { params: field, headers, responseType: "arraybuffer" });
|
||||||
|
const result = response.data;
|
||||||
|
|
||||||
|
return Buffer.from(result);
|
||||||
|
} catch (error: any) {
|
||||||
|
const { response } = error;
|
||||||
|
throw {
|
||||||
|
status: false,
|
||||||
|
message: response?.data?.error ?? response?.data?.message ?? "Unknown error",
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -101,9 +101,8 @@ export class RoutePrivate {
|
|||||||
app.delete("/api/menu/delete/:id/:hard", MenuController.delete);
|
app.delete("/api/menu/delete/:id/:hard", MenuController.delete);
|
||||||
app.put("/api/menu/restore/:id", MenuController.restore);
|
app.put("/api/menu/restore/:id", MenuController.restore);
|
||||||
|
|
||||||
app.post('/api/upload', FileController.upload)
|
app.post("/api/upload", FileController.upload);
|
||||||
app.delete('/api/delete', FileController.delete)
|
app.get("/api/download", FileController.download);
|
||||||
app.get('/api/download', FileController.download)
|
|
||||||
|
|
||||||
app.get("/api/administrativu/list", AdministrativuController.list);
|
app.get("/api/administrativu/list", AdministrativuController.list);
|
||||||
app.get("/api/administrativu/export", AdministrativuController.export);
|
app.get("/api/administrativu/export", AdministrativuController.export);
|
||||||
|
|||||||
Reference in New Issue
Block a user