🏗️ reconstruct all system in user module
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
import bcrypt from "bcrypt";
|
import bcrypt from "bcrypt";
|
||||||
import { findUserByEmailOrUsernameService } from "../../user/services/findUserByEmailOrUsername.service";
|
import { findUserByEmailOrUsernameService } from "../../user/services/getUserData.service";
|
||||||
import { LoginWithPasswordRequest } from "../auth.types";
|
import { LoginWithPasswordRequest } from "../auth.types";
|
||||||
import { AppError } from "../../../helpers/error/instances/app";
|
import { AppError } from "../../../helpers/error/instances/app";
|
||||||
import { UserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation/types";
|
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 Elysia from "elysia";
|
||||||
import { getAllUserController } from "./controller/getAllUser.controller";
|
import { createUserViaRegisterController } from "./controller/createUserViaRegister.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";
|
|
||||||
|
|
||||||
export const userModule = new Elysia({ prefix: "/users" })
|
export const userModule = new Elysia({ prefix: "/users" }).post(
|
||||||
.get("/", getAllUserController)
|
"/",
|
||||||
.get("/e/:email", findUserByEmailController)
|
createUserViaRegisterController
|
||||||
.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)
|
|
||||||
);
|
|
||||||
|
|||||||
@ -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({
|
export const createUserSchema = z.object({
|
||||||
name: Joi.string()
|
name: z.string(),
|
||||||
.min(4)
|
username: z
|
||||||
.max(255)
|
.string()
|
||||||
.required(),
|
.min(4) //Total all username character must over 4 character
|
||||||
username: Joi.string()
|
.regex(/^[a-zA-Z0-9_-]+$/), //Prohibiting the use of spaces and symbols other than - and _
|
||||||
.min(4)
|
email: z.email(),
|
||||||
.max(255)
|
password: z
|
||||||
.required(),
|
.string()
|
||||||
email: Joi.string()
|
.min(8) //Total all password chaacter must over 8 character
|
||||||
.email()
|
.regex(/[A-Z]/) //Min has 1 uppercase letter
|
||||||
.required(),
|
.regex(/[a-z]/) //Min has 1 lowercase letter
|
||||||
password: Joi.string()
|
.regex(/[0-9]/) //Min has 1 number
|
||||||
.min(8)
|
.regex(/[^A-Za-z0-9"]/), //Min has 1 symbol character
|
||||||
.max(255)
|
|
||||||
.required(),
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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 {
|
export interface getUserDataService {
|
||||||
queryTarget: "email" | "username" | "both";
|
identifier: string;
|
||||||
verbosity?: FindUserByEmailOrUsernameVerbosity; // If true, returns the user with all details including sensitive information
|
queryTarget: "id" | "email" | "username" | "email_username";
|
||||||
|
options?: getUserDataOptions;
|
||||||
}
|
}
|
||||||
enum FindUserByEmailOrUsernameVerbosity {
|
export interface getUserDataOptions {
|
||||||
"exists",
|
verbosity?: "exists" | "basic" | "full";
|
||||||
"basic",
|
include?: ("preference" | "role")[];
|
||||||
"extended",
|
}
|
||||||
"full",
|
|
||||||
|
export interface createUserViaRegisterInput {
|
||||||
|
name: string;
|
||||||
|
username: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user