mirror of
https://github.com/kyantech/Palmr.git
synced 2025-10-26 01:23:35 +00:00
refactor(file-handling): replace multer with fastify multipart for file uploads
This commit removes the dependency on multer and replaces it with fastify's built-in multipart handling for file uploads. The changes include: - Removing multer and related dependencies from package.json. - Refactoring logo and avatar services to handle base64 encoded images directly. - Updating docker-compose configurations to reflect changes in file storage. - Adding new documentation for file upload processes. The refactor simplifies the file upload process, reduces dependencies, and improves maintainability.
This commit is contained in:
@@ -2,41 +2,6 @@ import { AvatarService } from "./avatar.service";
|
||||
import { UpdateUserSchema, createRegisterUserSchema } from "./dto";
|
||||
import { UserService } from "./service";
|
||||
import { FastifyReply, FastifyRequest } from "fastify";
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import { Request, Response } from 'express';
|
||||
import fs from 'fs';
|
||||
|
||||
const uploadsDir = "/app/uploads/avatars";
|
||||
if (!fs.existsSync(uploadsDir)) {
|
||||
fs.mkdirSync(uploadsDir, { recursive: true });
|
||||
}
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: function (req, file, cb) {
|
||||
cb(null, uploadsDir);
|
||||
},
|
||||
filename: function (req, file, cb) {
|
||||
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
||||
const ext = path.extname(file.originalname);
|
||||
cb(null, `${uniqueSuffix}${ext}`);
|
||||
}
|
||||
});
|
||||
|
||||
const fileFilter = (req: any, file: any, cb: any) => {
|
||||
if (!file.mimetype.startsWith('image/')) {
|
||||
return cb(new Error('Only images are allowed'));
|
||||
}
|
||||
cb(null, true);
|
||||
};
|
||||
|
||||
const upload = multer({
|
||||
storage: storage,
|
||||
fileFilter: fileFilter,
|
||||
limits: {
|
||||
fileSize: 5 * 1024 * 1024
|
||||
}
|
||||
}).single('file');
|
||||
|
||||
export class UserController {
|
||||
private userService = new UserService();
|
||||
@@ -125,51 +90,30 @@ export class UserController {
|
||||
}
|
||||
|
||||
async uploadAvatar(request: FastifyRequest, reply: FastifyReply) {
|
||||
if (!request.isMultipart()) {
|
||||
return reply.status(400).send({ error: "Request must be multipart/form-data" });
|
||||
try {
|
||||
const userId = (request as any).user?.userId;
|
||||
if (!userId) {
|
||||
return reply.status(401).send({ error: "Unauthorized" });
|
||||
}
|
||||
|
||||
const file = await request.file();
|
||||
if (!file) {
|
||||
return reply.status(400).send({ error: "No file uploaded" });
|
||||
}
|
||||
|
||||
if (!file.mimetype.startsWith('image/')) {
|
||||
return reply.status(400).send({ error: "Only images are allowed" });
|
||||
}
|
||||
|
||||
const buffer = await file.toBuffer();
|
||||
const base64Image = await this.avatarService.uploadAvatar(buffer);
|
||||
const updatedUser = await this.userService.updateUserImage(userId, base64Image);
|
||||
|
||||
return reply.send(updatedUser);
|
||||
} catch (error: any) {
|
||||
console.error("Upload error:", error);
|
||||
return reply.status(400).send({ error: error.message });
|
||||
}
|
||||
|
||||
const userId = (request as any).user?.userId;
|
||||
if (!userId) {
|
||||
return reply.status(401).send({ error: "Unauthorized" });
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const rawRequest = request.raw;
|
||||
rawRequest.headers = request.headers;
|
||||
|
||||
upload(rawRequest as Request, reply.raw as Response, async (err) => {
|
||||
if (err) {
|
||||
console.error("Upload error:", err);
|
||||
if (err.code === 'LIMIT_FILE_SIZE') {
|
||||
return resolve(reply.status(400).send({ error: "File size cannot be larger than 5MB" }));
|
||||
}
|
||||
return resolve(reply.status(400).send({ error: err.message }));
|
||||
}
|
||||
|
||||
const file = (rawRequest as any).file;
|
||||
if (!file) {
|
||||
return resolve(reply.status(400).send({ error: "No file uploaded" }));
|
||||
}
|
||||
|
||||
try {
|
||||
const imageUrl = await this.avatarService.uploadAvatar(userId, file.path);
|
||||
const updatedUser = await this.userService.updateUserImage(userId, imageUrl);
|
||||
resolve(reply.send(updatedUser));
|
||||
} catch (error: any) {
|
||||
|
||||
try {
|
||||
if (fs.existsSync(file.path)) {
|
||||
await fs.promises.unlink(file.path);
|
||||
}
|
||||
} catch (cleanupError) {
|
||||
console.error("Error cleaning up temp file:", cleanupError);
|
||||
}
|
||||
console.error("Upload error:", error);
|
||||
resolve(reply.status(400).send({ error: error.message }));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async removeAvatar(request: FastifyRequest, reply: FastifyReply) {
|
||||
@@ -179,14 +123,9 @@ export class UserController {
|
||||
return reply.status(401).send({ error: "Unauthorized" });
|
||||
}
|
||||
|
||||
const user = await this.userService.getUserById(userId);
|
||||
if (user.image) {
|
||||
await this.avatarService.deleteAvatar(user.image);
|
||||
const updatedUser = await this.userService.updateUserImage(userId, null);
|
||||
return reply.send(updatedUser);
|
||||
}
|
||||
|
||||
return reply.send(user);
|
||||
await this.avatarService.deleteAvatar(userId);
|
||||
const updatedUser = await this.userService.getUserById(userId);
|
||||
return reply.send(updatedUser);
|
||||
} catch (error: any) {
|
||||
return reply.status(400).send({ error: error.message });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user