add:utils:file:store | create utility for store file in system
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -55,3 +55,6 @@ server.exe
|
|||||||
# debug and cached routes
|
# debug and cached routes
|
||||||
/src/routes.ts
|
/src/routes.ts
|
||||||
/src/modules/debug
|
/src/modules/debug
|
||||||
|
|
||||||
|
# uploaded files
|
||||||
|
/uploads
|
||||||
@ -13,6 +13,7 @@
|
|||||||
"@prisma/client": "^6.7.0",
|
"@prisma/client": "^6.7.0",
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
"@types/jsonwebtoken": "^9.0.9",
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
|
"@types/mime-types": "^3.0.1",
|
||||||
"aws-sdk": "^2.1692.0",
|
"aws-sdk": "^2.1692.0",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"cookie": "^1.0.2",
|
"cookie": "^1.0.2",
|
||||||
@ -20,6 +21,7 @@
|
|||||||
"ioredis": "^5.6.1",
|
"ioredis": "^5.6.1",
|
||||||
"joi": "^17.13.3",
|
"joi": "^17.13.3",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"mime-types": "^3.0.1",
|
||||||
"mock-aws-s3": "^4.0.2",
|
"mock-aws-s3": "^4.0.2",
|
||||||
"nock": "^14.0.4",
|
"nock": "^14.0.4",
|
||||||
"ua-parser-js": "^2.0.3"
|
"ua-parser-js": "^2.0.3"
|
||||||
|
|||||||
0
src/constants/file
Normal file
0
src/constants/file
Normal file
26
src/helpers/files/saveFile/index.ts
Normal file
26
src/helpers/files/saveFile/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { mkdir, writeFile } from "fs/promises";
|
||||||
|
import path from "path";
|
||||||
|
import crypto from "crypto";
|
||||||
|
import mime from "mime-types";
|
||||||
|
|
||||||
|
interface SaveFileOptions {
|
||||||
|
folder: string;
|
||||||
|
prefix?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const saveFile = async (
|
||||||
|
file: File,
|
||||||
|
{ folder, prefix }: SaveFileOptions
|
||||||
|
): Promise<string> => {
|
||||||
|
const ext = mime.extension(file.type) || "bin";
|
||||||
|
const uniqueName = `${prefix ?? ""}${crypto.randomUUID()}.${ext}`;
|
||||||
|
|
||||||
|
const relativeFolder = path.join("uploads", folder);
|
||||||
|
const relativePath = path.join(relativeFolder, uniqueName);
|
||||||
|
const absolutePath = path.join(process.cwd(), relativePath);
|
||||||
|
|
||||||
|
await mkdir(path.dirname(absolutePath), { recursive: true });
|
||||||
|
await writeFile(absolutePath, Buffer.from(await file.arrayBuffer()));
|
||||||
|
|
||||||
|
return relativePath;
|
||||||
|
};
|
||||||
17
src/helpers/files/saveFile/modules/saveAvatar.ts
Normal file
17
src/helpers/files/saveFile/modules/saveAvatar.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { saveFile } from "..";
|
||||||
|
import { AppError } from "../../../error/instances/app";
|
||||||
|
|
||||||
|
export const saveAvatar = async (file: File): Promise<string> => {
|
||||||
|
const allowedTypes = ["image/png", "image/jpeg", "image/webp"];
|
||||||
|
if (!allowedTypes.includes(file.type)) {
|
||||||
|
throw new AppError(
|
||||||
|
415,
|
||||||
|
"Unsupported Media Type. File must be in .jpg, .png, or .webp format"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await saveFile(file, {
|
||||||
|
folder: "avatar",
|
||||||
|
prefix: "usr-",
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -7,6 +7,7 @@ import { checkUserEmailAndUsernameAvailabillityService } from "./checkUserEmailA
|
|||||||
import { logoutService } from "../../auth/services/logout.service";
|
import { logoutService } from "../../auth/services/logout.service";
|
||||||
import { loginFromSystemService } from "../../auth/services/loginFromSystem.service";
|
import { loginFromSystemService } from "../../auth/services/loginFromSystem.service";
|
||||||
import { UserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation/types";
|
import { UserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation/types";
|
||||||
|
import { saveAvatar } from "../../../helpers/files/saveFile/modules/saveAvatar";
|
||||||
|
|
||||||
export const editUserService = async (
|
export const editUserService = async (
|
||||||
cookie: string,
|
cookie: string,
|
||||||
@ -29,6 +30,11 @@ export const editUserService = async (
|
|||||||
"The username or email has already taken by another user."
|
"The username or email has already taken by another user."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Store the avatar to the file system if provided in the payload
|
||||||
|
let storeAvatar: string | undefined = undefined;
|
||||||
|
if (payload.profilePicture)
|
||||||
|
storeAvatar = await saveAvatar(payload.profilePicture as File);
|
||||||
|
|
||||||
// Prepare the fields to update, only include fields that are provided in the payload
|
// Prepare the fields to update, only include fields that are provided in the payload
|
||||||
const fieldsToUpdate: Partial<Prisma.UserUpdateInput> = {
|
const fieldsToUpdate: Partial<Prisma.UserUpdateInput> = {
|
||||||
...(payload.username && payload.username !== jwtSession.user.username
|
...(payload.username && payload.username !== jwtSession.user.username
|
||||||
@ -47,9 +53,7 @@ export const editUserService = async (
|
|||||||
...(payload.bioProfile !== undefined
|
...(payload.bioProfile !== undefined
|
||||||
? { bioProfile: payload.bioProfile }
|
? { bioProfile: payload.bioProfile }
|
||||||
: {}),
|
: {}),
|
||||||
...(payload.profilePicture !== undefined
|
...(storeAvatar !== undefined ? { profilePicture: storeAvatar } : {}),
|
||||||
? { profilePicture: payload.profilePicture }
|
|
||||||
: {}),
|
|
||||||
...(payload.commentPicture !== undefined
|
...(payload.commentPicture !== undefined
|
||||||
? { commentPicture: payload.commentPicture }
|
? { commentPicture: payload.commentPicture }
|
||||||
: {}),
|
: {}),
|
||||||
@ -61,6 +65,7 @@ export const editUserService = async (
|
|||||||
// Update the user in the database, use username from the JWT session to find the user
|
// Update the user in the database, use username from the JWT session to find the user
|
||||||
await updateUserRepo(jwtSession.user.username, fieldsToUpdate);
|
await updateUserRepo(jwtSession.user.username, fieldsToUpdate);
|
||||||
|
|
||||||
|
// Clear the session and re-login the user to get a new JWT token
|
||||||
await logoutService(cookie);
|
await logoutService(cookie);
|
||||||
const newUserSession = await loginFromSystemService(
|
const newUserSession = await loginFromSystemService(
|
||||||
jwtSession.userId,
|
jwtSession.userId,
|
||||||
|
|||||||
Reference in New Issue
Block a user