diff --git a/src/adapters/notifications/NotificationCenterAdapter.ts b/src/adapters/notifications/NotificationCenterAdapter.ts index 7640e36bc..0dc6c0e05 100644 --- a/src/adapters/notifications/NotificationCenterAdapter.ts +++ b/src/adapters/notifications/NotificationCenterAdapter.ts @@ -10,8 +10,8 @@ import { NOTIFICATIONS_EVENT_NAMES } from '../../analytics/analytics'; import Bull from 'bull'; import { redisConfig } from '../../redis'; import config from '../../config'; -import { findUsersWhoDonatedToProject } from '../../repositories/donationRepository'; -import { findUsersWhoLikedProject } from '../../repositories/reactionRepository'; +import { findUsersWhoDonatedToProjectExcludeWhoLiked } from '../../repositories/donationRepository'; +import { findUsersWhoLikedProjectExcludeProjectOwner } from '../../repositories/reactionRepository'; import { findUsersWhoBoostedProject } from '../../repositories/powerBoostingRepository'; const notificationCenterUsername = process.env.NOTIFICATION_CENTER_USERNAME; const notificationCenterPassword = process.env.NOTIFICATION_CENTER_PASSWORD; @@ -355,7 +355,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { async projectCancelled(params: { project: Project }): Promise { const { project } = params; - const donors = await findUsersWhoDonatedToProject(project.id); + const donors = await findUsersWhoDonatedToProjectExcludeWhoLiked( + project.id, + ); donors.map(user => sendProjectRelatedNotificationsQueue.add({ project, @@ -364,7 +366,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { }), ); - const usersWhoLiked = await findUsersWhoLikedProject(project.id); + const usersWhoLiked = await findUsersWhoLikedProjectExcludeProjectOwner( + project.id, + ); usersWhoLiked.map(user => sendProjectRelatedNotificationsQueue.add({ project, @@ -394,7 +398,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { }): Promise { const { project, update } = params; - const donors = await findUsersWhoDonatedToProject(project.id); + const donors = await findUsersWhoDonatedToProjectExcludeWhoLiked( + project.id, + ); donors.map(user => sendProjectRelatedNotificationsQueue.add({ project, @@ -403,7 +409,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { }), ); - const usersWhoLiked = await findUsersWhoLikedProject(project.id); + const usersWhoLiked = await findUsersWhoLikedProjectExcludeProjectOwner( + project.id, + ); usersWhoLiked.map(user => sendProjectRelatedNotificationsQueue.add({ project, @@ -433,7 +441,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { async projectDeListed(params: { project: Project }): Promise { const { project } = params; - const donors = await findUsersWhoDonatedToProject(project.id); + const donors = await findUsersWhoDonatedToProjectExcludeWhoLiked( + project.id, + ); donors.map(user => sendProjectRelatedNotificationsQueue.add({ project, @@ -442,7 +452,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { }), ); - const usersWhoLiked = await findUsersWhoLikedProject(project.id); + const usersWhoLiked = await findUsersWhoLikedProjectExcludeProjectOwner( + project.id, + ); usersWhoLiked.map(user => sendProjectRelatedNotificationsQueue.add({ project, @@ -475,7 +487,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { const metadata = { reason, }; - const donors = await findUsersWhoDonatedToProject(project.id); + const donors = await findUsersWhoDonatedToProjectExcludeWhoLiked( + project.id, + ); donors.map(user => sendProjectRelatedNotificationsQueue.add({ project, @@ -485,7 +499,9 @@ export class NotificationCenterAdapter implements NotificationAdapterInterface { }), ); - const usersWhoLiked = await findUsersWhoLikedProject(project.id); + const usersWhoLiked = await findUsersWhoLikedProjectExcludeProjectOwner( + project.id, + ); usersWhoLiked.map(user => sendProjectRelatedNotificationsQueue.add({ project, diff --git a/src/repositories/donationRepository.test.ts b/src/repositories/donationRepository.test.ts index f0a377e1f..fd16f88ad 100644 --- a/src/repositories/donationRepository.test.ts +++ b/src/repositories/donationRepository.test.ts @@ -14,8 +14,9 @@ import { createDonation, findDonationById, findDonationsByTransactionId, - findUsersWhoDonatedToProject, + findUsersWhoDonatedToProjectExcludeWhoLiked, } from './donationRepository'; +import { Reaction } from '../entities/reaction'; describe('createDonation test cases', () => { it('should create donation ', async () => { @@ -58,7 +59,7 @@ describe( ); describe('findDonationById() test cases', findDonationByIdTestCases); describe( - 'findUsersWhoDonatedToProject() test cases', + 'findUsersWhoDonatedToProjectExcludeWhoLiked() test cases', findUsersWhoDonatedToProjectTestCases, ); @@ -127,24 +128,36 @@ function findDonationByIdTestCases() { } function findUsersWhoDonatedToProjectTestCases() { - it('should find wallet addresses of who donated to a project', async () => { + it('should find wallet addresses of who donated to a project, exclude who liked', async () => { const project = await saveProjectDirectlyToDb(createProjectData()); const donor1 = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); const donor2 = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); - const donor3 = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); + const whoLiked = await saveUserDirectlyToDb( + generateRandomEtheriumAddress(), + ); + await Reaction.create({ + project, + userId: whoLiked.id, + reaction: 'heart', + }).save(); await saveDonationDirectlyToDb(createDonationData(), donor1.id, project.id); await saveDonationDirectlyToDb(createDonationData(), donor2.id, project.id); - await saveDonationDirectlyToDb(createDonationData(), donor3.id, project.id); - const users = await findUsersWhoDonatedToProject(project.id); - assert.equal(users.length, 3); + await saveDonationDirectlyToDb( + createDonationData(), + whoLiked.id, + project.id, + ); + + const users = await findUsersWhoDonatedToProjectExcludeWhoLiked(project.id); + assert.equal(users.length, 2); assert.isOk( users.find(user => user.walletAddress === donor1.walletAddress), ); assert.isOk( users.find(user => user.walletAddress === donor2.walletAddress), ); - assert.isOk( - users.find(user => user.walletAddress === donor3.walletAddress), + assert.notOk( + users.find(user => user.walletAddress === whoLiked.walletAddress), ); }); it('should find wallet addresses of who donated to a project, not include repetitive items', async () => { @@ -159,7 +172,7 @@ function findUsersWhoDonatedToProjectTestCases() { await saveDonationDirectlyToDb(createDonationData(), donor2.id, project.id); await saveDonationDirectlyToDb(createDonationData(), donor3.id, project.id); await saveDonationDirectlyToDb(createDonationData(), donor3.id, project.id); - const users = await findUsersWhoDonatedToProject(project.id); + const users = await findUsersWhoDonatedToProjectExcludeWhoLiked(project.id); assert.equal(users.length, 3); assert.isOk( users.find(user => user.walletAddress === donor1.walletAddress), diff --git a/src/repositories/donationRepository.ts b/src/repositories/donationRepository.ts index 2444e6736..3cd68638f 100644 --- a/src/repositories/donationRepository.ts +++ b/src/repositories/donationRepository.ts @@ -1,6 +1,8 @@ import { Project } from '../entities/project'; import { Donation } from '../entities/donation'; import { ResourcesTotalPerMonthAndYear } from '../resolvers/donationResolver'; +import { User } from '../entities/user'; +import { Reaction } from '../entities/reaction'; export const createDonation = async (data: { amount: number; @@ -74,16 +76,23 @@ export const findDonationById = async ( .getOne(); }; -export const findUsersWhoDonatedToProject = async ( +export const findUsersWhoDonatedToProjectExcludeWhoLiked = async ( projectId: number, ): Promise<{ walletAddress: string; email?: string }[]> => { return Donation.createQueryBuilder('donation') + .leftJoinAndSelect('donation.project', 'project') .leftJoin('donation.user', 'user') + .leftJoin( + Reaction, + 'reaction', + 'reaction.projectId = project.id AND user.id = reaction.userId', + ) .distinctOn(['user.walletAddress']) .select('LOWER(user.walletAddress) AS "walletAddress", user.email as email') - .where(`"projectId"=:projectId`, { + .where(`donation."projectId"=:projectId`, { projectId, }) + .andWhere(`reaction.id IS NULL`) .getRawMany(); }; diff --git a/src/repositories/powerBoostingRepository.test.ts b/src/repositories/powerBoostingRepository.test.ts index 04c80b5a6..ce4e55a5c 100644 --- a/src/repositories/powerBoostingRepository.test.ts +++ b/src/repositories/powerBoostingRepository.test.ts @@ -22,7 +22,7 @@ import { PowerSnapshot } from '../entities/powerSnapshot'; import { PowerBoostingSnapshot } from '../entities/powerBoostingSnapshot'; import { getConnection } from 'typeorm'; import { Reaction } from '../entities/reaction'; -import { findUsersWhoLikedProject } from './reactionRepository'; +import { findUsersWhoLikedProjectExcludeProjectOwner } from './reactionRepository'; import { errorMessages } from '../utils/errorMessages'; describe('findUserPowerBoosting() testCases', findUserPowerBoostingTestCases); diff --git a/src/repositories/reactionRepository.test.ts b/src/repositories/reactionRepository.test.ts index 4e80c2444..8d97e269e 100644 --- a/src/repositories/reactionRepository.test.ts +++ b/src/repositories/reactionRepository.test.ts @@ -5,11 +5,11 @@ import { saveUserDirectlyToDb, } from '../../test/testUtils'; import { assert } from 'chai'; -import { findUsersWhoLikedProject } from './reactionRepository'; +import { findUsersWhoLikedProjectExcludeProjectOwner } from './reactionRepository'; import { Reaction } from '../entities/reaction'; describe( - 'findUsersWhoLikedProject() test cases', + 'findUsersWhoLikedProjectExcludeProjectOwner() test cases', findUsersWhoLikedProjectTestCases, ); @@ -41,7 +41,7 @@ function findUsersWhoLikedProjectTestCases() { reaction: 'heart', }).save(); - const users = await findUsersWhoLikedProject(project.id); + const users = await findUsersWhoLikedProjectExcludeProjectOwner(project.id); assert.equal(users.length, 3); assert.isOk( users.find(user => user.walletAddress === firstUser1.walletAddress), @@ -53,4 +53,41 @@ function findUsersWhoLikedProjectTestCases() { users.find(user => user.walletAddress === firstUser3.walletAddress), ); }); + it('should find wallet addresses of who liked to a project, exclude project owner', async () => { + const admin = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); + const project = await saveProjectDirectlyToDb(createProjectData(), admin); + const firstUser1 = await saveUserDirectlyToDb( + generateRandomEtheriumAddress(), + ); + const firstUser2 = await saveUserDirectlyToDb( + generateRandomEtheriumAddress(), + ); + await Reaction.create({ + project, + userId: firstUser1.id, + reaction: 'heart', + }).save(); + await Reaction.create({ + project, + userId: firstUser2.id, + reaction: 'heart', + }).save(); + await Reaction.create({ + project, + userId: admin.id, + reaction: 'heart', + }).save(); + + const users = await findUsersWhoLikedProjectExcludeProjectOwner(project.id); + assert.equal(users.length, 2); + assert.isOk( + users.find(user => user.walletAddress === firstUser1.walletAddress), + ); + assert.isOk( + users.find(user => user.walletAddress === firstUser2.walletAddress), + ); + assert.isNotOk( + users.find(user => user.walletAddress === admin.walletAddress), + ); + }); } diff --git a/src/repositories/reactionRepository.ts b/src/repositories/reactionRepository.ts index 43220eef0..edf0b1639 100644 --- a/src/repositories/reactionRepository.ts +++ b/src/repositories/reactionRepository.ts @@ -1,14 +1,23 @@ import { Reaction } from '../entities/reaction'; import { User } from '../entities/user'; -export const findUsersWhoLikedProject = async ( +export const findUsersWhoLikedProjectExcludeProjectOwner = async ( projectId: number, ): Promise<{ walletAddress: string; email?: string }[]> => { return Reaction.createQueryBuilder('reaction') .leftJoin(User, 'user', 'reaction.userId = user.id') - .select('LOWER(user.walletAddress) AS "walletAddress", user.email as email') + .leftJoinAndSelect('reaction.project', 'project') + .leftJoinAndSelect( + User, + 'projectOwner', + 'project.adminUserId = projectOwner.id', + ) + .select( + 'LOWER(user.walletAddress) AS "walletAddress", user.email as email, projectOwner.id as ownerId', + ) .where(`"projectId"=:projectId`, { projectId, }) + .andWhere(`user.id != projectOwner.id`) .getRawMany(); };