import usersLogs, { IUserLogs, userLogger } from './users.logs';
import { formatString } from '../../utils/Strings';
import { db } from '../../settings';
import { HttpCodes } from '../../config/Errors';
import { ErrorResponseC, SuccessResponseC } from '../services.response';
import { Response } from 'express';
import { ResultSetHeader, RowDataPacket } from 'mysql2';
import { AuthServices } from '../auth/auth.service';
import { Optimize } from '../../utils/Function';
export class UsersServices {
static getStatistics = async (): Promise<ResponseT> => {
try {
const sqlquery = `SELECT
(SELECT COUNT(*) FROM teachers) AS teachers,
(SELECT COUNT(*) FROM schools) AS schools,
(SELECT COUNT(*) FROM inst_designers) AS inst_designers,
(SELECT COUNT(*) FROM orders) AS total_orders,
(SELECT COUNT(*) FROM courses) AS courses
`;
const [statistics] = await db.query<any[]>(sqlquery);
const resp: ICode<IUserLogs> = usersLogs.GET_STATISTICS_SUCCESS;
const msg = resp.message;
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
statistics[0],
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_STATISTICS_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_STATISTICS_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getUsersBySuperAdmin = async (
res: Response,
user_id: number
): Promise<ResponseT> => {
try {
const sqlquery = `SELECT u.user_id, u.email, u.firstName, u.lastName, u.role, u.phone, s.schoolName FROM users u
LEFT JOIN schools s ON u.user_id = s.user_id
WHERE u.user_id != ?`;
const [users] = await db.query<UserI[]>(sqlquery, [user_id]);
const resp: ICode<IUserLogs> = usersLogs.GET_USERS_BY_SUPER_ADMIN_SUCCESS;
const msg = formatString(resp.message, { count: users.length });
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
users,
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(
usersLogs.GET_USERS_BY_SUPER_ADMIN_ERROR.message,
{
error: (err as Error)?.message || '',
}
);
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_USERS_BY_SUPER_ADMIN_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getUsersByAdmin = async (
res: Response,
user_id: number
): Promise<ResponseT> => {
try {
const sqlquery = `SELECT u.user_id, u.email, u.firstName, u.lastName, u.role, u.phone, s.schoolName FROM users u
LEFT JOIN schools s ON u.user_id = s.user_id
WHERE u.user_id != ? AND u.role != "super_admin" AND u.role != "admin" AND u.role != "inst_admin"`;
const [users] = await db.query<UserI[]>(sqlquery, [user_id]);
const resp: ICode<IUserLogs> = usersLogs.GET_USERS_BY_ADMIN_SUCCESS;
const msg = formatString(resp.message, { count: users.length });
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
users,
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_USERS_BY_ADMIN_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_USERS_BY_ADMIN_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getUserById = async (
res: Response,
userId: number
): Promise<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM users WHERE user_id = ?';
const [[user]] = await db.query<UserI[]>(sqlquery, [userId]);
if (!user) {
const msg = formatString(usersLogs.GET_USER_BY_ID_ERROR.message, {
userId,
});
userLogger.error(msg);
return new ErrorResponseC(
usersLogs.GET_USER_BY_ID_ERROR.type,
HttpCodes.NotFound.code,
msg
);
}
// get additional info base on role
const additionalInfo = await AuthServices.getAdditionalInfo(
user.role,
user.user_id
);
if (additionalInfo.isErr) {
const msg = formatString(usersLogs.GET_USER_BY_ID_ERROR.message, {
error: (additionalInfo.err as Error)?.message || '',
});
userLogger.error(msg, additionalInfo.err as Error);
return new ErrorResponseC(
usersLogs.GET_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
const resp: ICode<IUserLogs> = usersLogs.GET_USER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
userId: user.user_id,
email: user.email,
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
{ ...Optimize(user), ...additionalInfo.data },
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_USER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static updateUserById = async (
res: Response,
userId: number,
data: {
email: string;
firstName: string;
lastName: string;
role: string;
phone: string | null;
additionalInfo: any;
}
): Promise<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM users WHERE user_id = ?';
const [[user]] = await db.query<UserI[]>(sqlquery, [userId]);
if (!user) {
const msg = formatString(usersLogs.UPDATE_USER_BY_ID_ERROR.message, {
userId,
});
userLogger.error(msg);
return new ErrorResponseC(
usersLogs.UPDATE_USER_BY_ID_ERROR.type,
HttpCodes.NotFound.code,
msg
);
}
const sqlUpdateQuery =
'UPDATE users SET email = ?, firstName = ?, lastName = ?, role = ?, phone = ? WHERE user_id = ?';
const result = await db.query<ResultSetHeader[]>(sqlUpdateQuery, [
data.email,
data.firstName,
data.lastName,
data.role,
data.phone,
userId,
]);
// if (data.password) {
// const hashedPassword = bcrypt.hashSync(data.password, 10);
// const sqlUpdatePasswordQuery =
// 'UPDATE users SET password = ? WHERE user_id = ?';
// await db.query<ResultSetHeader[]>(sqlUpdatePasswordQuery, [
// hashedPassword,
// userId,
// ]);
// }
// update additional info base on role
if (
user.role !== 'admin' &&
user.role !== 'super_admin' &&
user.role !== 'inst_admin'
) {
const updateAdditionalInfo = await this.updateAdditionalInfo(
user.role,
user.user_id,
data.additionalInfo
);
if (updateAdditionalInfo.isErr) {
const msg = formatString(usersLogs.UPDATE_USER_BY_ID_ERROR.message, {
error: (updateAdditionalInfo.err as Error)?.message || '',
});
userLogger.error(msg, updateAdditionalInfo.err as Error);
return new ErrorResponseC(
usersLogs.UPDATE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
}
const resp: ICode<IUserLogs> = usersLogs.UPDATE_USER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
userId,
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
{ ...Optimize(user), ...data },
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.UPDATE_USER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.UPDATE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static updateTeacherById = async (
res: Response,
teacherId: number,
data: {
email: string;
firstName: string;
lastName: string;
role: string;
phone: string | null;
additionalInfo: any;
}
): Promise<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM teachers WHERE teacher_id = ?';
const [[teacher]] = await db.query<Teacher[]>(sqlquery, [teacherId]);
if (!teacher) {
const msg = formatString(usersLogs.UPDATE_USER_BY_ID_ERROR.message, {
teacherId,
});
userLogger.error(msg);
return new ErrorResponseC(
usersLogs.UPDATE_USER_BY_ID_ERROR.type,
HttpCodes.NotFound.code,
msg
);
}
const sqlUpdateQuery =
'UPDATE users SET email = ?, firstName = ?, lastName = ?, role = ?, phone = ? WHERE user_id = ?';
const result = await db.query<ResultSetHeader[]>(sqlUpdateQuery, [
data.email,
data.firstName,
data.lastName,
data.role,
data.phone,
teacher.user_id,
]);
// update additional info base on role
const updateAdditionalInfo = await this.updateAdditionalInfo(
'teacher',
teacher.user_id,
data.additionalInfo
);
if (updateAdditionalInfo.isErr) {
const msg = formatString(usersLogs.UPDATE_USER_BY_ID_ERROR.message, {
error: (updateAdditionalInfo.err as Error)?.message || '',
});
userLogger.error(msg, updateAdditionalInfo.err as Error);
return new ErrorResponseC(
usersLogs.UPDATE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
const resp: ICode<IUserLogs> = usersLogs.UPDATE_USER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
teacherId,
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
{ ...Optimize(teacher), ...data },
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.UPDATE_USER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.UPDATE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static updateAdditionalInfo = async (
role: string,
user_id: number,
additionalInfo: any
): Promise<{
isErr: boolean;
err: any;
}> => {
const tableName =
role === 'teacher'
? 'teachers'
: role === 'school'
? 'schools'
: 'inst_designers';
if (!additionalInfo) return { isErr: false, err: null };
const additionalInfoKeys = Object.keys(additionalInfo);
const additionalInfoValues = Object.values(additionalInfo);
const additionalInfoColumns = additionalInfoKeys.join(' = ?, ');
additionalInfoValues.push(user_id);
try {
const sqlquery = `UPDATE ${tableName} SET ${additionalInfoColumns} = ? WHERE user_id = ?`;
await db.query<RowDataPacket[]>(sqlquery, additionalInfoValues);
return { isErr: false, err: null };
} catch (err) {
return { isErr: true, err };
}
};
static deleteUserById = async (
res: Response,
userId: number
): Promise<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM users WHERE user_id = ?';
const [[user]] = await db.query<UserI[]>(sqlquery, [userId]);
if (!user) {
const msg = formatString(usersLogs.DELETE_USER_BY_ID_ERROR.message, {
userId,
});
userLogger.error(msg);
return new ErrorResponseC(
usersLogs.DELETE_USER_BY_ID_ERROR.type,
HttpCodes.NotFound.code,
msg
);
}
const sqlDeleteQuery = 'DELETE FROM users WHERE user_id = ?';
await db.query<RowDataPacket[]>(sqlDeleteQuery, [userId]);
// delete additional info base on role
if (
user.role !== 'admin' &&
user.role !== 'super_admin' &&
user.role !== 'inst_admin'
) {
const tableName =
user.role === 'teacher'
? 'teachers'
: user.role === 'school'
? 'schools'
: 'inst_designers';
const sqlDeleteAdditionalInfoQuery = `DELETE FROM ${tableName} WHERE user_id = ?`;
await db.query<RowDataPacket[]>(sqlDeleteAdditionalInfoQuery, [userId]);
}
const resp: ICode<IUserLogs> = usersLogs.DELETE_USER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
userId,
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
{ ...Optimize(user) },
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.DELETE_USER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.DELETE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static deleteTeacherById = async (
res: Response,
teacherId: number
): Promise<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM teachers WHERE teacher_id = ?';
const [[teacher]] = await db.query<Teacher[]>(sqlquery, [teacherId]);
if (!teacher) {
const msg = formatString(usersLogs.DELETE_USER_BY_ID_ERROR.message, {
teacherId,
});
userLogger.error(msg);
return new ErrorResponseC(
usersLogs.DELETE_USER_BY_ID_ERROR.type,
HttpCodes.NotFound.code,
msg
);
}
const sqlDeleteQuery = 'DELETE FROM users WHERE user_id = ?';
await db.query<RowDataPacket[]>(sqlDeleteQuery, [teacher.user_id]);
const resp: ICode<IUserLogs> = usersLogs.DELETE_USER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
teacherId,
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
{ ...Optimize(teacher) },
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.DELETE_USER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.DELETE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static bulkDeleteUsers = async (
res: Response,
userIds: number[]
): Promise<ResponseT> => {
try {
// const sqlDeleteQuery = 'DELETE FROM users WHERE user_id IN (?)';
// await db.query<RowDataPacket[]>(sqlDeleteQuery, [userIds]);
for (const userId of userIds) {
const sqlDeleteQuery = 'DELETE FROM users WHERE user_id = ?';
await db.query<RowDataPacket[]>(sqlDeleteQuery, [userId]);
}
const resp: ICode<IUserLogs> = usersLogs.DELETE_USER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
userIds: userIds.join(', '),
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(resp.type, {}, msg, HttpCodes.Accepted.code);
} catch (err) {
const msg = formatString(usersLogs.DELETE_USER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.DELETE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static bulkDeleteTeachers = async (
res: Response,
teacherIds: number[]
): Promise<ResponseT> => {
try {
for (const teacherId of teacherIds) {
const sqlquery = 'SELECT * FROM teachers WHERE teacher_id = ?';
const [[teacher]] = await db.query<Teacher[]>(sqlquery, [teacherId]);
if (!teacher) {
const msg = formatString(usersLogs.DELETE_USER_BY_ID_ERROR.message, {
teacherId,
});
userLogger.error(msg);
return new ErrorResponseC(
usersLogs.DELETE_USER_BY_ID_ERROR.type,
HttpCodes.NotFound.code,
msg
);
}
const sqlDeleteQuery = 'DELETE FROM users WHERE user_id = ?';
await db.query<RowDataPacket[]>(sqlDeleteQuery, [teacher.user_id]);
}
const resp: ICode<IUserLogs> = usersLogs.DELETE_USER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
teacherIds: teacherIds.join(', '),
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(resp.type, {}, msg, HttpCodes.Accepted.code);
} catch (err) {
const msg = formatString(usersLogs.DELETE_USER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.DELETE_USER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getTeachersBySchool = async (
res: Response,
schoolId: number
): Promise<ResponseT> => {
try {
const sqlquery =
'SELECT t.*, u.firstName, u.lastName, u.user_id, u.email, u.phone FROM teachers t JOIN users u ON t.user_id = u.user_id WHERE t.school_id = ?';
const [teachers] = await db.query<Teacher[]>(sqlquery, [schoolId]);
const resp: ICode<IUserLogs> = usersLogs.GET_TEACHERS_BY_SCHOOL_SUCCESS;
const msg = formatString(resp.message, { count: teachers.length });
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
teachers,
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_TEACHERS_BY_SCHOOL_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_TEACHERS_BY_SCHOOL_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getTeacherById = async (
res: Response,
teacherId: number
): Promise<ResponseT> => {
try {
const sqlquery =
'SELECT t.*, u.firstName, u.lastName, u.user_id, u.email, u.phone FROM teachers t JOIN users u ON t.user_id = u.user_id WHERE t.teacher_id = ?';
const [[teacher]] = await db.query<Teacher[]>(sqlquery, [teacherId]);
if (!teacher) {
const msg = formatString(usersLogs.GET_TEACHER_BY_ID_ERROR.message, {
teacherId,
});
userLogger.error(msg);
return new ErrorResponseC(
usersLogs.GET_TEACHER_BY_ID_ERROR.type,
HttpCodes.NotFound.code,
msg
);
}
const resp: ICode<IUserLogs> = usersLogs.GET_TEACHER_BY_ID_SUCCESS;
const msg = formatString(resp.message, {
teacherId,
});
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
teacher,
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_TEACHER_BY_ID_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_TEACHER_BY_ID_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getSchools = async (res: Response): Promise<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM schools';
const [schools] = await db.query<School[]>(sqlquery);
const resp: ICode<IUserLogs> = usersLogs.GET_SCHOOLS_SUCCESS;
const msg = resp.message;
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
schools,
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_SCHOOLS_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_SCHOOLS_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getTeachers = async (res: Response): Promise<ResponseT> => {
try {
const sqlquery =
'SELECT t.*, u.email FROM teachers t JOIN users u ON t.user_id = u.user_id';
const [teachers] = await db.query<Teacher[]>(sqlquery);
const resp: ICode<IUserLogs> = usersLogs.GET_TEACHERS_SUCCESS;
const msg = resp.message;
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
teachers,
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_TEACHERS_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_TEACHERS_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
static getInstDesigners = async (res: Response): Promise<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM inst_designers';
const [instDesigners] = await db.query<any[]>(sqlquery);
const resp: ICode<IUserLogs> = usersLogs.GET_INST_DESIGNERS_SUCCESS;
const msg = resp.message;
userLogger.info(msg, { type: resp.type });
return new SuccessResponseC(
resp.type,
instDesigners,
msg,
HttpCodes.Accepted.code
);
} catch (err) {
const msg = formatString(usersLogs.GET_INST_DESIGNERS_ERROR.message, {
error: (err as Error)?.message || '',
});
userLogger.error(msg, err as Error);
return new ErrorResponseC(
usersLogs.GET_INST_DESIGNERS_ERROR.type,
HttpCodes.InternalServerError.code,
msg
);
}
};
}