🏗️ reconstruct all system in user module
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import bcrypt from "bcrypt";
|
||||
import { findUserByEmailOrUsernameService } from "../../user/services/findUserByEmailOrUsername.service";
|
||||
import { findUserByEmailOrUsernameService } from "../../user/services/getUserData.service";
|
||||
import { LoginWithPasswordRequest } from "../auth.types";
|
||||
import { AppError } from "../../../helpers/error/instances/app";
|
||||
import { UserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation/types";
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
import { Context } from "elysia";
|
||||
import { checkUserPasswordService } from "../services/checkUserPassword.service";
|
||||
import { jwtDecode } from "../../../helpers/http/jwt/decode";
|
||||
import { getCookie } from "../../../helpers/http/userHeader/cookies/getCookies";
|
||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
||||
|
||||
export const checkUserPasswordController = async (
|
||||
ctx: Context & { body: { password: string } }
|
||||
) => {
|
||||
try {
|
||||
// Get the credentials information from cookies
|
||||
const cookie = getCookie(ctx);
|
||||
const jwtPayload = jwtDecode(cookie.auth_token!);
|
||||
|
||||
// Execute the check user password service
|
||||
const checkUserPassword = await checkUserPasswordService(
|
||||
jwtPayload.user.username,
|
||||
ctx.body.password
|
||||
);
|
||||
|
||||
// If the password is valid, return a success response
|
||||
return returnWriteResponse(
|
||||
ctx.set,
|
||||
204,
|
||||
"Password is valid",
|
||||
checkUserPassword
|
||||
);
|
||||
} catch (error) {
|
||||
return mainErrorHandler(ctx.set, error);
|
||||
}
|
||||
};
|
||||
@ -1,50 +0,0 @@
|
||||
import {
|
||||
returnErrorResponse,
|
||||
returnWriteResponse,
|
||||
} from "../../../helpers/callback/httpResponse";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { Context } from "elysia";
|
||||
import { createUserService } from "../services/createUser.service";
|
||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||
import { createUserSchema } from "../schemas/createUser.schema";
|
||||
|
||||
/**
|
||||
* @function createUser
|
||||
* @description Creates a new user in the database.
|
||||
*
|
||||
* @param {Context & { body: Prisma.UserCreateInput }} ctx - The context object containing the request body.
|
||||
* @param {Prisma.UserCreateInput} ctx.body - The user data to be created.
|
||||
*
|
||||
* @returns {Promise<Object>} A response object indicating success or failure.
|
||||
* @throws {Object} An error response object if validation fails or an error occurs during user creation.
|
||||
*
|
||||
* @example
|
||||
* Request route: POST /users
|
||||
* Request body:
|
||||
* {
|
||||
* "username": "john_doe",
|
||||
* "email": "john@example.com",
|
||||
* "password": "password123"
|
||||
* }
|
||||
*/
|
||||
export const createUserController = async (
|
||||
ctx: Context & { body: Prisma.UserCreateInput }
|
||||
) => {
|
||||
// Validate the user input using a validation schema
|
||||
const { error } = createUserSchema.validate(ctx.body);
|
||||
if (error)
|
||||
return returnErrorResponse(ctx.set, 400, "Invalid user input", error);
|
||||
|
||||
// Create the user in the database using the service
|
||||
try {
|
||||
const newUser = await createUserService(ctx.body);
|
||||
return returnWriteResponse(
|
||||
ctx.set,
|
||||
201,
|
||||
"User created successfully",
|
||||
newUser
|
||||
);
|
||||
} catch (error) {
|
||||
return mainErrorHandler(ctx.set, error);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,21 @@
|
||||
import { Context } from "elysia";
|
||||
import { createUserSchema } from "../schemas/createUser.schema";
|
||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||
import { createUserViaRegisterService } from "../services/createUserViaRegister.service";
|
||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
||||
|
||||
export const createUserViaRegisterController = async (ctx: Context) => {
|
||||
try {
|
||||
const validate = createUserSchema.parse(ctx.body);
|
||||
|
||||
const createUser = await createUserViaRegisterService(validate);
|
||||
return returnWriteResponse(
|
||||
ctx.set,
|
||||
201,
|
||||
"User Successfully Created",
|
||||
createUser
|
||||
);
|
||||
} catch (error) {
|
||||
return mainErrorHandler(ctx.set, error);
|
||||
}
|
||||
};
|
||||
@ -1,93 +0,0 @@
|
||||
import { Context } from "elysia";
|
||||
import {
|
||||
returnErrorResponse,
|
||||
returnWriteResponse,
|
||||
} from "../../../helpers/callback/httpResponse";
|
||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { updateUserService } from "../services/updateUser.service";
|
||||
import { getCookie } from "../../../helpers/http/userHeader/cookies/getCookies";
|
||||
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
|
||||
import { setCookie } from "../../../helpers/http/userHeader/cookies/setCookies";
|
||||
import { COOKIE_KEYS } from "../../../constants/cookie.keys";
|
||||
import { jwtEncode } from "../../../helpers/http/jwt/encode";
|
||||
import { editUserSchema } from "../schemas/editUser.schema";
|
||||
|
||||
/**
|
||||
* @function editUserController
|
||||
* @description Updates user profile information. Requires valid JWT authentication token in cookies.
|
||||
* On success, returns updated user data and sets a new JWT token in cookies.
|
||||
* In development environment, the new JWT token is also returned in the response.
|
||||
*
|
||||
* @param {Context & { body: Prisma.UserUncheckedCreateInput }} ctx - The context object containing request information.
|
||||
* @param {Object} ctx.body - The updated user data.
|
||||
*
|
||||
* @returns {Promise<Object>} A response object indicating success or failure.
|
||||
* @throws {Object} An error response if authentication fails or validation errors occur.
|
||||
*
|
||||
* @example
|
||||
* Request route: PUT /users
|
||||
* Request headers:
|
||||
* {
|
||||
* "Cookie": "auth_token=<JWT_TOKEN>"
|
||||
* }
|
||||
* Request body:
|
||||
* {
|
||||
* "username": "new_username",
|
||||
* "name": "Updated Name",
|
||||
* "birthDate": "1990-01-01T00:00:00.000Z",
|
||||
* "gender": "male",
|
||||
* "phoneCC": 62,
|
||||
* "phoneNumber": 81234567890,
|
||||
* "bioProfile": "Updated bio",
|
||||
* "profilePicture": JPG/PNG/JPEG File,
|
||||
* "commentPicture": JPG/PNG/JPEG File,
|
||||
* "deletedAt": null
|
||||
* }
|
||||
*
|
||||
* Success Response:
|
||||
* Status: 201 Created
|
||||
* {
|
||||
* "message": "User data updated",
|
||||
* "token": "<NEW_JWT_TOKEN>" // Only in development environment
|
||||
* }
|
||||
*
|
||||
* Failure Responses:
|
||||
* - 401 Unauthorized: Missing or invalid authentication token
|
||||
* - 400 Bad Request: Invalid user data
|
||||
* - 500 Internal Server Error: Database operation failed
|
||||
*/
|
||||
export const editUserController = async (
|
||||
ctx: Context & {
|
||||
body: Prisma.UserUncheckedCreateInput;
|
||||
}
|
||||
) => {
|
||||
// Validate the request body against the edit user schema
|
||||
const { error } = editUserSchema.validate(ctx.body);
|
||||
if (error)
|
||||
return returnErrorResponse(ctx.set, 422, "Invalid form input", error);
|
||||
|
||||
try {
|
||||
// Get the user JWT token from cookies, if the token is not found, return an error response
|
||||
const userCookie = getCookie(ctx);
|
||||
const auth_token = userCookie.auth_token!;
|
||||
|
||||
// Get user browser header information from the context
|
||||
const userHeaderInfo = getUserHeaderInformation(ctx);
|
||||
|
||||
// Excecute the edit user data service
|
||||
const newUserData = await updateUserService(
|
||||
auth_token,
|
||||
userHeaderInfo,
|
||||
ctx.body
|
||||
);
|
||||
|
||||
// create a new JWT token with the updated user data, and set it in the cookies
|
||||
const newJwtToken = await jwtEncode(newUserData);
|
||||
setCookie(ctx.set, COOKIE_KEYS.AUTH, newJwtToken);
|
||||
|
||||
return returnWriteResponse(ctx.set, 201, "User data updated", newJwtToken);
|
||||
} catch (error) {
|
||||
return mainErrorHandler(ctx.set, error);
|
||||
}
|
||||
};
|
||||
@ -1,12 +0,0 @@
|
||||
import { Context } from "elysia";
|
||||
import { findUserByEmailService } from "../services/findUserByEmail.service";
|
||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||
|
||||
export const findUserByEmailController = async (ctx: Context) => {
|
||||
try {
|
||||
const findUserByEmail = await findUserByEmailService(ctx.params.email);
|
||||
return findUserByEmail;
|
||||
} catch (error) {
|
||||
return mainErrorHandler(ctx.set, error);
|
||||
}
|
||||
};
|
||||
@ -1,18 +0,0 @@
|
||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||
import { Context } from "elysia";
|
||||
import { getAllUsersService } from "../services/getAllUser.service";
|
||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||
|
||||
export const getAllUserController = async (ctx: Context) => {
|
||||
try {
|
||||
const allUser = await getAllUsersService();
|
||||
return returnReadResponse(
|
||||
ctx.set,
|
||||
200,
|
||||
"All user ranks successfully",
|
||||
allUser
|
||||
);
|
||||
} catch (error) {
|
||||
return mainErrorHandler(ctx.set, error);
|
||||
}
|
||||
};
|
||||
@ -1,7 +0,0 @@
|
||||
import { Context } from "elysia";
|
||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
||||
|
||||
export const softDeleteUserController = async (ctx: Context) => {
|
||||
const data = ctx.params.username;
|
||||
return returnWriteResponse(ctx.set, 201, "Okay", data);
|
||||
};
|
||||
@ -1,30 +1,7 @@
|
||||
import Elysia from "elysia";
|
||||
import { getAllUserController } from "./controller/getAllUser.controller";
|
||||
import { createUserController } from "./controller/createUser.controller";
|
||||
import { editUserController } from "./controller/editUser.controller";
|
||||
import { unautenticatedMiddleware } from "../../middleware/auth/unauthenticated.middleware";
|
||||
import { authenticatedMiddleware } from "../../middleware/auth/authenticated.middleware";
|
||||
import { checkUserPasswordController } from "./controller/checkUserPassword.controller";
|
||||
import { isOwnerOrAdminMiddleware } from "../../middleware/userRoles/isOwnerOrAdmin.middleware";
|
||||
import { softDeleteUserController } from "./controller/softDeleteUser.controller";
|
||||
import { findUserByEmailController } from "./controller/findUserByEmail.controller";
|
||||
import { createUserViaRegisterController } from "./controller/createUserViaRegister.controller";
|
||||
|
||||
export const userModule = new Elysia({ prefix: "/users" })
|
||||
.get("/", getAllUserController)
|
||||
.get("/e/:email", findUserByEmailController)
|
||||
.group("", (app) =>
|
||||
app
|
||||
.onBeforeHandle(unautenticatedMiddleware) // middleware to ensure the user is not authenticated
|
||||
.post("/", createUserController)
|
||||
)
|
||||
.group("", (app) =>
|
||||
app
|
||||
.onBeforeHandle(authenticatedMiddleware) // middleware to ensure the user is authenticated
|
||||
.put("/", editUserController)
|
||||
.post("/check-password", checkUserPasswordController)
|
||||
)
|
||||
.group("", (app) =>
|
||||
app
|
||||
.onBeforeHandle(isOwnerOrAdminMiddleware)
|
||||
.delete(":username", softDeleteUserController)
|
||||
);
|
||||
export const userModule = new Elysia({ prefix: "/users" }).post(
|
||||
"/",
|
||||
createUserViaRegisterController
|
||||
);
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import { userModel } from "../user.model";
|
||||
|
||||
export const checkUserEmailAndUsernameAvailabillityRepo = async (
|
||||
id: string,
|
||||
username: string,
|
||||
email: string
|
||||
) => {
|
||||
const checkUsernameAndEmailAvailabillity = await userModel.findFirst({
|
||||
where: {
|
||||
OR: [{ username: username ?? undefined }, { email: email ?? undefined }],
|
||||
NOT: {
|
||||
id: id,
|
||||
},
|
||||
},
|
||||
});
|
||||
return checkUsernameAndEmailAvailabillity;
|
||||
};
|
||||
@ -0,0 +1,10 @@
|
||||
import { userModel } from "../../user.model";
|
||||
import { createUserViaRegisterInput } from "../../user.types";
|
||||
|
||||
export const createUserViaRegisterRepository = async (
|
||||
payload: createUserViaRegisterInput
|
||||
) => {
|
||||
return await userModel.create({
|
||||
data: payload,
|
||||
});
|
||||
};
|
||||
@ -1,13 +0,0 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { userModel } from "../user.model";
|
||||
|
||||
export const createUserRepo = async (data: Prisma.UserCreateInput) => {
|
||||
const userData = await userModel.create({
|
||||
data,
|
||||
omit: {
|
||||
password: true,
|
||||
},
|
||||
});
|
||||
|
||||
return userData;
|
||||
};
|
||||
@ -1,28 +0,0 @@
|
||||
import { userModel } from "../user.model";
|
||||
import { FindUserByEmailOrUsernameOptions } from "../user.types";
|
||||
|
||||
export const findUserByEmailOrUsernameRepository = async (
|
||||
identifier: string,
|
||||
options: FindUserByEmailOrUsernameOptions
|
||||
) => {
|
||||
const userData = await userModel.findUnique({
|
||||
where: { email: identifier },
|
||||
include: {
|
||||
assignedRoles: {
|
||||
select: {
|
||||
role: {
|
||||
omit: {
|
||||
createdBy: true,
|
||||
updatedAt: true,
|
||||
createdAt: true,
|
||||
deletedAt: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!userData) return false;
|
||||
return userData;
|
||||
};
|
||||
@ -1,11 +0,0 @@
|
||||
import { userModel } from "../user.model";
|
||||
|
||||
export const getAllUserRepo = async () => {
|
||||
const data = await userModel.findMany({
|
||||
where: {
|
||||
deletedAt: null,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
@ -1,16 +0,0 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { userModel } from "../user.model";
|
||||
|
||||
export const updateUserRepository = async (
|
||||
username: string,
|
||||
payload: Prisma.UserUpdateInput
|
||||
) => {
|
||||
const userData = await userModel.update({
|
||||
where: {
|
||||
username,
|
||||
},
|
||||
data: payload,
|
||||
});
|
||||
|
||||
return userData;
|
||||
};
|
||||
@ -1,19 +1,17 @@
|
||||
import Joi from "joi";
|
||||
import z from "zod";
|
||||
|
||||
export const createUserSchema = Joi.object({
|
||||
name: Joi.string()
|
||||
.min(4)
|
||||
.max(255)
|
||||
.required(),
|
||||
username: Joi.string()
|
||||
.min(4)
|
||||
.max(255)
|
||||
.required(),
|
||||
email: Joi.string()
|
||||
.email()
|
||||
.required(),
|
||||
password: Joi.string()
|
||||
.min(8)
|
||||
.max(255)
|
||||
.required(),
|
||||
export const createUserSchema = z.object({
|
||||
name: z.string(),
|
||||
username: z
|
||||
.string()
|
||||
.min(4) //Total all username character must over 4 character
|
||||
.regex(/^[a-zA-Z0-9_-]+$/), //Prohibiting the use of spaces and symbols other than - and _
|
||||
email: z.email(),
|
||||
password: z
|
||||
.string()
|
||||
.min(8) //Total all password chaacter must over 8 character
|
||||
.regex(/[A-Z]/) //Min has 1 uppercase letter
|
||||
.regex(/[a-z]/) //Min has 1 lowercase letter
|
||||
.regex(/[0-9]/) //Min has 1 number
|
||||
.regex(/[^A-Za-z0-9"]/), //Min has 1 symbol character
|
||||
});
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
import { checkUserEmailAndUsernameAvailabillityRepo } from "../repositories/checkUserEmailAndUsernameAvailabillity.repository";
|
||||
|
||||
export const checkUserEmailAndUsernameAvailabillityService = async (
|
||||
payload: Prisma.UserUpdateInput,
|
||||
idException: string
|
||||
) => {
|
||||
try {
|
||||
const usernameAndEmailAvailabillity =
|
||||
checkUserEmailAndUsernameAvailabillityRepo(
|
||||
idException!,
|
||||
payload.username as string,
|
||||
payload.email as string
|
||||
);
|
||||
return usernameAndEmailAvailabillity;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
@ -1,28 +0,0 @@
|
||||
import { AppError } from "../../../helpers/error/instances/app";
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
import { comparePassword } from "../../../helpers/security/password/compare";
|
||||
import { findUserByEmailOrUsernameService } from "./findUserByEmailOrUsername.service";
|
||||
import { User } from "@prisma/client";
|
||||
|
||||
export const checkUserPasswordService = async (
|
||||
username: string,
|
||||
password: string
|
||||
) => {
|
||||
try {
|
||||
// find user by username and get the password
|
||||
const userData = (await findUserByEmailOrUsernameService(username, {
|
||||
verbose: true,
|
||||
})) as User;
|
||||
const StoredPassword = userData.password;
|
||||
|
||||
// compare the provided password with the stored password
|
||||
const matchingPassword = await comparePassword(password, StoredPassword);
|
||||
if (!matchingPassword) {
|
||||
throw new AppError(401, "Invalid Credential");
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
@ -1,19 +0,0 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { hashPassword } from "../../../helpers/security/password/hash";
|
||||
import { createUserRepo } from "../repositories/createUser.repository";
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
|
||||
export const createUserService = async (userData: Prisma.UserCreateInput) => {
|
||||
try {
|
||||
const { password, ...rest } = userData; // Destructure the password and the rest of the user data
|
||||
const hashedPassword = await hashPassword(password); // Hash the password before saving to the database
|
||||
|
||||
const newUser = await createUserRepo({
|
||||
...rest,
|
||||
password: hashedPassword,
|
||||
});
|
||||
return newUser;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error, 500, "Internal server error");
|
||||
}
|
||||
};
|
||||
19
src/modules/user/services/createUserViaRegister.service.ts
Normal file
19
src/modules/user/services/createUserViaRegister.service.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
import { hashPassword } from "../../../helpers/security/password/hash";
|
||||
import { createUserViaRegisterRepository } from "../repositories/create/createUserViaRegister.repository";
|
||||
import { createUserViaRegisterInput } from "../user.types";
|
||||
|
||||
export const createUserViaRegisterService = async (
|
||||
payload: createUserViaRegisterInput
|
||||
) => {
|
||||
try {
|
||||
const hashedPassword = await hashPassword(payload.password);
|
||||
|
||||
return createUserViaRegisterRepository({
|
||||
...payload,
|
||||
password: hashedPassword,
|
||||
});
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
@ -1,13 +0,0 @@
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
import { findUserByEmailOrUsernameRepository } from "../repositories/findUserByEmailOrUsername.repository";
|
||||
|
||||
export const findUserByEmailService = async (email: string) => {
|
||||
try {
|
||||
const findUserByEmail = findUserByEmailOrUsernameRepository(email, {
|
||||
queryTarget: "email",
|
||||
});
|
||||
return findUserByEmail;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
@ -1,21 +0,0 @@
|
||||
import { AppError } from "../../../helpers/error/instances/app";
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
import { findUserByEmailOrUsernameRepository } from "../repositories/findUserByEmailOrUsername.repository";
|
||||
import { FindUserByEmailOrUsernameOptions } from "../user.types";
|
||||
|
||||
export const findUserByEmailOrUsernameService = async (
|
||||
identifier: string,
|
||||
options: FindUserByEmailOrUsernameOptions
|
||||
) => {
|
||||
try {
|
||||
const userData = await findUserByEmailOrUsernameRepository(
|
||||
identifier,
|
||||
options
|
||||
);
|
||||
if (!userData) throw new AppError(404, "User not found");
|
||||
|
||||
return userData;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
@ -1,11 +0,0 @@
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
import { getAllUserRepo } from "../repositories/getAllUser.repository";
|
||||
|
||||
export const getAllUsersService = async () => {
|
||||
try {
|
||||
const allUser = await getAllUserRepo();
|
||||
return allUser;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
@ -1,85 +0,0 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { jwtDecode } from "../../../helpers/http/jwt/decode";
|
||||
import { AppError } from "../../../helpers/error/instances/app";
|
||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||
import { updateUserRepository } from "../repositories/updateUser.repository";
|
||||
import { checkUserEmailAndUsernameAvailabillityService } from "./checkUserEmailAndUsernameAvailabillity.service";
|
||||
import { logoutService } from "../../auth/services/logout.service";
|
||||
import { loginFromSystemService } from "../../auth/services/loginFromSystem.service";
|
||||
import { UserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation/types";
|
||||
import { saveAvatar } from "../../../helpers/files/saveFile/modules/saveAvatar";
|
||||
import { saveCommentBackground } from "../../../helpers/files/saveFile/modules/saveCommentBackgorund";
|
||||
|
||||
export const updateUserService = async (
|
||||
cookie: string,
|
||||
userHeaderInfo: UserHeaderInformation,
|
||||
payload: Prisma.UserUpdateInput
|
||||
) => {
|
||||
try {
|
||||
// Decode the JWT token and verify the user, if the user is not the same as the identifier, throw an error
|
||||
const jwtSession = jwtDecode(cookie);
|
||||
|
||||
// Check if the username or email is being taken by another user, if so, throw an error
|
||||
const isUsernameOrEmailIsBeingTaken = await checkUserEmailAndUsernameAvailabillityService(
|
||||
payload,
|
||||
jwtSession.userId
|
||||
);
|
||||
if (isUsernameOrEmailIsBeingTaken)
|
||||
throw new AppError(
|
||||
409,
|
||||
"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.avatar) storeAvatar = await saveAvatar(payload.avatar as File);
|
||||
|
||||
// Store the comment background to the file system if provided in the payload
|
||||
let storeCommentBackground: string | undefined = undefined;
|
||||
if (payload.commentBackground)
|
||||
storeCommentBackground = await saveCommentBackground(
|
||||
payload.commentBackground as File
|
||||
);
|
||||
|
||||
// Prepare the fields to update, only include fields that are provided in the payload
|
||||
const fieldsToUpdate: Partial<Prisma.UserUpdateInput> = {
|
||||
...(payload.username && payload.username !== jwtSession.user.username
|
||||
? { username: payload.username }
|
||||
: {}),
|
||||
|
||||
...(payload.name !== undefined ? { name: payload.name } : {}),
|
||||
...(payload.birthDate !== undefined
|
||||
? { birthDate: payload.birthDate }
|
||||
: {}),
|
||||
...(payload.gender !== undefined ? { gender: payload.gender } : {}),
|
||||
...(payload.phoneCC !== undefined ? { phoneCC: payload.phoneCC } : {}),
|
||||
...(payload.phoneNumber !== undefined
|
||||
? { phoneNumber: payload.phoneNumber }
|
||||
: {}),
|
||||
...(payload.bioProfile !== undefined
|
||||
? { bioProfile: payload.bioProfile }
|
||||
: {}),
|
||||
...(storeAvatar !== undefined ? { avatar: storeAvatar } : {}),
|
||||
...(storeCommentBackground !== undefined
|
||||
? { commentBackground: storeCommentBackground }
|
||||
: {}),
|
||||
...(payload.deletedAt !== undefined
|
||||
? { deletedAt: payload.deletedAt }
|
||||
: {}),
|
||||
};
|
||||
|
||||
// Update the user in the database, use username from the JWT session to find the user
|
||||
await updateUserRepository(jwtSession.user.username, fieldsToUpdate);
|
||||
|
||||
// Clear the session and re-login the user to get a new JWT token
|
||||
await logoutService(cookie);
|
||||
const newUserSession = await loginFromSystemService(
|
||||
jwtSession.userId,
|
||||
userHeaderInfo
|
||||
);
|
||||
|
||||
return newUserSession;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error, 500, "Internal server error");
|
||||
}
|
||||
};
|
||||
@ -1,10 +1,16 @@
|
||||
export interface FindUserByEmailOrUsernameOptions {
|
||||
queryTarget: "email" | "username" | "both";
|
||||
verbosity?: FindUserByEmailOrUsernameVerbosity; // If true, returns the user with all details including sensitive information
|
||||
export interface getUserDataService {
|
||||
identifier: string;
|
||||
queryTarget: "id" | "email" | "username" | "email_username";
|
||||
options?: getUserDataOptions;
|
||||
}
|
||||
enum FindUserByEmailOrUsernameVerbosity {
|
||||
"exists",
|
||||
"basic",
|
||||
"extended",
|
||||
"full",
|
||||
export interface getUserDataOptions {
|
||||
verbosity?: "exists" | "basic" | "full";
|
||||
include?: ("preference" | "role")[];
|
||||
}
|
||||
|
||||
export interface createUserViaRegisterInput {
|
||||
name: string;
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user