Skip to content

Commit

Permalink
Fix/firebase api (#202)
Browse files Browse the repository at this point in the history
  • Loading branch information
LuongDangDoanh authored Jul 5, 2024
1 parent 8a5082d commit 5b4d534
Show file tree
Hide file tree
Showing 11 changed files with 1,552 additions and 161 deletions.
1 change: 1 addition & 0 deletions imageUpload/firebase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dung xoa cai nay!!!!
1,336 changes: 1,315 additions & 21 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"express": "^4.19.2",
"express-rate-limit": "^7.3.1",
"express-validator": "^7.1.0",
"firebase-admin": "^12.2.0",
"http-status-codes": "^2.3.0",
"husky": "^9.0.11",
"jsonwebtoken": "^9.0.2",
Expand Down Expand Up @@ -68,6 +69,7 @@
"@types/passport-facebook": "^3.0.3",
"@types/passport-google-oauth20": "^2.0.16",
"@types/request": "^2.48.12",
"@types/uuid": "^10.0.0",
"@types/validator": "^13.12.0",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.14.1",
Expand Down
22 changes: 22 additions & 0 deletions src/config/firebase.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as firebaseAdmin from "firebase-admin";
const a = {
type: process.env.TYPE,
project_id: process.env.PROJECT_ID,
private_key_id: process.env.PRIVATE_KEY_ID,
private_key: process.env.PRIVATE_KEY,
client_email: process.env.CLIENT_EMAIL,
client_id: process.env.CLIENT_IDFB,
auth_uri: process.env.AUTH_URI,
token_uri: process.env.TOKEN_URI,
auth_provider_x509_cert_url: process.env.AUTH_PROVIDER_X509_CERT_URL,
client_x509_cert_url: process.env.CLIENT_X509_CERT_URL,
universe_domain: process.env.UNIVERSE_DOMAIN,
};

const admin = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(
a as firebaseAdmin.ServiceAccount,
),
});

export const storageRef = admin.storage().bucket(process.env.BUCKET);
129 changes: 90 additions & 39 deletions src/modules/user/user.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,22 @@ import { OTP_MESSAGES } from "../otp/otp.messages";
import { UserRole } from "./user.enum";
import { USER_MESSAGES } from "./user.messages";
import {

BlockBody,

ListAccountQuery,

LoginRequestBody,
LogoutReqBody,
RefreshTokenReqBody,
RegisterReqBody,
TokenPayload,
UpdateMeReqBody,
UserResponseAfterCheckEmailOrPhone
} from './user.requests'
import User from './user.schema'
import usersService from './user.services'
import adminService from "../admin/admin.services";
import { UserList } from "~/constants/user.type";
import { UserRole } from "./user.enum";


UserResponseAfterCheckEmailOrPhone,
} from "./user.requests";
import User from "./user.schema";
import usersService from "./user.services";
import { v4 as uuidv4 } from "uuid";
import path from "path";
import { storageRef } from "~/config/firebase.config";
import fs from "fs";

export const registerController = async (
req: Request<ParamsDictionary, any, RegisterReqBody>,
Expand Down Expand Up @@ -264,55 +260,54 @@ export const refreshTokenController = async (
return res.json({
message: USER_MESSAGES.REFRESH_TOKEN_SUCCESSFULLY,

data: { access_token }
})
}
data: { access_token },
});
};

export const blockAccountController = async (
req: Request<ParamsDictionary, any, BlockBody>,
res: Response
res: Response,
) => {
console.log(req.cookies['refresh_token'])
await usersService.logout(req.cookies['refresh_token'])
res.clearCookie('refresh_token')
console.log(req.cookies["refresh_token"]);
await usersService.logout(req.cookies["refresh_token"]);
res.clearCookie("refresh_token");
try {
const reason = req.body.description_reason
const picture_image_prove = req.body.picture_image_prove
const timeBlock = new Date()
const user_id = req.body._id
const reason = req.body.description_reason;
const picture_image_prove = req.body.picture_image_prove;
const timeBlock = new Date();
const user_id = req.body._id;
await usersService.blockAccount(
user_id,
reason,
picture_image_prove,
timeBlock
)
timeBlock,
);
return res.json({
message: USER_MESSAGES.USER_HAS_BEEN_BLOCKED
})
message: USER_MESSAGES.USER_HAS_BEEN_BLOCKED,
});
} catch (error) {
return res.status(400).json({
message: 'Bad request'
})
message: "Bad request",
});
}
}
};

export const unblockAccountController = async (
req: Request<ParamsDictionary, any, BlockBody>,
res: Response
res: Response,
) => {
try {
const user_id = req.body._id
await usersService.unblockAccount(user_id)
const user_id = req.body._id;
await usersService.unblockAccount(user_id);
return res.json({
message: USER_MESSAGES.USER_UNBLOCK_SUCCESSFULLY
})
message: USER_MESSAGES.USER_UNBLOCK_SUCCESSFULLY,
});
} catch (error) {
return res.status(400).json({
message: 'Bad request'
})
message: "Bad request",
});
}
}

};

export const getListUserController = async (req: Request, res: Response) => {
const query = req.queryListAccount as ListAccountQuery;
Expand Down Expand Up @@ -400,4 +395,60 @@ export const getListUserController = async (req: Request, res: Response) => {
});
}
};
async function downloadAndUploadImage(
imageUrl: string,
filename: string,
): Promise<string> {
const response = await fetch(imageUrl);
if (!response.ok) {
throw new Error(`Failed to download image from ${imageUrl}`);
}
const buffer = await response.arrayBuffer();
const tempFilePath = path.resolve("imageUpload") + `\\${filename}.jpeg`;
// //checkTypeLink
// const fileType = await fileTypeFromBuffer(buffer)
// if (!fileType || !fileType.mime.startsWith('image/')) {
// await fs.promises.unlink(tempFilePath)
// throw new Error(`File ${tempFilePath} is not an image!!!`)
// }
await fs.promises.writeFile(tempFilePath, Buffer.from(buffer));
try {
const url = await uploadFile(tempFilePath, filename);
return url;
} catch (err) {
throw new Error(USER_MESSAGES.CANT_UPLOAD_IMG);
} finally {
await fs.promises.unlink(tempFilePath);
}
}

export const getLinkPicture = async (
req: Request<ParamsDictionary, any, UpdateMeReqBody>,
res: Response,
) => {
const imageUrl = req.body.avatar_url;
const user_Id = (req.body as User)._id;
if (!imageUrl) {
return res.json({
message: USER_MESSAGES.CANT_FIND_THIS_IMAGE,
});
}
const url = await downloadAndUploadImage(imageUrl, `${user_Id}`);
console.log(url);
return res.status(200).json({
message: USER_MESSAGES.UPLOAD_PICTURE_SUCCESSFULLY,
details: url,
});
};
async function uploadFile(path: string, filename: string): Promise<string> {
// Upload the File
const storage = await storageRef.upload(path, {
public: true,
destination: `/uploads/${filename}`,
metadata: {
contentType: "image/jpeg",
firebaseStorageDownloadTokens: uuidv4(),
},
});
return storage[0].metadata.mediaLink ?? "";
}
14 changes: 9 additions & 5 deletions src/modules/user/user.messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,17 @@ export const USER_MESSAGES = {

//token

REFRESH_TOKEN_IS_REQUIRED: 'Refresh token is required',
OTP_IS_INCORRECT: 'OTP is incorrect',
REFRESH_TOKEN_IS_REQUIRED: "Refresh token is required",
OTP_IS_INCORRECT: "OTP is incorrect",
// block
USER_HAS_BEEN_BLOCKED: 'user has been blocked',
USER_UNBLOCK_SUCCESSFULLY: 'user unblock successfully'
USER_HAS_BEEN_BLOCKED: "user has been blocked",
USER_UNBLOCK_SUCCESSFULLY: "user unblock successfully",

//don't have permission
DONT_HAVE_PERMISSION: `You don't have permission`,
} as const;

//Upload picture
CANT_UPLOAD_IMG: "Cannot upload image",
CANT_FIND_THIS_IMAGE: "Cannot find this image",
UPLOAD_PICTURE_SUCCESSFULLY: "Upload picture successfully",
} as const;
21 changes: 17 additions & 4 deletions src/modules/user/user.middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@ import { isValidPhoneNumberForCountry, validate } from "~/utils/validation";
import { OTP_STATUS } from "../otp/otp.enum";
import { OTP_MESSAGES } from "../otp/otp.messages";
import otpService from "../otp/otp.services";
import {
NoticeUser,
Subscription,
UserVerifyStatus,
UserRole,
} from "./user.enum";
import { PROTECT_MESSAGES } from "../protectRouting/protect.messages";
import { checkRole, routesConfig } from "../protectRouting/protect.utils";
import { NoticeUser, UserRole, UserVerifyStatus } from "./user.enum";
import { LoginRequestBody, TokenPayload } from "./user.requests";
import usersService from "./user.services";
//! Prevent db injection, XSS attack
Expand Down Expand Up @@ -289,9 +294,8 @@ export const loginValidator = validate(

if (
user.notice === NoticeUser.Banned ||
user.reasonBanned !== '' ||
user.reasonBanned !== "" ||
user.block === Subscription.True

) {
throw new ErrorWithStatus({
message: USER_MESSAGES.ACCOUNT_IS_BANNED,
Expand Down Expand Up @@ -376,7 +380,7 @@ export const loginValidator = validate(

if (
user.notice === NoticeUser.Banned ||
user.reasonBanned !== '' ||
user.reasonBanned !== "" ||
user.block === Subscription.True
) {
throw new ErrorWithStatus({
Expand Down Expand Up @@ -1302,3 +1306,12 @@ export const pagination = async (
next();
}
};

export const getLinkImg = validate(
checkSchema(
{
avatar_url: imageSchema,
},
["body"],
),
);
14 changes: 7 additions & 7 deletions src/modules/user/user.requests.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ObjectId } from 'mongodb'
import { ObjectId } from "mongodb";
import { JwtPayload } from "jsonwebtoken";
import {
Subscription,
Expand Down Expand Up @@ -80,13 +80,13 @@ export type LogoutReqBody = {
};

export type RefreshTokenReqBody = {
refresh_token: string
}
refresh_token: string;
};
export interface BlockBody {
_id: ObjectId
description_reason?: string
picture_image_prove?: string
refresh_token: string
_id: ObjectId;
description_reason?: string;
picture_image_prove?: string;
refresh_token: string;
}

export type ListAccountQuery = {
Expand Down
16 changes: 10 additions & 6 deletions src/modules/user/user.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
blockAccountController,
changePasswordController,
forgotPasswordController,
getLinkPicture,
getListUserController,
getMeController,
loginController,
Expand All @@ -28,6 +29,7 @@ import {
checkNewPasswordValidator,
checkVerifyAccount,
forgotPasswordValidator,
getLinkImg,
isUserRole,
loginValidator,
pagination,
Expand Down Expand Up @@ -235,17 +237,17 @@ usersRouter.post(
usersRouter.post(
"/refresh-token",
refreshTokenCookieValidator,
wrapAsync(refreshTokenController)
)
wrapAsync(refreshTokenController),
);

usersRouter.post(
'/block',
"/block",
accessTokenValidator,
refreshTokenCookieValidator,
wrapAsync(blockAccountController)
)
wrapAsync(blockAccountController),
);

usersRouter.post('/unblock', wrapAsync(unblockAccountController))
usersRouter.post("/unblock", wrapAsync(unblockAccountController));

usersRouter.get(
"/list-account",
Expand All @@ -255,4 +257,6 @@ usersRouter.get(
wrapAsync(getListUserController),
);

usersRouter.post("/getLinkPic", getLinkImg, wrapAsync(getLinkPicture));

export default usersRouter;
Loading

0 comments on commit 5b4d534

Please sign in to comment.