update
This commit is contained in:
7
.prettierrc
Normal file
7
.prettierrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"printWidth": 5000,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 4,
|
||||
"useTabs": true
|
||||
}
|
||||
@ -22,10 +22,10 @@
|
||||
"database": {
|
||||
"engine": "postgres",
|
||||
"host": "127.0.0.1",
|
||||
"port": "15432",
|
||||
"username": "saude_tl",
|
||||
"password": "saude_tl_local",
|
||||
"database": "saude_tl",
|
||||
"port": "1520",
|
||||
"username": "saude_stag",
|
||||
"password": "gM*#o>3W4&5X",
|
||||
"database": "saude_stag",
|
||||
"synchronize": true,
|
||||
"logging": true
|
||||
},
|
||||
|
||||
@ -12,8 +12,8 @@ import { Language } from "../langs/lang";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import fileUpload from "express-fileupload";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import config from '../../config/stag.json';
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import config from "../../config/stag.json";
|
||||
import { profile } from "console";
|
||||
|
||||
const log: Logger<ILogObj> = new Logger({
|
||||
@ -137,20 +137,10 @@ export class UserController {
|
||||
const mapped_data = list_data.map((user) => ({
|
||||
...user,
|
||||
profile_picture: user.profile_picture ?? null,
|
||||
file_profile_picture: user.profile_picture
|
||||
? `${config.server.host_swagger}uploads/doctor-profile/${user.profile_picture}`
|
||||
: null,
|
||||
file_profile_picture: user.profile_picture ? `${config.server.host_swagger}uploads/doctor-profile/${user.profile_picture}` : null,
|
||||
}));
|
||||
|
||||
return ReturnHelper.successResponselist(
|
||||
res,
|
||||
200,
|
||||
Language.lang.success_view,
|
||||
count_data,
|
||||
current_page,
|
||||
total_count_data,
|
||||
mapped_data,
|
||||
);
|
||||
return ReturnHelper.successResponselist(res, 200, Language.lang.success_view, count_data, current_page, total_count_data, mapped_data);
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
@ -214,24 +204,14 @@ export class UserController {
|
||||
filter: param.filter,
|
||||
col_any_eq: ["email"],
|
||||
col_any_like: ["User.name", "User.username"],
|
||||
additional_where: "roles.is_doctor = :is_doctor",
|
||||
additional_where: "roles.name = :doctor_role_name",
|
||||
});
|
||||
whereVal.is_doctor = true;
|
||||
whereVal.doctor_role_name = "Doctor";
|
||||
|
||||
const res_count = userRepository
|
||||
.createQueryBuilder("User")
|
||||
.leftJoin("User.roles", "roles")
|
||||
.where(whereAttr, whereVal);
|
||||
const res_count = userRepository.createQueryBuilder("User").leftJoin("User.roles", "roles").where(whereAttr, whereVal);
|
||||
|
||||
const subquery = userRepository
|
||||
.createQueryBuilder("User")
|
||||
.select("User.id", "id")
|
||||
.leftJoin("User.roles", "roles")
|
||||
.where(whereAttr, whereVal)
|
||||
.orderBy("User." + param.order_field, param.order_direction)
|
||||
.offset(offset)
|
||||
.limit(param.limit)
|
||||
.distinct(true);
|
||||
const orderExpr = "User." + param.order_field;
|
||||
const subquery = userRepository.createQueryBuilder("User").select("User.id", "id").addSelect(orderExpr, "_list_doctor_order").leftJoin("User.roles", "roles").where(whereAttr, whereVal).orderBy(orderExpr, param.order_direction).offset(offset).limit(param.limit).distinct(true);
|
||||
|
||||
const res_list = userRepository
|
||||
.createQueryBuilder("User")
|
||||
@ -255,20 +235,10 @@ export class UserController {
|
||||
const mapped_data = list_data.map((user) => ({
|
||||
...user,
|
||||
profile_picture: user.profile_picture ?? null,
|
||||
file_profile_picture: user.profile_picture
|
||||
? `${config.server.host_swagger}uploads/doctor-profile/${user.profile_picture}`
|
||||
: null,
|
||||
file_profile_picture: user.profile_picture ? `${config.server.host_swagger}uploads/doctor-profile/${user.profile_picture}` : null,
|
||||
}));
|
||||
|
||||
return ReturnHelper.successResponselist(
|
||||
res,
|
||||
200,
|
||||
Language.lang.success_view,
|
||||
count_data,
|
||||
current_page,
|
||||
total_count_data,
|
||||
mapped_data,
|
||||
);
|
||||
return ReturnHelper.successResponselist(res, 200, Language.lang.success_view, count_data, current_page, total_count_data, mapped_data);
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
@ -323,10 +293,7 @@ export class UserController {
|
||||
|
||||
const filename = "user.xlsx";
|
||||
|
||||
res.setHeader(
|
||||
"Content-Type",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
);
|
||||
res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
res.setHeader("Content-Disposition", "attachment; filename=" + filename);
|
||||
|
||||
const workbook = new exceljs.stream.xlsx.WorkbookWriter({ stream: res });
|
||||
@ -348,25 +315,7 @@ export class UserController {
|
||||
const fetchAndWrite = async (page: any) => {
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
const data = await userRepository
|
||||
.createQueryBuilder()
|
||||
.where(whereAttr, whereVal)
|
||||
.select([
|
||||
"User.id as id",
|
||||
"User.name as name",
|
||||
"User.email as email",
|
||||
"User.username as username",
|
||||
"User.status as status",
|
||||
"User.created_at as created_at",
|
||||
"roles.name as role_name",
|
||||
"application.id as application",
|
||||
])
|
||||
.leftJoin("User.roles", "roles")
|
||||
.leftJoin("roles.application", "application")
|
||||
.orderBy(param.order_field, param.order_direction)
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.getRawMany();
|
||||
const data = await userRepository.createQueryBuilder().where(whereAttr, whereVal).select(["User.id as id", "User.name as name", "User.email as email", "User.username as username", "User.status as status", "User.created_at as created_at", "roles.name as role_name", "application.id as application"]).leftJoin("User.roles", "roles").leftJoin("roles.application", "application").orderBy(param.order_field, param.order_direction).offset(offset).limit(limit).getRawMany();
|
||||
|
||||
data.forEach((item: any) => sheet.addRow(item).commit());
|
||||
|
||||
@ -410,11 +359,7 @@ export class UserController {
|
||||
const schema = Joi.object().keys({
|
||||
email: Joi.string().email().max(64).required().label("Email"),
|
||||
username: Joi.string().max(64).required().label("Username"),
|
||||
password: Joi.string()
|
||||
.pattern(new RegExp("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"))
|
||||
.min(8)
|
||||
.required()
|
||||
.label("Password"),
|
||||
password: Joi.string().pattern(new RegExp("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$")).min(8).required().label("Password"),
|
||||
retype_password: Joi.ref("password"),
|
||||
name: Joi.string().max(64).required().label("Name"),
|
||||
employee_id: Joi.string().uuid().optional().allow("").label("Employee ID"),
|
||||
@ -431,9 +376,7 @@ export class UserController {
|
||||
data.status = param.status;
|
||||
|
||||
if (param.employee_id && param.employee_id != "") {
|
||||
const employee = await OrmHelper.DB.manager
|
||||
.getRepository(HrmsEmployee)
|
||||
.findOneByOrFail({ id: param.employee_id });
|
||||
const employee = await OrmHelper.DB.manager.getRepository(HrmsEmployee).findOneByOrFail({ id: param.employee_id });
|
||||
data.employee = employee;
|
||||
} else {
|
||||
data.employee = null;
|
||||
@ -505,23 +448,11 @@ export class UserController {
|
||||
for (let r of data.roles) {
|
||||
if (r.id == param.id_role) {
|
||||
//already added
|
||||
return ReturnHelper.errorResponse(
|
||||
res,
|
||||
409,
|
||||
401,
|
||||
Language.lang.failed_insert + ", roles already exists ",
|
||||
"",
|
||||
);
|
||||
return ReturnHelper.errorResponse(res, 409, 401, Language.lang.failed_insert + ", roles already exists ", "");
|
||||
}
|
||||
|
||||
if (r.application.id == new_role?.application.id) {
|
||||
return ReturnHelper.errorResponse(
|
||||
res,
|
||||
409,
|
||||
402,
|
||||
Language.lang.failed_insert + ", roles in this application already exists ",
|
||||
"",
|
||||
);
|
||||
return ReturnHelper.errorResponse(res, 409, 402, Language.lang.failed_insert + ", roles in this application already exists ", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -604,13 +535,7 @@ export class UserController {
|
||||
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_delete, data);
|
||||
} else {
|
||||
return ReturnHelper.errorResponse(
|
||||
res,
|
||||
404,
|
||||
401,
|
||||
Language.lang.failed_not_found + ", role not found",
|
||||
"",
|
||||
);
|
||||
return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found + ", role not found", "");
|
||||
}
|
||||
} else {
|
||||
return ReturnHelper.errorResponse(res, 404, 402, Language.lang.failed_not_found, "");
|
||||
@ -702,11 +627,7 @@ export class UserController {
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
id: Joi.string().uuid().required().label("ID"),
|
||||
password: Joi.string()
|
||||
.pattern(new RegExp("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"))
|
||||
.min(8)
|
||||
.required()
|
||||
.label("Password"),
|
||||
password: Joi.string().pattern(new RegExp("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$")).min(8).required().label("Password"),
|
||||
retype_password: Joi.ref("password"),
|
||||
});
|
||||
|
||||
@ -738,11 +659,7 @@ export class UserController {
|
||||
}
|
||||
}
|
||||
|
||||
static async uploadFile(
|
||||
files: fileUpload.FileArray | null | undefined,
|
||||
fieldName: string,
|
||||
folderPath: string
|
||||
): Promise<string | null> {
|
||||
static async uploadFile(files: fileUpload.FileArray | null | undefined, fieldName: string, folderPath: string): Promise<string | null> {
|
||||
if (!files || !files[fieldName]) return null;
|
||||
|
||||
const file = files[fieldName] as fileUpload.UploadedFile;
|
||||
@ -752,13 +669,15 @@ export class UserController {
|
||||
throw { message: `${fieldName}: File size exceeds 1MB limit` };
|
||||
}
|
||||
|
||||
const allowedMimes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
|
||||
const allowedMimes = ["image/jpeg", "image/jpg", "image/png", "image/webp"];
|
||||
if (!allowedMimes.includes(file.mimetype)) {
|
||||
throw { message: `${fieldName}: Invalid file type. Only JPG, PNG, and WEBP are allowed` };
|
||||
throw {
|
||||
message: `${fieldName}: Invalid file type. Only JPG, PNG, and WEBP are allowed`,
|
||||
};
|
||||
}
|
||||
|
||||
const ext = file.name.split('.');
|
||||
const name = uuidv4() + '.' + ext[ext.length - 1];
|
||||
const ext = file.name.split(".");
|
||||
const name = uuidv4() + "." + ext[ext.length - 1];
|
||||
const file_path = path.join(folderPath, name);
|
||||
|
||||
if (!fs.existsSync(folderPath)) {
|
||||
@ -825,7 +744,7 @@ export class UserController {
|
||||
name: Joi.string().max(64).required().label("Name"),
|
||||
employee_id: Joi.string().uuid().optional().allow("").label("Employee ID"),
|
||||
status: Joi.string().required().label("Status"),
|
||||
profile_picture: Joi.string().allow('', null).optional().label("Profile Picture"),
|
||||
profile_picture: Joi.string().allow("", null).optional().label("Profile Picture"),
|
||||
});
|
||||
|
||||
req.body.id = req.params["id"];
|
||||
@ -837,10 +756,10 @@ export class UserController {
|
||||
const data = await userRepository.findOneBy({ id: param.id });
|
||||
|
||||
if (data != null) {
|
||||
const doctorprofile = await UserController.uploadFile(req.files, 'profile_picture', 'uploads/doctor-profile');
|
||||
const doctorprofile = await UserController.uploadFile(req.files, "profile_picture", "uploads/doctor-profile");
|
||||
if (doctorprofile) {
|
||||
if (data.profile_picture) {
|
||||
const oldFilePath = path.join('uploads/doctor-profile', data.profile_picture);
|
||||
const oldFilePath = path.join("uploads/doctor-profile", data.profile_picture);
|
||||
await UserController.deleteFile(oldFilePath);
|
||||
}
|
||||
data.profile_picture = doctorprofile;
|
||||
@ -884,7 +803,6 @@ export class UserController {
|
||||
|
||||
return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_update, err.message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static async updateUserSignature(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
@ -920,7 +838,7 @@ export class UserController {
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
id: Joi.string().uuid().required().label("ID"),
|
||||
user_signature: Joi.string().allow('', null).optional().label("User Signature"),
|
||||
user_signature: Joi.string().allow("", null).optional().label("User Signature"),
|
||||
});
|
||||
|
||||
req.body.id = req.params["id"];
|
||||
@ -932,12 +850,12 @@ export class UserController {
|
||||
const data = await userRepository.findOneBy({ id: param.id });
|
||||
|
||||
if (data != null) {
|
||||
const usersignature = await UserController.uploadFile(req.files, 'user_signature', 'uploads/user-signature');
|
||||
const usersignature = await UserController.uploadFile(req.files, "user_signature", "uploads/user-signature");
|
||||
|
||||
if (usersignature) {
|
||||
// ← Hapus signature lama jika ada
|
||||
if (data.signature) {
|
||||
const oldFilePath = path.join('uploads/user-signature', data.signature);
|
||||
const oldFilePath = path.join("uploads/user-signature", data.signature);
|
||||
await UserController.deleteFile(oldFilePath);
|
||||
}
|
||||
|
||||
@ -1009,16 +927,8 @@ export class UserController {
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
const userRTRepository = OrmHelper.DB.getRepository(UserRefreshToken);
|
||||
|
||||
const affected = (
|
||||
!param.hard
|
||||
? await userRepository.softDelete({ id: param.id })
|
||||
: await userRepository.delete({ id: param.id })
|
||||
).affected ?? 0;
|
||||
const affected_rt = (
|
||||
!param.hard
|
||||
? await userRTRepository.softDelete({ id_user: param.id })
|
||||
: await userRTRepository.delete({ id_user: param.id })
|
||||
).affected;
|
||||
const affected = (!param.hard ? await userRepository.softDelete({ id: param.id }) : await userRepository.delete({ id: param.id })).affected ?? 0;
|
||||
const affected_rt = (!param.hard ? await userRTRepository.softDelete({ id_user: param.id }) : await userRTRepository.delete({ id_user: param.id })).affected;
|
||||
|
||||
if (affected > 0) {
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_delete, {});
|
||||
@ -1056,19 +966,7 @@ export class UserController {
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
const detail = await userRepository.findOne({
|
||||
relations: [
|
||||
"roles",
|
||||
"roles.application",
|
||||
"employee",
|
||||
"employee.department",
|
||||
"employee.position",
|
||||
"employee.shift",
|
||||
"employee.nationality",
|
||||
"employee.aldeia",
|
||||
"employee.suco",
|
||||
"employee.administrativu",
|
||||
"employee.munisipo",
|
||||
],
|
||||
relations: ["roles", "roles.application", "employee", "employee.department", "employee.position", "employee.shift", "employee.nationality", "employee.aldeia", "employee.suco", "employee.administrativu", "employee.munisipo"],
|
||||
where: { id: param.id },
|
||||
});
|
||||
|
||||
@ -1076,13 +974,9 @@ export class UserController {
|
||||
const data = {
|
||||
...detail,
|
||||
signature: detail.signature ?? null,
|
||||
file_signature: detail.signature
|
||||
? `${config.server.host_swagger}uploads/user-signature/${detail.signature}`
|
||||
: null,
|
||||
file_signature: detail.signature ? `${config.server.host_swagger}uploads/user-signature/${detail.signature}` : null,
|
||||
profile: detail.profile_picture ?? null,
|
||||
profile_picture: detail.profile_picture
|
||||
? `${config.server.host_swagger}uploads/doctor-profile/${detail.profile_picture}`
|
||||
: null,
|
||||
profile_picture: detail.profile_picture ? `${config.server.host_swagger}uploads/doctor-profile/${detail.profile_picture}` : null,
|
||||
};
|
||||
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_view, data);
|
||||
|
||||
Reference in New Issue
Block a user