Files
SkyArtShop/backend/routes/upload.js
Local Server 61929a5daf updateweb
2025-12-14 01:54:40 -06:00

208 lines
5.4 KiB
JavaScript

const express = require("express");
const router = express.Router();
const multer = require("multer");
const path = require("path");
const fs = require("fs").promises;
const { requireAuth } = require("../middleware/auth");
const { pool } = require("../config/database");
// Configure multer for file uploads
const storage = multer.diskStorage({
destination: async function (req, file, cb) {
const uploadDir = path.join(__dirname, "..", "..", "website", "uploads");
try {
await fs.mkdir(uploadDir, { recursive: true });
cb(null, uploadDir);
} catch (error) {
cb(error);
}
},
filename: function (req, file, cb) {
// Generate unique filename
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
const ext = path.extname(file.originalname);
const name = path
.basename(file.originalname, ext)
.replace(/[^a-z0-9]/gi, "-")
.toLowerCase();
cb(null, name + "-" + uniqueSuffix + ext);
},
});
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB limit
},
fileFilter: function (req, file, cb) {
// Accept images only
if (!file.mimetype.startsWith("image/")) {
return cb(new Error("Only image files are allowed!"), false);
}
cb(null, true);
},
});
// Upload multiple files
router.post(
"/upload",
requireAuth,
upload.array("files", 10),
async (req, res) => {
try {
const uploadedBy = req.session.user?.id || null;
const files = [];
// Insert each file into database
for (const file of req.files) {
const result = await pool.query(
`INSERT INTO uploads
(filename, original_name, file_path, file_size, mime_type, uploaded_by, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
RETURNING id, filename, original_name, file_path, file_size, mime_type, created_at`,
[
file.filename,
file.originalname,
`/uploads/${file.filename}`,
file.size,
file.mimetype,
uploadedBy,
]
);
files.push({
id: result.rows[0].id,
filename: result.rows[0].filename,
originalName: result.rows[0].original_name,
size: result.rows[0].file_size,
mimetype: result.rows[0].mime_type,
path: result.rows[0].file_path,
uploadDate: result.rows[0].created_at,
});
}
res.json({
success: true,
message: `${files.length} file(s) uploaded successfully`,
files: files,
});
} catch (error) {
console.error("Upload error:", error);
// If database insert fails, clean up uploaded files
if (req.files) {
for (const file of req.files) {
try {
await fs.unlink(file.path);
} catch (unlinkError) {
console.error("Error cleaning up file:", unlinkError);
}
}
}
res.status(500).json({
success: false,
error: error.message,
});
}
}
);
// Get all uploaded files
router.get("/uploads", requireAuth, async (req, res) => {
try {
// Query files from database
const result = await pool.query(
`SELECT
id,
filename,
original_name,
file_path,
file_size,
mime_type,
uploaded_by,
created_at,
updated_at,
used_in_type,
used_in_id
FROM uploads
ORDER BY created_at DESC`
);
const files = result.rows.map((row) => ({
id: row.id,
filename: row.filename,
originalName: row.original_name,
size: row.file_size,
mimetype: row.mime_type,
path: row.file_path,
uploadDate: row.created_at,
uploadedBy: row.uploaded_by,
usedInType: row.used_in_type,
usedInId: row.used_in_id,
}));
res.json({
success: true,
files: files,
});
} catch (error) {
console.error("Error listing files:", error);
res.status(500).json({
success: false,
error: error.message,
});
}
});
// Delete a file
router.delete("/uploads/:filename", requireAuth, async (req, res) => {
try {
const filename = req.params.filename;
const uploadDir = path.join(__dirname, "..", "..", "website", "uploads");
const filePath = path.join(uploadDir, filename);
// Security check: ensure file is within uploads directory
if (!filePath.startsWith(uploadDir)) {
return res.status(403).json({
success: false,
error: "Invalid file path",
});
}
// Start transaction: delete from database first
const result = await pool.query(
"DELETE FROM uploads WHERE filename = $1 RETURNING id",
[filename]
);
if (result.rowCount === 0) {
return res.status(404).json({
success: false,
error: "File not found in database",
});
}
// Then delete physical file
try {
await fs.unlink(filePath);
} catch (fileError) {
console.warn("File already deleted from disk:", filename);
// Continue anyway since database record is deleted
}
res.json({
success: true,
message: "File deleted successfully",
});
} catch (error) {
console.error("Error deleting file:", error);
res.status(500).json({
success: false,
error: error.message,
});
}
});
module.exports = router;