first commit

This commit is contained in:
2026-07-16 20:48:43 -03:00
commit 5696cee264
1111 changed files with 322270 additions and 0 deletions
@@ -0,0 +1,504 @@
import UsersManager from "../Users/Users";
import CompaniesManager from "../Companies/Companies";
import {
ConvertU2UMessageConversationParams,
CountUnreadConversationParams,
CreateMessageConversationParams,
DeleteConversationsByCompanyParams,
DeleteConversationsByUserParams,
DeleteMessageConversationParams,
FindConversationItem,
FindConversationsResults,
IMessageConversation,
IMessageConversationsManager,
MarkConversationAsReadParams,
MESSAGE_CONVERSATION_TYPES,
PaginateFindContactsParams,
PaginateFindContactsResults,
PaginateMessageConversationsParams,
PaginateMessageConversationsResults,
} from "./MessagesConversations.Interface";
import { MessageConversationsAdapterMongoose } from "./MessagesConversations.Adapter.Mongoose";
import EmployeesList from "../Employees/Employee";
import ClientsList from "../Clients/Clients";
import getAvatar from "../../helpers/getAvatar";
import UserList from "../Users/Users";
import MessagesList from "../Messages/Messages";
import { isNull } from "../../helpers/IsNull";
import SystemNoficationsList from "../SystemNotifications/SystemNotification";
import mongoose from "mongoose";
type GetConversationParams = {
userId: string;
};
class MessageConversationsManager implements IMessageConversationsManager {
conversations: MessageConversationsAdapterMongoose;
constructor() {
this.conversations = new MessageConversationsAdapterMongoose();
}
public async deleteConversationsByUser(data: DeleteConversationsByUserParams): Promise<void> {
const conversationsFrom = await this.conversations.find({ userIdFrom: data.userId });
for (const conv of conversationsFrom) {
await MessagesList.messages.messageList.deleteMany({ conversationId: conv.id });
}
const conversationsTo = await this.conversations.find({ userIdTo: data.userId });
for (const conv of conversationsTo) {
await MessagesList.messages.messageList.deleteMany({ conversationId: conv.id });
}
await this.conversations.conversationList.deleteMany({ userIdFrom: data.userId });
await this.conversations.conversationList.deleteMany({ userIdTo: data.userId });
}
public async deleteConversationsByCompany(
data: DeleteConversationsByCompanyParams
): Promise<void> {
const conversations = await this.conversations.find({ companyId: data.companyId });
for (const conv of conversations) {
await MessagesList.messages.messageList.deleteMany({ conversationId: conv.id });
}
await this.conversations.conversationList.deleteMany({ companyId: data.companyId });
}
public async createConversation(
data: CreateMessageConversationParams
): Promise<IMessageConversation> {
if (data.userIdFrom) {
const userFromCheck = await UsersManager.users.findOne({ _id: data.userIdFrom });
if (!userFromCheck) {
throw new Error("Usuario invalido");
}
}
if (data.userIdTo) {
const userToCheck = await UsersManager.users.findOne({ _id: data.userIdTo });
if (!userToCheck) {
throw new Error("Usuario invalido");
}
}
if (data.companyId) {
const companyCheck = await CompaniesManager.companies.findOne({ _id: data.companyId });
if (!companyCheck) {
throw new Error("La compañia no existe");
}
}
const newConversation = await this.conversations.create(data);
return newConversation;
}
public async deleteConversation(data: DeleteMessageConversationParams): Promise<void> {
const checkUser = await UsersManager.users.findOne({ _id: data.sessionUser });
if (!checkUser) {
throw new Error("Usuario invalido");
}
const checkConversation = await this.conversations.conversationList.findOne({
_id: data.id,
});
if (!checkConversation) {
throw new Error("Conversacion invalida");
}
if (checkConversation.type == MESSAGE_CONVERSATION_TYPES.USER_TO_USER) {
if (String(checkConversation.userIdFrom) !== data.sessionUser) {
throw new Error("No tienes permiso para eliminar esta conversacion");
}
} else if (checkConversation.type == MESSAGE_CONVERSATION_TYPES.USER_TO_ORG) {
if (String(checkConversation.userIdFrom) !== data.sessionUser) {
throw new Error("No tienes permiso para eliminar esta conversacion");
}
}
await this.conversations.delete(data.id);
}
public async paginateConversations(
filters: PaginateMessageConversationsParams
): Promise<PaginateMessageConversationsResults> {
return await this.conversations.paginate(filters);
}
private async getUserRelationWithMe(userId: string, sessionUser: string): Promise<string> {
const myOrgs = await EmployeesList.employees.find({ userId: sessionUser });
for (const org of myOrgs) {
const organization = await CompaniesManager.companies.findOne({ _id: org.companyId });
if (!organization) {
continue;
}
//Buscamos si es un colaborador en una de mis organizaciones.
const employee = await EmployeesList.employees.findOne({
userId,
companyId: org.companyId,
});
if (employee) {
return "Colaborador en " + organization.name;
}
//Buscamos si es un cliente en una de mis organizaciones.
const client = await ClientsList.clients.findOne({
userId: userId,
companyId: org.companyId,
});
if (client) {
return "Cliente de " + organization.name;
}
}
const orgsAsClient = await ClientsList.clients.find({
userId: sessionUser,
});
for (const organization of orgsAsClient) {
const checkColaIsCollaborator = await EmployeesList.employees.findOne({
companyId: organization.companyId,
userId: userId,
});
if (checkColaIsCollaborator) {
const org = await CompaniesManager.companies.findOne({
_id: organization.companyId,
});
if (!org) {
continue;
}
return "Miembro de " + org.name;
}
}
return "Otros contactos";
}
public async findConversations(
data: PaginateFindContactsParams
): Promise<FindConversationsResults> {
const items: FindConversationItem[] = [];
const conversations = await this.conversations.paginate(data);
for (const conversation of conversations.data) {
let contactName = "";
let contactUserId: string | undefined = "";
let contactAvatar: string = "";
let conversationName = "";
let conversationDescription = "";
let conversationImage = "";
if (conversation.type == MESSAGE_CONVERSATION_TYPES.USER_TO_USER) {
if (conversation.userIdFrom == data.sessionUser) {
const user = await UserList.users.findOne({ _id: conversation.userIdTo });
if (!user) {
continue;
}
contactName = UserList.getUserFullName(user);
contactUserId = String(conversation.userIdTo);
contactAvatar = user.avatar ? user.avatar : "";
} else if (conversation.userIdTo == data.sessionUser) {
const user = await UserList.users.findOne({ _id: conversation.userIdFrom });
if (!user) {
continue;
}
contactName = UserList.getUserFullName(user);
contactUserId = String(conversation.userIdFrom);
contactAvatar = user.avatar ? user.avatar : "";
}
if (contactUserId) {
conversationName = contactName;
conversationDescription = await this.getUserRelationWithMe(
contactUserId,
data.sessionUser
);
conversationImage = getAvatar(contactUserId, contactAvatar, contactName);
}
} else if (conversation.type == MESSAGE_CONVERSATION_TYPES.USER_TO_ORG) {
if (conversation.userIdFrom == data.sessionUser) {
const org = await CompaniesManager.companies.findOne({
_id: conversation.companyId,
});
if (!org) {
continue;
}
conversationName = org.name;
conversationDescription = org.description;
conversationImage = isNull<string>(org.iconFile, org.name);
} else if (conversation.companyId) {
const user = await UserList.users.findOne({ _id: conversation.userIdFrom });
if (!user) {
continue;
}
conversationName = UserList.getUserFullName(user);
conversationDescription = "Consulta a la organización";
conversationImage = getAvatar(user.id, user.avatar, conversationName);
}
}
let unreadCount = 0;
if (conversation && conversation.id) {
unreadCount = await this.countUnreadMessages({
conversationId: conversation.id,
sessionUser: data.sessionUser,
});
}
items.push({
conversation: {
id: conversation.id,
userIdFrom: conversation.userIdFrom,
userIdTo: conversation.userIdTo,
companyId: conversation.companyId,
type: conversation.type,
newMessages: unreadCount,
},
name: conversationName,
description: conversationDescription,
image: conversationImage,
orderWeight: 1,
});
}
return {
data: items,
page: conversations.page,
pages: conversations.pages,
} as FindConversationsResults;
}
private async getConversationIfExists(
data: GetConversationParams
): Promise<IMessageConversation | null> {
let conversation = await this.conversations.conversationList.findOne({
userIdFrom: data.userId,
});
if (!conversation) {
conversation = await this.conversations.conversationList.findOne({
userIdTo: data.userId,
});
}
return conversation;
}
public async paginateFindContacts(
data: PaginateFindContactsParams
): Promise<PaginateFindContactsResults> {
const items: FindConversationItem[] = [];
//Mostrar las organizaciones en las que el usuario es cliente.
const companiesAsClient = await CompaniesManager.getByClientId({
clientId: data.sessionUser,
sessionUser: data.sessionUser,
});
for (const org of companiesAsClient) {
items.push({
conversation: {
companyId: org.id,
type: MESSAGE_CONVERSATION_TYPES.USER_TO_ORG,
newMessages: 0,
},
name: org.name,
description: org.description,
image: org.logoFile,
orderWeight: 1,
});
//Mostrar los colaboradores de esa organizacion.
const employeesByOrganization = await EmployeesList.findByCompanyId({
companyId: org.id,
});
for (const employee of employeesByOrganization) {
const conversation = await this.getConversationIfExists({
userId: employee.userId,
});
let unreadCount = 0;
if (conversation && conversation.id) {
unreadCount = await this.countUnreadMessages({
conversationId: conversation.id,
sessionUser: data.sessionUser,
});
}
items.push({
conversation: conversation
? ({
id: conversation.id,
userIdFrom: conversation.userIdFrom,
userIdTo: conversation.userIdTo,
companyId: conversation.companyId,
type: conversation.type,
newMessages: unreadCount,
} as IMessageConversation)
: {
userIdTo: employee.userId,
type: MESSAGE_CONVERSATION_TYPES.USER_TO_USER,
newMessages: 0,
},
name: employee.fullName,
description: org.name,
image: employee.avatar,
orderWeight: 2,
});
}
}
//Mostras los clientes y colaboradores de las organizaciones donde el usuario es colaborador.
const companiesAsCollaborator = await EmployeesList.employees.find({
userId: data.sessionUser,
});
for (const org of companiesAsCollaborator) {
const organization = await CompaniesManager.companies.findOne({ _id: org.companyId });
if (!organization) {
continue;
}
//Mostras los clientes de las organizaciones donde el usuario es colaborador.
const organizationClients = await ClientsList.clients.find({
companyId: org.companyId,
});
for (const client of organizationClients) {
if (!client.userId) {
continue;
}
const clientName = ClientsList.getClientFullName(client);
items.push({
conversation: {
userIdFrom: data.sessionUser,
userIdTo: client.userId,
type: MESSAGE_CONVERSATION_TYPES.USER_TO_USER,
newMessages: 0,
},
name: clientName,
description: "Cliente de " + organization.name,
image: getAvatar(client.userId, "", clientName),
orderWeight: 2,
});
}
//Mostrar los colaboradores de las organizaciones donde el usuario es colaborador.
const organizationEmployees = await EmployeesList.employees.find({
companyId: org.companyId,
});
for (const employee of organizationEmployees) {
const employeeUser = await UserList.users.findOne({ _id: employee.userId });
if (!employeeUser) {
continue;
}
if (employee.userId == data.sessionUser) {
continue;
}
const employeeName = UserList.getUserFullName(employeeUser);
items.push({
conversation: {
userIdFrom: data.sessionUser,
userIdTo: employee.userId,
type: MESSAGE_CONVERSATION_TYPES.USER_TO_USER,
newMessages: 0,
},
name: employeeName,
description: "Colaborador en " + organization.name,
image: getAvatar(employee.userId, "", employeeName),
orderWeight: 2,
});
}
}
const query = data.query ? data.query.toUpperCase() : "";
return {
data: items.filter(
(i) =>
String(i.name + i.description)
.toUpperCase()
.indexOf(query) >= 0
),
page: 1,
pages: 1,
} as PaginateFindContactsResults;
}
public async markConversationAsRead(data: MarkConversationAsReadParams): Promise<void> {
const checkUser = await UsersManager.users.findOne({ _id: data.sessionUser });
if (!checkUser) {
throw new Error("Usuario invalido");
}
const checkConversation = await this.conversations.conversationList.findOne({
_id: data.conversationId,
});
if (!checkConversation) {
throw new Error("Conversacion invalida");
}
await MessagesList.markAsRead({
conversationId: data.conversationId,
sessionUser: data.sessionUser,
});
await SystemNoficationsList.deleteConversationNotifications({
conversationId: data.conversationId,
userId: data.sessionUser,
sessionUser: data.sessionUser,
});
}
public async convertUserToUser(data: ConvertU2UMessageConversationParams): Promise<void> {
const checkUser = await UsersManager.users.findOne({ _id: data.sessionUser });
if (!checkUser) {
throw new Error("Usuario invalido");
}
const checkConversation = await this.conversations.conversationList.findOne({
_id: data.conversationId,
});
if (!checkConversation) {
throw new Error("Conversacion invalida");
}
checkConversation.type = MESSAGE_CONVERSATION_TYPES.USER_TO_USER;
checkConversation.userIdTo = data.sessionUser;
await checkConversation.save();
}
public async countUnreadMessages(data: CountUnreadConversationParams): Promise<number> {
const searchCriteria: mongoose.FilterQuery<IMessageConversation> = {};
searchCriteria.conversationId = data.conversationId;
searchCriteria.readed = false;
searchCriteria.userId = { $ne: data.sessionUser };
const unreadMessages = await MessagesList.messages.find(searchCriteria);
return unreadMessages.length;
}
}
const MessageConversationList = new MessageConversationsManager();
export default MessageConversationList;