UNPKG

tuain-ecosystem-lib

Version:

Servicio de gestión mensajería instantanea de la plataforma Tuain

582 lines (551 loc) 26.1 kB
const { ObjectId } = require('mongodb'); const { dbQueries: { users: userQueries }, collections: { thirdParties: thirdPartiesColl, stores: storesColl, users: usersColl, userRelations: userRelationsColl, userGroups: userGroupsColl, userGroupMembers: userGroupMembersColl, usersExtendedData: usersExtendedDataColl, }, } = require('../../config'); const modErrs = { store: { notFound: ['01', 'No se encontró sucursal que se ajuste a la búsqueda'], }, addStoreUser: { thirdPartyDontMatch: ['01', 'Usuario y establecimiento no pertenecen al mismo tercero'], userAndStoreRelated: ['02', 'Usuario y establecimiento ya están relacionados'], }, removeStoreUser: { notRelated: ['01', 'Usuario y establecimiento no están relacionados'], }, addThirdPartyUser: { thirdPartyDontMatch: ['01', 'Usuario está relacionado con un tercero diferente'], alreadyRelated: ['02', 'Usuario ya está relacionado con tercero'], }, removeThirdPartyUser: { notRelated: ['01', 'Usuario y tercero no están relacionados'], hasStoresRelation: ['02', 'Usuario cuenta con relación con establecimiento'], }, findingGroup: { notFound: ['01', 'No se encontraron grupos que se ajusten a la búsqueda'], alreadyActive: ['02', 'Grupo ya está activo'], alreadyInactive: ['03', 'Grupo ya está inactivo'], emptyGroup: ['04', 'Grupo no tiene miembros'], }, findingUser: { notFound: ['01', 'No se encontraron usuarios que se ajusten a la búsqueda'], }, createGroup: { alreadyExist: ['01', 'Grupo ya existe'], }, userToGroup: { alreadyExist: ['01', 'Usuario ya vinculado al grupo'], notFound: ['02', 'Usuario no vinculado al grupo'], }, }; class UserManager { constructor(getDb, logger, errMgr, options) { this.options = options; this.getDb = getDb; this.logger = logger; this.errMgr = errMgr; this.errMgr.addModuleSet('lib-users', modErrs); } // async getStoreUsers(reqData) { // const { networkId, storeId } = reqData; // const storeCol = this.getDb().collection(storesColl); // const store = await storeCol.find(userQueries.findById(storeId), { users: 1 }); // if (!store) { // const errorDetail = `Sucursal con Id ${storeId} no encontrado`; // const errorObj = this.errMgr.get(modErrs.store.notFound, errorDetail); // return [errorObj, null]; // } // return [null, store]; // } async getStoreUsers(reqData) { const { thirdPartyId, storeId } = reqData; // Se localiza el establecimiento const thirdCol = this.getDb().collection(thirdPartiesColl); const thirdParty = await thirdCol.findOne(userQueries.findById(thirdPartyId)); if (!thirdParty) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.store.notFound, errorDetail); return [errorObj, null]; } // Se valida si el usuario tiene relación con el tercero const userRelationsCol = this.getDb().collection(userRelationsColl); const userRelations = await userRelationsCol.findOne(userQueries.findByUserId(userId)); if (userRelations) { if (userRelations.thirdPartyId.toString() !== thirdPartyId) { // El usuario ya cuenta con relacion en el ecosistema con un tercero diferente const errorDetail = `Usuario ${userId} ya está relacionado con on tercero diferente `; const errorObj = this.errMgr.get(modErrs.addThirdPartyUser.thirdPartyDontMatch, errorDetail); return [errorObj, null]; } if (userRelations.thirdPartyId.toString() === thirdPartyId) { // El usuario ya cuenta con relacion en el ecosistema con el tercero const errorDetail = `Usuario ${userId} ya está relacionado con el tercero`; const errorObj = this.errMgr.get(modErrs.addThirdPartyUser.alreadyRelated, errorDetail); return [errorObj, null]; } } const actionResult = await userRelationsCol.insertOne({ userId: ObjectId(userId), thirdPartyId: ObjectId(thirdPartyId), }); const result = !!actionResult?.insertedId; return [null, { result }]; } async addStoreUser(reqData) { const { storeId, userId } = reqData; // Se localiza el establecimiento const storesCol = this.getDb().collection(storesColl); const store = await storesCol.findOne(userQueries.findById(storeId)); if (!store) { const errorDetail = `Establecimiento ${storeId} no encontrado`; const errorObj = this.errMgr.get(modErrs.store.notFound, errorDetail); return [errorObj, null]; } // Se valida si el usuario tiene relación con un tercero const userRelationsCol = this.getDb().collection(userRelationsColl); const userRelations = await userRelationsCol.findOne(userQueries.findByUserId(userId)); if (userRelations) { if (userRelations.thirdPartyId.toString() !== store.thirdPartyId.toString()) { // El usuario ya cuenta con relaciones en el ecosistema con un tercero diferente const errorDetail = `Establecimiento ${storeId} pertenece a un tercero diferente al del usuario ${userId}`; const errorObj = this.errMgr.get(modErrs.addStoreUser.thirdPartyDontMatch, errorDetail); return [errorObj, null]; } const existingStore = userRelations.stores?.find((sto) => sto.storeId === storeId) ?? null; if (existingStore) { const errorDetail = `Usuario ${userId} ya pertenece al establecimiento ${storeId}`; const errorObj = this.errMgr.get(modErrs.addStoreUser.userAndStoreRelated, errorDetail); return [errorObj, null]; } } const storeType = store?.storeType; let result; if (userRelations) { const userRelationId = userRelations?._id; const updateResult = await userRelationsCol.updateOne(userQueries.findById(userRelationId), { $addToSet: { stores: { storeId, storeType } }, }); result = updateResult?.result?.nModified > 0; } else { const actionResult = await userRelationsCol.insertOne( userQueries.insertUserRelation(userId, store.thirdPartyId, storeId, storeType), ); result = !!actionResult?.insertedId; } return [null, { result }]; } async removeStoreUser(reqData) { const { storeId, userId } = reqData; const storesCol = this.getDb().collection(storesColl); const store = await storesCol.findOne(userQueries.findById(storeId)); if (!store) { const errorDetail = `Sucursal con Id ${storeId} no encontrada`; const errorObj = this.errMgr.get(modErrs.store.notFound, errorDetail); return [errorObj, null]; } const userRelationsCol = this.getDb().collection(userRelationsColl); const userRelations = await userRelationsCol.findOne(userQueries.findByUserId(userId)); const userRelationId = userRelations?._id; const existingStore = userRelations?.stores.find((sto) => sto.storeId === storeId) ?? null; if (!existingStore) { const errorDetail = `Sucursal ${storeId} no relacionada con el usuario ${userId}`; const errorObj = this.errMgr.get(modErrs.removeStoreUser.notRelated, errorDetail); return [errorObj, null]; } // { $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } } const updateResult = await userRelationsCol.updateOne( userQueries.findById(userRelationId), userQueries.removeStoreFromUser(storeId), ); const result = updateResult?.result?.nModified > 0; return [null, { result }]; } async removeStoresUser(reqData) { const { userId } = reqData; const userRelationsCol = this.getDb().collection(userRelationsColl); const userRelations = await userRelationsCol.findOne(userQueries.findByUserId(userId)); const userRelationId = userRelations?._id; let updateResult; if (userRelationId) { updateResult = await userRelationsCol.updateOne(userQueries.findById(userRelationId), userQueries.removeStoresFromUser()); } const result = updateResult?.result?.nModified > 0; return [null, { result }]; } async addThirdPartyUser(reqData) { const { thirdPartyId, userId } = reqData; // Se localiza el establecimiento const thirdCol = this.getDb().collection(thirdPartiesColl); const thirdParty = await thirdCol.findOne(userQueries.findById(thirdPartyId)); if (!thirdParty) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.store.notFound, errorDetail); return [errorObj, null]; } // Se valida si el usuario tiene relación con el tercero const userRelationsCol = this.getDb().collection(userRelationsColl); const userRelations = await userRelationsCol.findOne(userQueries.findByUserId(userId)); if (userRelations) { if (userRelations.thirdPartyId.toString() !== thirdPartyId) { // El usuario ya cuenta con relacion en el ecosistema con un tercero diferente const errorDetail = `Usuario ${userId} ya está relacionado con on tercero diferente `; const errorObj = this.errMgr.get(modErrs.addThirdPartyUser.thirdPartyDontMatch, errorDetail); return [errorObj, null]; } if (userRelations.thirdPartyId.toString() === thirdPartyId) { // El usuario ya cuenta con relacion en el ecosistema con el tercero const errorDetail = `Usuario ${userId} ya está relacionado con el tercero`; const errorObj = this.errMgr.get(modErrs.addThirdPartyUser.alreadyRelated, errorDetail); return [errorObj, null]; } } const actionResult = await userRelationsCol.insertOne({ userId: ObjectId(userId), thirdPartyId: ObjectId(thirdPartyId), }); const result = !!actionResult?.insertedId; return [null, { result }]; } async removeThirdPartyUser(reqData) { const { thirdPartyId, userId } = reqData; const thirdCol = this.getDb().collection(thirdPartiesColl); const thirdParty = await thirdCol.findOne(userQueries.findById(thirdPartyId)); if (!thirdParty) { const errorDetail = `Tercero con Id ${thirdPartyId} no encontrado`; const errorObj = this.errMgr.get(modErrs.store.notFound, errorDetail); return [errorObj, null]; } const userRelationsCol = this.getDb().collection(userRelationsColl); const userRelations = await userRelationsCol.findOne(userQueries.findByUserId(userId)); const userRelationId = userRelations?._id; if (!userRelations || userRelations?.thirdPartyId.toString() !== thirdPartyId) { const errorDetail = `Usuario ${userId} no está relacionado con el tercero ${thirdPartyId}`; const errorObj = this.errMgr.get(modErrs.removeThirdPartyUser.notRelated, errorDetail); return [errorObj, null]; } if (userRelations?.stores?.length > 0) { const errorDetail = `Usuario ${userId} tiene relación con ${userRelations?.stores?.length} establecimiento(s)`; const errorObj = this.errMgr.get(modErrs.removeThirdPartyUser.hasStoresRelation, errorDetail); return [errorObj, null]; } const deleteResult = await userRelationsCol.deleteOne(userQueries.findById(userRelationId)); const result = deleteResult?.result?.nDeleted > 0 ?? null; return [null, { result }]; } /** * Grupos de usuarios */ async findGroups(groupData, constraints) { const pageNumber = constraints?.requestedPage || 1; const recordsPerPage = constraints?.recordsPerPage || 50; // const currentFilter = constraints.currentFilter; const userGroupsCol = this.getDb().collection(userGroupsColl); const users = await userGroupsCol .find() .skip(recordsPerPage * (pageNumber - 1)) .limit(recordsPerPage) .toArray(); return [null, users]; } async findGroup(reqData) { const { groupId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo ${groupId} no fue encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groupDetail]; } async createGroup(groupData) { const { ownerId, name } = groupData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findGroup(ownerId, name)); if (groupDetail) { const errorDetail = `Grupo ${name} ya existe para el propietario ${ownerId}`; const errorObj = this.errMgr.get(modErrs.createGroup.alreadyExist, errorDetail); return [errorObj, null]; } const newGroupData = { ...groupData, creationDate: new Date(), }; const actionResult = await userGroupsCol.insertOne(userQueries.saveGroup(newGroupData)); this.logger.debug(`Creación de un nuevo grupo ${groupData} con resultado ${actionResult?.insertedId}`); return [null, { groupId: actionResult?.insertedId }]; } async modifyGroup(reqData) { const { groupId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const updateData = { ...reqData }; delete updateData.groupId; const actionResult = await userGroupsCol.updateOne(userQueries.findById(groupId), userQueries.updateGroup(updateData)); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Modificación de grupo ${groupId} con resultado ${result}`); return [null, { result }]; } async activateGroup(reqData) { const { groupId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (groupDetail.enabled) { const errorDetail = `Grupo con Id ${groupId} actualmente activo`; const errorObj = this.errMgr.get(modErrs.findingGroup.alreadyActive, errorDetail); return [errorObj, null]; } const actionResult = await userGroupsCol.updateOne(userQueries.findById(groupId), userQueries.updateObj({ enabled: true })); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Activación del grupo ${groupId} con reultado ${result}`); return [null, { result }]; } async getUserGroupByOwner(groupData) { const { ownerId, name, groupType } = groupData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findGroup(ownerId, name, groupType)); if (!groupDetail) { const errorDetail = `No se encontró grupo con ese dueño y nombre ${name}`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groupDetail]; } async getUserGroupsByOwner(groupData) { const { ownerId, groupType } = groupData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groups = await userGroupsCol.find(userQueries.findOwnerGroups(ownerId, groupType)).toArray(); if (!groups || groups.length < 1) { const errorDetail = `No se encontraron grupos con dueño ${ownerId}`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groups]; } async findUserGroups(groupData) { const { userId } = groupData; const groupMembersCol = this.getDb().collection(userGroupMembersColl); const groups = await groupMembersCol.aggregate(userQueries.findUserGroups(userId)).toArray(); if (!groups || groups.length === 0) { const errorDetail = `No se encontraon grupos con ${userId} en los miembros`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } return [null, groups]; } async inactivateGroup(reqData) { const { groupId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (!groupDetail.enabled) { const errorDetail = `Grupo con Id ${groupId} actualmente inactivo`; const errorObj = this.errMgr.get(modErrs.findingGroup.alreadyInactive, errorDetail); return [errorObj, null]; } const actionResult = await userGroupsCol.updateOne(userQueries.findById(groupId), userQueries.updateObj({ enabled: false })); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Activación del grupo ${groupId} con reultado ${result}`); return [null, { result }]; } async deleteGroup(reqData) { const { groupId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (groupDetail.enabled) { const errorDetail = `Grupo con Id ${groupId} actualmente activo`; const errorObj = this.errMgr.get(modErrs.findingGroup.alreadyActive, errorDetail); return [errorObj, null]; } const actionResult = await userGroupsCol.deleteOne(userQueries.findById(groupId)); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación del grupo ${groupId} con resultado ${result}`); return [null, { result }]; } async existUserGroup(userId, groupId) { const membersCol = this.getDb().collection(userGroupMembersColl); const memberDetail = await membersCol.findOne(userQueries.findUserGroup(userId, groupId)); return memberDetail !== null && memberDetail !== undefined; } async addUserToGroup(reqData) { const { groupId, userId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const existingThirdGroup = await this.existUserGroup(userId, groupId); if (existingThirdGroup) { const errorDetail = `Usuario con Id ${userId} ya existe en el grupo con Id ${groupId}`; const errorObj = this.errMgr.get(modErrs.userToGroup.alreadyExist, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(userGroupMembersColl); const actionResult = await membersCol.insertOne(userQueries.newGroupMember(reqData)); this.logger.debug(`Adición del usuario ${userId} al grupo ${groupId} con resultado ${actionResult?.insertedId}`); return [null, { membershipId: actionResult?.insertedId }]; } async getUserGroupMembers(reqData) { const { groupId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const groupDetail = await userGroupsCol.findOne(userQueries.findById(groupId)); if (!groupDetail) { const errorDetail = `Grupo con Id ${groupId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(userGroupMembersColl); const groupMembers = await membersCol.find(userQueries.findGroupMembers(groupId)).toArray(); if (!groupMembers || groupMembers?.length === 0) { const errorDetail = `Grupo con Id ${groupId} vacío`; const errorObj = this.errMgr.get(modErrs.findingGroup.emptyGroup, errorDetail); return [errorObj, null]; } return [null, groupMembers]; } async getUserGroupsMembersByOwner(reqData) { const { ownerId, groupType } = reqData; let message; const userGroupsCol = this.getDb().collection(userGroupsColl); const groups = await userGroupsCol.find(userQueries.findGroupIdsByOwner(ownerId, groupType)).toArray(); if (!groups || groups.length === 0) { message = `No existen grupos de ${ownerId}`; if (groupType) { message += ` de tipo ${groupType}`; } const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, message); return [errorObj, null]; } const groupIds = groups.map((grp) => grp._id); const membersCol = this.getDb().collection(userGroupMembersColl); const groupsMembers = await membersCol.aggregate(userQueries.findUserGroupsMembers(groupIds)).toArray(); if (!groupsMembers || groupsMembers?.length === 0) { message = 'Grupos sin miembros'; const errorObj = this.errMgr.get(modErrs.findingGroup.emptyGroup, message); return [errorObj, null]; } return [null, groupsMembers]; } async deleteUserFromGroup(reqData) { const { membershipId, groupId, userId } = reqData; const membersCol = this.getDb().collection(userGroupMembersColl); const membershipQuery = membershipId ? userQueries.findById(membershipId) : { groupId: ObjectId(groupId), userId: ObjectId(userId) }; const membershipDetail = await membersCol.findOne(membershipQuery); if (!membershipDetail) { const errorDetail = `No existe membresía a grupo con Id ${membershipId}`; const errorObj = this.errMgr.get(modErrs.userToGroup.notFound, errorDetail); return [errorObj, null]; } const membershipIdFound = membershipDetail?._id; const actionResult = await membersCol.deleteOne(userQueries.findById(membershipIdFound)); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación de membreía ${membershipId} con resultado ${result}`); return [null, { result }]; } async deleteUserFromGroups(reqData) { const { userId } = reqData; const membersCol = this.getDb().collection(userGroupMembersColl); const actionResult = await membersCol.deleteMany({ userId: ObjectId(userId) }); const result = actionResult?.result?.n > 0; this.logger.debug(`Eliminación de membresías de ${userId} con resultado ${result}`); return [null, { result }]; } async moveGroupMembers(reqData) { const { sourceGroupId, destinationGroupId } = reqData; const userGroupsCol = this.getDb().collection(userGroupsColl); const sourceGroupDetailPrms = userGroupsCol.findOne(userQueries.findById(sourceGroupId)); const destGroupDetailPrms = userGroupsCol.findOne(userQueries.findById(destinationGroupId)); const [sourceGroupDetail, destGroupDetail] = await Promise.all([sourceGroupDetailPrms, destGroupDetailPrms]); if (!sourceGroupDetail) { const errorDetail = `Grupo con Id ${sourceGroupDetail} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } if (!destGroupDetail) { const errorDetail = `Grupo con Id ${destGroupDetail} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingGroup.notFound, errorDetail); return [errorObj, null]; } const membersCol = this.getDb().collection(userGroupMembersColl); const actionResult = await membersCol.update( userQueries.findMembers(sourceGroupId), userQueries.updateObj({ groupId: destinationGroupId }), ); const result = actionResult?.result?.nModified > 0; this.logger.debug(`Movimiento de miembros de grupo ${sourceGroupId} hacia ${destinationGroupId} con resultado ${result}`); return [null, { result }]; } async addUserExtendedData(reqData) { const { userId } = reqData; const usersExtendedDataCol = this.getDb().collection(usersExtendedDataColl); const usersCol = this.getDb().collection(usersColl); const userDetail = await usersCol.findOne(userQueries.findById(userId)); if (!userDetail) { const errorDetail = `Usuario con Id ${userId} no encontrado`; const errorObj = this.errMgr.get(modErrs.findingUser.notFound, errorDetail); return [errorObj, null]; } const extendedData = { ...reqData }; delete extendedData.userId; const usersExtendedData = await usersExtendedDataCol.findOne({ userId: ObjectId(userId) }); let usersExtendedDataId = 0; if (!usersExtendedData) { const actionResult = await usersExtendedDataCol.insertOne({ userId: ObjectId(userId), ...extendedData, }); usersExtendedDataId = actionResult?.insertedId; } else { const updateResult = await usersExtendedDataCol.updateOne({ userId: ObjectId(userId) }, { $set: { ...extendedData } }); usersExtendedDataId = updateResult?.result?.nModified > 0 ? usersExtendedData?._id : 0; } return [null, { usersExtendedDataId }]; } async getUserExtendedData(reqData) { const { userId, userData } = reqData; const usersExtendedDataCol = this.getDb().collection(usersExtendedDataColl); const extendedDataQuery = { userId: ObjectId(userId) }; const usersExtendedData = (await usersExtendedDataCol.findOne(extendedDataQuery)) ?? {}; if (!usersExtendedData) { return [null, null]; } delete usersExtendedData.userId; if (userData) { return [null, usersExtendedData?.[userData] ?? {}]; } return [null, usersExtendedData]; } } module.exports = UserManager;