Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
|
89ff6d27d4 |
|
@ -19,4 +19,11 @@ ACCESS_TOKEN_EXPIRY=
|
||||||
|
|
||||||
SUPABASE_URL=
|
SUPABASE_URL=
|
||||||
SUPABASE_KEY=
|
SUPABASE_KEY=
|
||||||
DATABASE_URL=
|
DATABASE_URL=
|
||||||
|
|
||||||
|
# aws s3 creds
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_REGION=
|
||||||
|
AWS_S3_BUCKET=
|
1887
package-lock.json
generated
1887
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -13,18 +13,22 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.832.0",
|
||||||
|
"@aws-sdk/s3-request-presigner": "^3.832.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"joi": "^17.13.3",
|
"joi": "^17.13.3",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"multer": "^2.0.1",
|
||||||
"pg": "^8.16.0",
|
"pg": "^8.16.0",
|
||||||
"pg-hstore": "^2.3.4",
|
"pg-hstore": "^2.3.4",
|
||||||
"postgres": "^3.4.7",
|
"postgres": "^3.4.7",
|
||||||
"sequelize": "^6.37.7",
|
"sequelize": "^6.37.7",
|
||||||
"swagger-jsdoc": "^6.2.8",
|
"swagger-jsdoc": "^6.2.8",
|
||||||
"swagger-ui-express": "^5.0.1",
|
"swagger-ui-express": "^5.0.1",
|
||||||
"twilio": "^5.7.1"
|
"twilio": "^5.7.1",
|
||||||
|
"uuid": "^11.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^3.1.10"
|
"nodemon": "^3.1.10"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import User from '../models/user.js';
|
import User from '../models/user.js';
|
||||||
|
import { uploadFile, getSignedFileUrl } from "../service/s3.service.js";
|
||||||
|
|
||||||
// UPDATE USER
|
// UPDATE USER
|
||||||
const updateUser = async (req, res) => {
|
const updateUser = async (req, res) => {
|
||||||
|
@ -47,9 +48,48 @@ const deleteUser = async (req, res) => {
|
||||||
res.json({ message: 'User deleted' });
|
res.json({ message: 'User deleted' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload file to S3 and return fileKey
|
||||||
|
*/
|
||||||
|
const uploadS3File = async (req, res) => {
|
||||||
|
try {
|
||||||
|
console.log("Received file:", req.file?.originalname);
|
||||||
|
|
||||||
|
if (!req.file) {
|
||||||
|
return res.status(400).json({ error: "No file provided" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileKey = await uploadFile(req.file);
|
||||||
|
res.json({ message: "File uploaded successfully", fileKey });
|
||||||
|
} catch (err) {
|
||||||
|
console.error("S3 upload error:", err);
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a signed URL for S3 file
|
||||||
|
*/
|
||||||
|
const getS3SignedUrl = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { key } = req.params;
|
||||||
|
if (!key) {
|
||||||
|
return res.status(400).json({ error: "File key is required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = await getSignedFileUrl(key);
|
||||||
|
res.json({ url });
|
||||||
|
} catch (err) {
|
||||||
|
console.error("S3 signed URL error:", err);
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
updateUser,
|
updateUser,
|
||||||
getAllUsers,
|
getAllUsers,
|
||||||
getUserById,
|
getUserById,
|
||||||
deleteUser,
|
deleteUser,
|
||||||
|
uploadS3File,
|
||||||
|
getS3SignedUrl
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,8 @@ import userController from "../controllers/user.controller.js";
|
||||||
import validate from "../middleware/validate.js";
|
import validate from "../middleware/validate.js";
|
||||||
import { updateUserSchema } from "../validators/user.validator.js";
|
import { updateUserSchema } from "../validators/user.validator.js";
|
||||||
import verifyToken from "../middleware/authenticate.js";
|
import verifyToken from "../middleware/authenticate.js";
|
||||||
|
import multer from "multer";
|
||||||
|
const upload = multer(); // memory storage
|
||||||
|
|
||||||
router.put(
|
router.put(
|
||||||
"/update-user",
|
"/update-user",
|
||||||
|
@ -13,5 +14,12 @@ router.put(
|
||||||
userController.updateUser
|
userController.updateUser
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.post("/upload", upload.single("file"), userController.uploadS3File);
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/get-upload/:key",
|
||||||
|
userController.getS3SignedUrl
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
40
src/service/s3.service.js
Normal file
40
src/service/s3.service.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
|
||||||
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import s3Client from "../utils/s3Client.js";
|
||||||
|
|
||||||
|
const bucketName = process.env.AWS_S3_BUCKET;
|
||||||
|
|
||||||
|
export const uploadFile = async (file) => {
|
||||||
|
if (!file || !file.buffer) {
|
||||||
|
throw new Error("Invalid file data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileKey = `${uuidv4()}-${file.originalname}`;
|
||||||
|
|
||||||
|
const command = new PutObjectCommand({
|
||||||
|
Bucket: bucketName,
|
||||||
|
Key: fileKey,
|
||||||
|
Body: file.buffer,
|
||||||
|
ContentType: file.mimetype,
|
||||||
|
});
|
||||||
|
|
||||||
|
await s3Client.send(command);
|
||||||
|
|
||||||
|
return fileKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSignedFileUrl = async (fileKey, expiresIn = 3600) => {
|
||||||
|
if (!fileKey) {
|
||||||
|
throw new Error("File key is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = new GetObjectCommand({
|
||||||
|
Bucket: bucketName,
|
||||||
|
Key: fileKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
const signedUrl = await getSignedUrl(s3Client, command, { expiresIn });
|
||||||
|
|
||||||
|
return signedUrl;
|
||||||
|
};
|
11
src/utils/s3Client.js
Normal file
11
src/utils/s3Client.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { S3Client } from "@aws-sdk/client-s3";
|
||||||
|
|
||||||
|
const s3Client = new S3Client({
|
||||||
|
region: process.env.AWS_REGION,
|
||||||
|
credentials: {
|
||||||
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
||||||
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default s3Client;
|
Loading…
Reference in a new issue