first commit
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
const hashPassword = async (password: string, saltLength = 12) => {
|
||||
const salt = await bcrypt.genSalt(saltLength);
|
||||
const hashedPassword = await bcrypt.hash(password, salt);
|
||||
return hashedPassword;
|
||||
};
|
||||
|
||||
export default hashPassword;
|
||||
@@ -0,0 +1,3 @@
|
||||
export function isNull<Type>(data: any, returnValue: Type): Type {
|
||||
return data ? data : returnValue;
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
const NoPermissionMessage = () => {
|
||||
return "No tienes permisos para realizar esta acción.";
|
||||
};
|
||||
|
||||
export { NoPermissionMessage };
|
||||
@@ -0,0 +1,11 @@
|
||||
import { isNull } from "./IsNull";
|
||||
|
||||
export function joinStrings(params: any[], concat: string): string {
|
||||
let returnValue: string = "";
|
||||
params.forEach((param) => {
|
||||
const value = isNull<string>(param, concat);
|
||||
returnValue += value + " ";
|
||||
});
|
||||
|
||||
return returnValue.trimEnd();
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
import EmployeesList from "../Models/Employees/Employee";
|
||||
import { EmployeeRoles } from "../Models/Employees/Employees.Interface";
|
||||
import UserList from "../Models/Users/Users";
|
||||
import { IUserDocument } from "../Models/Users/Users.Adapter.Mongoose";
|
||||
import { NoPermissionMessage } from "./NoPermissionMessage";
|
||||
import CompaniesList from "../Models/Companies/Companies";
|
||||
import { ICompanyDocument } from "../Models/Companies/Companies.Adapter.Mongoose";
|
||||
import ClientsList from "../Models/Clients/Clients";
|
||||
import { PlanFeatures } from "../Models/Plans/Plans.interface";
|
||||
import PlanSubscriptionsList from "../Models/PlanSubscriptions/PlanSubscriptons";
|
||||
import { IClientDocument } from "../Models/Clients/Clients.Adapter.Mongoose";
|
||||
|
||||
export type ValidateSessionUserParams = {
|
||||
sessionUser: string;
|
||||
};
|
||||
|
||||
export type ValidateSessionUserResult = {
|
||||
user: IUserDocument;
|
||||
};
|
||||
|
||||
export async function validateSessionUser(
|
||||
data: ValidateSessionUserParams
|
||||
): Promise<ValidateSessionUserResult> {
|
||||
const sessionUser = await UserList.users.findOne({
|
||||
_id: data.sessionUser,
|
||||
});
|
||||
|
||||
if (!sessionUser) {
|
||||
throw new Error(
|
||||
"No se ha encontrado el usuario o no tiene permisos para realizar esta acción"
|
||||
);
|
||||
}
|
||||
|
||||
return { user: sessionUser };
|
||||
}
|
||||
|
||||
export type ValidatePermissionsByCompanyParams = {
|
||||
companyId: string;
|
||||
sessionUser: string;
|
||||
};
|
||||
|
||||
export type ValidatePermissionsByCompanyResult = {
|
||||
company: ICompanyDocument;
|
||||
};
|
||||
|
||||
export async function validatePermissionsByCompany(
|
||||
data: ValidatePermissionsByCompanyParams
|
||||
): Promise<ValidatePermissionsByCompanyResult> {
|
||||
const company = await CompaniesList.companies.findOne({
|
||||
_id: data.companyId,
|
||||
});
|
||||
|
||||
if (!company) {
|
||||
throw new Error("No se ha encontrado la organización");
|
||||
}
|
||||
|
||||
const hasAdminPermission = await EmployeesList.checkRoleById(
|
||||
data.companyId,
|
||||
data.sessionUser,
|
||||
EmployeeRoles.ADMIN
|
||||
);
|
||||
|
||||
if (!hasAdminPermission) {
|
||||
throw new Error(NoPermissionMessage());
|
||||
}
|
||||
|
||||
return { company };
|
||||
}
|
||||
|
||||
export type ValidatePermissionsByClientParams = {
|
||||
sessionUser: string;
|
||||
feature?: PlanFeatures;
|
||||
clientId: string;
|
||||
};
|
||||
|
||||
export type ValidationPermissionsByClientResult = {
|
||||
client: IClientDocument;
|
||||
company: ICompanyDocument;
|
||||
};
|
||||
|
||||
export async function validatePermissionsByClient(
|
||||
data: ValidatePermissionsByClientParams
|
||||
): Promise<ValidationPermissionsByClientResult> {
|
||||
const client = await ClientsList.clients.findOne({ _id: data.clientId });
|
||||
|
||||
if (!client) {
|
||||
throw new Error("No se ha encontrado el cliente");
|
||||
}
|
||||
|
||||
const clientCompany = await CompaniesList.companies.findOne({
|
||||
_id: String(client.companyId),
|
||||
});
|
||||
|
||||
if (!clientCompany) {
|
||||
throw new Error("No se ha encontrado la empresa del cliente");
|
||||
}
|
||||
|
||||
// Verificar si el usuario de sesión es un empleado con permisos de administrador
|
||||
const hasAdminPermission = await EmployeesList.checkRoleById(
|
||||
clientCompany.id,
|
||||
data.sessionUser,
|
||||
EmployeeRoles.ADMIN
|
||||
);
|
||||
|
||||
if (!hasAdminPermission) {
|
||||
throw new Error(NoPermissionMessage());
|
||||
}
|
||||
|
||||
if (data.feature) {
|
||||
const canAccess = await PlanSubscriptionsList.checkFeature({
|
||||
userId: String(clientCompany.ownerId),
|
||||
feature: data.feature,
|
||||
});
|
||||
|
||||
if (!canAccess) {
|
||||
throw new Error("La organizacion no tiene un plan que soporte el módulo de pagos");
|
||||
}
|
||||
}
|
||||
|
||||
return { client, company: clientCompany };
|
||||
}
|
||||
|
||||
export type GetAuthorizedUsersParams = {
|
||||
companyId: string;
|
||||
};
|
||||
|
||||
export type GetAuthorizedUsersResult = {
|
||||
companyId: string;
|
||||
authorizedUsers: string[];
|
||||
};
|
||||
|
||||
export async function getAuthorizedUsers(
|
||||
data: GetAuthorizedUsersParams
|
||||
): Promise<GetAuthorizedUsersResult> {
|
||||
const company = await CompaniesList.companies.findOne({
|
||||
_id: data.companyId,
|
||||
});
|
||||
|
||||
if (!company) {
|
||||
throw new Error("No se ha encontrado la organización");
|
||||
}
|
||||
|
||||
const employees = await EmployeesList.findByCompanyId({
|
||||
companyId: data.companyId,
|
||||
});
|
||||
|
||||
let returnValue: string[] = [];
|
||||
|
||||
for (const employee of employees) {
|
||||
const hasAdminPermission = await EmployeesList.checkRoleById(
|
||||
data.companyId,
|
||||
String(employee.userId),
|
||||
EmployeeRoles.ADMIN
|
||||
);
|
||||
|
||||
if (hasAdminPermission) {
|
||||
returnValue.push(String(employee.userId));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
companyId: company.id,
|
||||
authorizedUsers: returnValue,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export const formatCurrency = (value: number): string => {
|
||||
const formatter = new Intl.NumberFormat("en-US", {
|
||||
style: "currency",
|
||||
currency: "ARS",
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
|
||||
// Reemplazamos el símbolo "ARS" o "ARS$" por "$"
|
||||
return formatter.format(value).replace(/^ARS\s?/, "$");
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export default function getAvatar(
|
||||
userId: string,
|
||||
avatar: string | null | undefined,
|
||||
fallback: string
|
||||
): string {
|
||||
const rootPath = process.env.PUBLIC_AVATAR_URL;
|
||||
if (userId == null) return fallback;
|
||||
if (avatar == undefined || avatar == null || avatar === "") return fallback;
|
||||
|
||||
const rootDir =
|
||||
process.env.NODE_ENV !== "production"
|
||||
? process.env.GET_AVATAR_USERS_FILES_ROOT_DEV
|
||||
: process.env.GET_AVATAR_USERS_FILES_ROOT_PRO;
|
||||
|
||||
const uploadPath = path.join(__dirname, rootDir + userId);
|
||||
|
||||
const filePath = path.join(uploadPath, avatar);
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return avatar ? rootPath + userId + "/" + avatar : "";
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export default function getHeader(
|
||||
companyId: string,
|
||||
header: string | null | undefined,
|
||||
fallback: string
|
||||
): string {
|
||||
const rootPath = process.env.PUBLIC_HEADER_URL;
|
||||
if (companyId == null) return fallback;
|
||||
if (header == undefined || header == null || header === "") return fallback;
|
||||
|
||||
const rootDir =
|
||||
process.env.NODE_ENV !== "production"
|
||||
? process.env.GET_HEADER_COMPANIES_FILES_ROOT_DEV
|
||||
: process.env.GET_HEADER_COMPANIES_FILES_ROOT_PRO;
|
||||
|
||||
const uploadPath = path.join(__dirname, rootDir + companyId);
|
||||
|
||||
const filePath = path.join(uploadPath, header);
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return header ? rootPath + companyId + "/" + header : "";
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export default function getServiceImage(
|
||||
serviceId: string,
|
||||
image: string | null | undefined,
|
||||
fallback: string
|
||||
): string {
|
||||
const rootPath = process.env.PUBLIC_SERVICE_IMAGE_URL;
|
||||
if (serviceId == null) return fallback;
|
||||
if (image == undefined || image == null || image === "") return fallback;
|
||||
|
||||
const rootDir =
|
||||
process.env.NODE_ENV !== "production"
|
||||
? process.env.GET_SERVICE_IMAGE_FILES_ROOT_DEV
|
||||
: process.env.GET_SERVICE_IMAGE_FILES_ROOT_PRO;
|
||||
|
||||
const uploadPath = path.join(__dirname, rootDir + serviceId);
|
||||
|
||||
const filePath = path.join(uploadPath, image);
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return image ? rootPath + serviceId + "/" + image : "";
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
const getTimeStringFromNumber = (decimalHours: number): string => {
|
||||
// Calcula las horas y minutos
|
||||
const hours = Math.floor(decimalHours);
|
||||
const minutes = Math.round((decimalHours - hours) * 60);
|
||||
|
||||
// Asegúrate de que el formato sea siempre de dos dígitos
|
||||
const paddedHours = hours.toString().padStart(2, "0");
|
||||
const paddedMinutes = minutes.toString().padStart(2, "0");
|
||||
|
||||
return `${paddedHours}:${paddedMinutes}`;
|
||||
};
|
||||
|
||||
export { getTimeStringFromNumber };
|
||||
@@ -0,0 +1,26 @@
|
||||
import sharp from "sharp";
|
||||
|
||||
/**
|
||||
* Resizes and crops an image to the specified dimensions.
|
||||
*
|
||||
* @param {sharp.Sharp} img - The image to be resized and cropped.
|
||||
* @param {number} width - The desired width of the output image.
|
||||
* @param {number} height - The desired height of the output image.
|
||||
* @return {Promise<sharp.Sharp>} A promise that resolves to the resized and cropped image.
|
||||
*/
|
||||
const resizeAndCrop = async (
|
||||
img: sharp.Sharp,
|
||||
width: number,
|
||||
height: number
|
||||
): Promise<sharp.Sharp> => {
|
||||
const buffer = await img
|
||||
.resize(width, height, {
|
||||
fit: "cover", // rellena todo el espacio, recorta si es necesario
|
||||
position: "centre", // centra el recorte (opcional, es el valor por defecto)
|
||||
})
|
||||
.toBuffer();
|
||||
|
||||
return sharp(buffer);
|
||||
};
|
||||
|
||||
export { resizeAndCrop };
|
||||
Reference in New Issue
Block a user