mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-20 16:39:07 -05:00
refactor user-service
This commit is contained in:
@@ -192,7 +192,8 @@ class AuthController {
|
||||
editUserById = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const roles = req?.user?.role;
|
||||
if (!roles.includes("superadmin")) {
|
||||
|
||||
if (!roles || !roles.includes("superadmin")) {
|
||||
throw new AppError({ message: "Unauthorized", status: 403 });
|
||||
}
|
||||
|
||||
@@ -201,7 +202,7 @@ class AuthController {
|
||||
|
||||
await editUserByIdParamValidation.validateAsync(req.params);
|
||||
// If this is superadmin self edit, allow "superadmin" role
|
||||
if (userId === req.user._id) {
|
||||
if (userId === req.user?.id) {
|
||||
await editSuperadminUserByIdBodyValidation.validateAsync(req.body);
|
||||
} else {
|
||||
await editUserByIdBodyValidation.validateAsync(req.body);
|
||||
@@ -217,7 +218,7 @@ class AuthController {
|
||||
editUserPasswordById = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const roles = req?.user?.role;
|
||||
if (!roles.includes("superadmin")) {
|
||||
if (!roles || !roles.includes("superadmin")) {
|
||||
throw new AppError({ message: "Unauthorized", status: 403 });
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class IncidentController {
|
||||
try {
|
||||
const resolvedIncident = await this.incidentService.resolveIncidentManually({
|
||||
incidentId: req?.params?.incidentId,
|
||||
userId: req?.user?._id,
|
||||
userId: req?.user?.id,
|
||||
teamId: req?.user?.teamId,
|
||||
comment: req?.body?.comment,
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ class MaintenanceWindowController {
|
||||
try {
|
||||
await getMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
|
||||
const teamId = req.user.teamId;
|
||||
const teamId = req.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
}
|
||||
@@ -130,7 +130,7 @@ class MaintenanceWindowController {
|
||||
await editMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body);
|
||||
|
||||
const teamId = req.user.teamId;
|
||||
const teamId = req.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ class MonitorController {
|
||||
try {
|
||||
await createMonitorBodyValidation.validateAsync(req.body);
|
||||
|
||||
const userId = requireString(req?.user?._id, "User ID");
|
||||
const userId = requireString(req?.user?.id, "User ID");
|
||||
const teamId = requireTeamId(req?.user?.teamId);
|
||||
|
||||
const monitor = await this.monitorService.createMonitor(teamId, userId, req.body);
|
||||
@@ -193,7 +193,7 @@ class MonitorController {
|
||||
throw new AppError({ message: "File is empty", status: 400 });
|
||||
}
|
||||
|
||||
const userId = requireString(req?.user?._id, "User ID");
|
||||
const userId = requireString(req?.user?.id, "User ID");
|
||||
const teamId = requireTeamId(req?.user?.teamId);
|
||||
|
||||
const fileData = req?.file?.buffer?.toString("utf-8");
|
||||
@@ -286,9 +286,9 @@ class MonitorController {
|
||||
|
||||
addDemoMonitors = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const _id = requireString(req?.user?._id, "User ID");
|
||||
const id = requireString(req?.user?.id, "User ID");
|
||||
const teamId = requireTeamId(req?.user?.teamId);
|
||||
const demoMonitors = await this.monitorService.addDemoMonitors({ userId: _id, teamId });
|
||||
const demoMonitors = await this.monitorService.addDemoMonitors({ userId: id, teamId });
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
|
||||
@@ -53,7 +53,7 @@ class NotificationController {
|
||||
throw new AppError({ message: "Team ID is required", status: 400 });
|
||||
}
|
||||
|
||||
const userId = req?.user?._id;
|
||||
const userId = req?.user?.id;
|
||||
if (!userId) {
|
||||
throw new AppError({ message: "User ID is required", status: 400 });
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ class StatusPageController {
|
||||
await createStatusPageBodyValidation.validateAsync(req.body);
|
||||
await imageValidation.validateAsync(req.file);
|
||||
|
||||
const { _id, teamId } = req.user;
|
||||
const { id, teamId } = req.user ?? {};
|
||||
const statusPage = await this.db.statusPageModule.createStatusPage({
|
||||
statusPageData: req.body,
|
||||
image: req.file,
|
||||
userId: _id,
|
||||
userId: id,
|
||||
teamId,
|
||||
});
|
||||
return res.status(200).json({
|
||||
@@ -87,7 +87,7 @@ class StatusPageController {
|
||||
};
|
||||
getStatusPagesByTeamId = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const teamId = req.user.teamId;
|
||||
const teamId = req.user?.teamId;
|
||||
const statusPages = await this.db.statusPageModule.getStatusPagesByTeamId(teamId);
|
||||
|
||||
return res.status(200).json({
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
|
||||
import jwt from "jsonwebtoken";
|
||||
import ServiceRegistry from "../../service/system/serviceRegistry.js";
|
||||
import SettingsService from "../../service/system/settingsService.js";
|
||||
@@ -5,20 +7,12 @@ import StringService from "../../service/system/stringService.js";
|
||||
const SERVICE_NAME = "verifyJWT";
|
||||
const TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* Verifies the JWT token
|
||||
* @function
|
||||
* @param {express.Request} req
|
||||
* @param {express.Response} res
|
||||
* @param {express.NextFunction} next
|
||||
* @returns {express.Response}
|
||||
*/
|
||||
const verifyJWT = (req, res, next) => {
|
||||
const verifyJWT = (req: Request, res: Response, next: NextFunction) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
const token = req.headers["authorization"];
|
||||
// Make sure a token is provided
|
||||
if (!token) {
|
||||
const error = new Error(stringService.noAuthToken);
|
||||
const error: any = new Error(stringService.noAuthToken);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
@@ -26,7 +20,7 @@ const verifyJWT = (req, res, next) => {
|
||||
}
|
||||
// Make sure it is properly formatted
|
||||
if (!token.startsWith(TOKEN_PREFIX)) {
|
||||
const error = new Error(stringService.invalidAuthToken); // Instantiate a new Error object for improperly formatted token
|
||||
const error: any = new Error(stringService.invalidAuthToken); // Instantiate a new Error object for improperly formatted token
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifyJWT";
|
||||
@@ -37,7 +31,7 @@ const verifyJWT = (req, res, next) => {
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
// Verify the token's authenticity
|
||||
const { jwtSecret } = ServiceRegistry.get(SettingsService.SERVICE_NAME).getSettings();
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
jwt.verify(parsedToken, jwtSecret, (err: any, decoded: any) => {
|
||||
if (err) {
|
||||
const errorMessage = err.name === "TokenExpiredError" ? stringService.expiredAuthToken : stringService.invalidAuthToken;
|
||||
err.details = { msg: errorMessage };
|
||||
@@ -4,9 +4,12 @@ export interface IUsersRepository {
|
||||
create(user: Partial<User>, imageFile?: Express.Multer.File | null): Promise<User>;
|
||||
// fetch
|
||||
findByEmail(email: string): Promise<User>;
|
||||
findById(id: string): Promise<User>;
|
||||
findAll(): Promise<User[]>;
|
||||
// update
|
||||
updateById(id: string, patch: Partial<User>, file?: Express.Multer.File | null): Promise<User>;
|
||||
// delete
|
||||
deleteById(id: string): Promise<User>;
|
||||
// other
|
||||
findSuperAdmin(): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,20 @@ class MongoUsersRepository implements IUsersRepository {
|
||||
return this.toEntity(user);
|
||||
};
|
||||
|
||||
findById = async (id: string) => {
|
||||
const user = await UserModel.findById(id).select("-password").select("-profileImage");
|
||||
if (!user) {
|
||||
throw new Error("User not found");
|
||||
}
|
||||
|
||||
return this.toEntity(user);
|
||||
};
|
||||
|
||||
findAll = async () => {
|
||||
const users = await UserModel.find().select("-password").select("-profileImage");
|
||||
return this.mapDocuments(users);
|
||||
};
|
||||
|
||||
updateById = async (id: string, patch: Partial<User & { deleteProfileImage?: boolean }>, file?: Express.Multer.File | null): Promise<User> => {
|
||||
const candidateUser = { ...patch };
|
||||
|
||||
@@ -113,6 +127,14 @@ class MongoUsersRepository implements IUsersRepository {
|
||||
return this.toEntity(updatedUser);
|
||||
};
|
||||
|
||||
deleteById = async (id: string) => {
|
||||
const deletedUser = await UserModel.findByIdAndDelete(id);
|
||||
if (!deletedUser) {
|
||||
throw new AppError({ message: "User not found", service: SERVICE_NAME, status: 404 });
|
||||
}
|
||||
return this.toEntity(deletedUser);
|
||||
};
|
||||
|
||||
findSuperAdmin = async () => {
|
||||
const superAdmin = await UserModel.findOne({ role: "superadmin" });
|
||||
if (superAdmin !== null) {
|
||||
@@ -120,6 +142,13 @@ class MongoUsersRepository implements IUsersRepository {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
private mapDocuments = (documents: UserDocument[]): User[] => {
|
||||
if (!documents?.length) {
|
||||
return [];
|
||||
}
|
||||
return documents.map((doc) => this.toEntity(doc));
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoUsersRepository;
|
||||
|
||||
@@ -187,7 +187,7 @@ class UserService {
|
||||
};
|
||||
|
||||
requestRecovery = async (email: string) => {
|
||||
const user = await this.db.userModule.getUserByEmail(email);
|
||||
const user = await this.usersRepository.findByEmail(email);
|
||||
|
||||
// Delete existing tokens
|
||||
await this.recoveryTokensRepository.deleteManyByEmail(email);
|
||||
@@ -231,14 +231,14 @@ class UserService {
|
||||
return { user: existingUser, token };
|
||||
};
|
||||
|
||||
deleteUser = async (user: any) => {
|
||||
deleteUser = async (user: User) => {
|
||||
const email = user?.email;
|
||||
if (!email) {
|
||||
throw this.errorService.createBadRequestError("No email in request");
|
||||
}
|
||||
|
||||
const teamId = user?.teamId;
|
||||
const userId = user?._id;
|
||||
const userId = user?.id;
|
||||
|
||||
if (!teamId) {
|
||||
throw this.errorService.createBadRequestError("No team ID in request");
|
||||
@@ -267,24 +267,28 @@ class UserService {
|
||||
));
|
||||
}
|
||||
// 6. Delete the user by id
|
||||
await this.db.userModule.deleteUser(userId);
|
||||
await this.usersRepository.deleteById(userId);
|
||||
};
|
||||
|
||||
getAllUsers = async () => {
|
||||
const users = await this.db.userModule.getAllUsers();
|
||||
return users;
|
||||
return await this.usersRepository.findAll();
|
||||
};
|
||||
|
||||
getUserById = async (roles: any, userId: any) => {
|
||||
const user = await this.db.userModule.getUserById(roles, userId);
|
||||
if (!roles.includes("superadmin")) {
|
||||
throw new AppError({ message: "User is not a superadmin", service: SERVICE_NAME, status: 403 });
|
||||
}
|
||||
const user = await this.usersRepository.findById(userId);
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
editUserById = async (userId: any, user: any) => {
|
||||
await this.db.userModule.editUserById(userId, user);
|
||||
editUserById = async (userId: any, patch: Partial<User>) => {
|
||||
await this.usersRepository.updateById(userId, patch, null);
|
||||
};
|
||||
|
||||
setPasswordByUserId = async (userId: any, password: string) => {
|
||||
const updatedUser = await this.db.userModule.updateUser({ userId: userId, user: { password: password }, file: null });
|
||||
const updatedUser = await this.usersRepository.updateById(userId, { password }, null);
|
||||
return updatedUser;
|
||||
};
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { ITokenizedUser } from "../db/models/index.ts";
|
||||
import type { User } from "@/types/index.js";
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface Request {
|
||||
file?: Multer.File;
|
||||
user?: ITokenizedUser;
|
||||
user?: User | undefined;
|
||||
resource?: any;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user