Skip to content

Commit

Permalink
emit an event when product is created to notify users
Browse files Browse the repository at this point in the history
  • Loading branch information
radekm2000 committed Jun 8, 2024
1 parent 0d13db9 commit c364226
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 62 deletions.
9 changes: 6 additions & 3 deletions server/ecommerce/src/discord-bot/discord-bot.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ import { Product } from 'src/utils/entities/product.entity';
import { ProductNotificationService } from 'src/product-notification/product-notification.service';
import { ProductNotification } from 'src/utils/entities/product-notification.entity';
import { FollowersService } from 'src/followers/followers.service';
import { ItemNotifierService } from './src/commands/notifiers/item-notifier.service';
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';
import { IProductsService } from 'src/spi/products';
import { DiscordGuildModule } from 'src/discord-guild/discord-guild.module';
import { DiscordGuildService } from 'src/discord-guild/discord-guild.service';
import { DiscordNotificationsModule } from 'src/discord-notifications/discord-notifications.module';
import { ProductsModule } from 'src/products/products.module';
import { ItemNotifierModule } from './src/commands/notifiers/item-notifier.module';
import { ProductNotificationModule } from 'src/product-notification/product-notification.module';

@Module({
controllers: [DiscordBotController],
providers: [
DiscordBotService,
UsersService,
{ provide: IProductsService, useClass: ProductsService },
ProductNotificationService,
FollowersService,
ItemNotifierService,
],

imports: [
Expand All @@ -41,7 +41,10 @@ import { DiscordNotificationsModule } from 'src/discord-notifications/discord-no
Product,
ProductNotification,
]),
ProductsModule,
ItemNotifierModule,
DiscordNotificationsModule,
ProductNotificationModule,
],
exports: [DiscordBotService],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Module } from '@nestjs/common';
import { Module, forwardRef } from '@nestjs/common';
import { ItemNotifierService } from './item-notifier.service';
import { UsersService } from 'src/users/users.service';
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';
Expand All @@ -10,6 +10,9 @@ import { Avatar } from 'src/utils/entities/avatar.entity';
import { Product } from 'src/utils/entities/product.entity';
import { ProductNotification } from 'src/utils/entities/product-notification.entity';
import { DiscordNotificationsModule } from 'src/discord-notifications/discord-notifications.module';
import { ProductsModule } from 'src/products/products.module';
import { ItemNotifier } from './item-notifier';
import { UsersModule } from 'src/users/users.module';

@Module({
imports: [
Expand All @@ -22,8 +25,10 @@ import { DiscordNotificationsModule } from 'src/discord-notifications/discord-no
ProductNotification,
]),
DiscordNotificationsModule,
forwardRef(() => ProductsModule),
UsersModule,
],
providers: [ItemNotifierService, UsersService],
providers: [ItemNotifierService, ItemNotifier],
exports: [ItemNotifierService],
})
export class ItemNotifierModule {}
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import { Injectable } from '@nestjs/common';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { ItemNotifier } from './item-notifier';
import { UsersService } from 'src/users/users.service';
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';
import { Product } from 'src/utils/entities/product.entity';
import { OnEvent } from '@nestjs/event-emitter';
import { GeneralEvents } from 'src/events/constants/events';
import { ProductsService } from 'src/products/products.service';
import { IProductsService } from 'src/spi/products';

@Injectable()
export class ItemNotifierService {
private readonly itemNotifier: ItemNotifier;
private logger: Logger;

constructor(
private usersService: UsersService,
private discordNotificationsService: DiscordNotificationsService,
@Inject(ItemNotifier) private readonly itemNotifier: ItemNotifier,
) {
this.itemNotifier = new ItemNotifier({
bot: this.discordNotificationsService.discordNotificationsBot,
usersService: this.usersService,
});
this.logger = new Logger(ItemNotifierService.name);
}

public notifyUsers = async (userId: number, product: Product) => {
return await this.itemNotifier.notifyUsers(userId, product);
};
@OnEvent(GeneralEvents.ProductCreated, { async: true })
public async notifyUsers(product: Product) {
this.logger.log(`${ItemNotifierService.name} recieved an event`);

try {
await this.itemNotifier.notifyUsers(product);
} catch (error) {
this.logger.error(error.message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import { Avatar } from 'src/utils/entities/avatar.entity';
import { Message } from 'src/utils/entities/message.entity';
import { Review } from 'src/utils/entities/review.entity';
import { EmbedBuilder } from 'discord.js';
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { DiscordNotificationsBot } from 'src/discord-notifications/discord-notifications-bot';
import { IProductsService } from 'src/spi/products';
import { ProductsService } from 'src/products/products.service';
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';

type User = {
followings: Follow[];
Expand All @@ -30,24 +33,27 @@ type User = {

type Config = {
bot: DiscordNotificationsBot;
productsService: IProductsService;
usersService: UsersService;
};

@Injectable()
export class ItemNotifier {
private readonly usersService: UsersService;
private readonly bot: DiscordNotificationsBot;
constructor(
@Inject(UsersService) private usersService: UsersService,
@Inject(IProductsService) private productsService: IProductsService,
@Inject(DiscordNotificationsService)
private discordNotificationService: DiscordNotificationsService,
) {}

constructor(config: Config) {
this.bot = config.bot;
this.usersService = config.usersService;
}

public notifyUsers = async (userId: number, product: Product) => {
const user = await this.usersService.getUserInfo(userId);
public notifyUsers = async (product: Product) => {
const existingProductWithImage = await this.productsService.findProduct(
product.id,
);
const user = await this.usersService.getUserInfo(product.user.id);
const usersToNotify = await this.getUsersToNotify(user);

await this.notify(usersToNotify, product);
await this.notify(usersToNotify, existingProductWithImage);
};

private getUsersToNotify = async (user: User) => {
Expand All @@ -62,7 +68,7 @@ export class ItemNotifier {
const productAuthor = product.user.username;
await Promise.all(
usersToNotify.map((user) =>
this.bot.sendDM(user.discordId, {
this.discordNotificationService.sendDM(user.discordId, {
embeds: [
new EmbedBuilder()
.setTitle(`**${productAuthor}** has listed a new item`)
Expand Down
6 changes: 4 additions & 2 deletions server/ecommerce/src/discord-guild/discord-guild.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { ItemNotifierService } from 'src/discord-bot/src/commands/notifiers/item
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';
import { DiscordNotificationsModule } from 'src/discord-notifications/discord-notifications.module';
import { DiscordBotModule } from 'src/discord-bot/discord-bot.module';
import { ProductNotificationModule } from 'src/product-notification/product-notification.module';
import { ItemNotifierModule } from 'src/discord-bot/src/commands/notifiers/item-notifier.module';

@Module({
imports: [
Expand All @@ -32,11 +34,11 @@ import { DiscordBotModule } from 'src/discord-bot/discord-bot.module';
]),
DiscordNotificationsModule,
DiscordBotModule,
ProductNotificationModule,
ItemNotifierModule,
],
providers: [
UsersService,
ProductNotificationService,
ItemNotifierService,
{
provide: IProductsService,
useClass: ProductsService,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Logger } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import {
AutocompleteInteraction,
ChatInputCommandInteraction,
Expand All @@ -18,6 +18,7 @@ type Config = {
botApplicationId: string;
};

@Injectable()
export class DiscordNotificationsBot {
private readonly logger: Logger;
private readonly bot: Client;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { DiscordNotificationsBot } from './discord-notifications-bot';
import { Client, IntentsBitField } from 'discord.js';
import { Client, IntentsBitField, MessageCreateOptions } from 'discord.js';

@Injectable()
export class DiscordNotificationsService implements OnModuleInit {
Expand Down Expand Up @@ -33,4 +33,11 @@ export class DiscordNotificationsService implements OnModuleInit {
async onModuleInit() {
await this.discordNotificationsBot.start();
}

public sendDM = async (
userDiscordId: string,
message: MessageCreateOptions,
) => {
return await this.discordNotificationsBot.sendDM(userDiscordId, message);
};
}
4 changes: 4 additions & 0 deletions server/ecommerce/src/events/constants/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ export enum DiscordEvents {
AssignDiscordRole = 'assignDiscordrole',
SyncUserRoles = 'syncUserRoles',
}

export enum GeneralEvents {
ProductCreated = 'productCreated',
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,11 @@ import { Avatar } from 'src/utils/entities/avatar.entity';
import { ProductsService } from 'src/products/products.service';
import { Product } from 'src/utils/entities/product.entity';
import { Image } from 'src/utils/entities/image.entity';
import { ItemNotifier } from 'src/discord-bot/src/commands/notifiers/item-notifier';
import { ItemNotifierService } from 'src/discord-bot/src/commands/notifiers/item-notifier.service';
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';
import { IProductsService } from 'src/spi/products';
import { DiscordGuildService } from 'src/discord-guild/discord-guild.service';
import { DiscordGuildModule } from 'src/discord-guild/discord-guild.module';
import { IDiscordGuildService } from 'src/spi/discord-guild';
import { DiscordBotService } from 'src/discord-bot/discord-bot.service';
import { FollowersService } from 'src/followers/followers.service';
import { DiscordNotificationsModule } from 'src/discord-notifications/discord-notifications.module';
import { DiscordBotModule } from 'src/discord-bot/discord-bot.module';
import { ItemNotifierModule } from 'src/discord-bot/src/commands/notifiers/item-notifier.module';

@Module({
imports: [
Expand All @@ -35,14 +29,13 @@ import { DiscordBotModule } from 'src/discord-bot/discord-bot.module';
Image,
]),
DiscordNotificationsModule,
DiscordBotModule,
ItemNotifierModule,
],
controllers: [ProductNotificationController],
providers: [
ProductNotificationService,
UsersService,
{ provide: IProductsService, useClass: ProductsService },
ItemNotifierService,

FollowersService,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import {
HttpStatus,
Inject,
Injectable,
Logger,
forwardRef,
} from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { InjectRepository } from '@nestjs/typeorm';
import { GeneralEvents } from 'src/events/constants/events';
import { IProductsService } from 'src/spi/products';
import { UsersService } from 'src/users/users.service';
import { ProductNotification } from 'src/utils/entities/product-notification.entity';
Expand All @@ -14,14 +17,20 @@ import { Repository } from 'typeorm';

@Injectable()
export class ProductNotificationService {
private logger: Logger;
constructor(
@InjectRepository(ProductNotification)
private productNotificationRepository: Repository<ProductNotification>,
private usersService: UsersService,
@Inject(forwardRef(() => IProductsService))
private productsService: IProductsService,
) {}
async notifyFollowersAboutNewProduct(product: Product) {
) {
this.logger = new Logger(ProductNotificationService.name);
}

@OnEvent(GeneralEvents.ProductCreated)
public async notifyFollowersAboutNewProduct(product: Product) {
this.logger.log(`${ProductNotificationService.name} received an event`);
const existingProductWithImage = await this.productsService.findProduct(
product.id,
);
Expand All @@ -38,7 +47,6 @@ export class ProductNotificationService {
message: `${user.username} has listed a new item ${existingProductWithImage.title} with price ${existingProductWithImage.price} USD`,
receiverId: follow.follower.id,
}));

await this.createProductNotificationsAndInsertThemToDb(
productNotifications,
);
Expand Down
8 changes: 3 additions & 5 deletions server/ecommerce/src/products/products.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,23 @@ import { Follow } from 'src/utils/entities/followers.entity';
import { FollowersModule } from 'src/followers/followers.module';
import { Profile } from 'src/utils/entities/profile.entity';
import { Avatar } from 'src/utils/entities/avatar.entity';
import { ProductNotificationService } from 'src/product-notification/product-notification.service';
import { ProductNotification } from 'src/utils/entities/product-notification.entity';
import { StripeService } from 'src/stripe/stripe.service';
import { NodemailerService } from 'src/nodemailer/nodemailer.service';
import { DiscordNotificationsService } from 'src/discord-notifications/discord-notifications.service';
import { ItemNotifierService } from 'src/discord-bot/src/commands/notifiers/item-notifier.service';
import { IProductsService } from 'src/spi/products';
import { DiscordNotificationsModule } from 'src/discord-notifications/discord-notifications.module';
import { ProductNotificationModule } from 'src/product-notification/product-notification.module';

@Module({
controllers: [ProductsController],
providers: [
{ provide: IProductsService, useClass: ProductsService },
UsersService,

ProductNotificationService,
StripeService,
NodemailerService,
ItemNotifierService,

],
imports: [
TypeOrmModule.forFeature([
Expand All @@ -41,8 +38,9 @@ import { DiscordNotificationsModule } from 'src/discord-notifications/discord-no
Avatar,
ProductNotification,
]),
ProductNotificationModule,
FollowersModule,
DiscordNotificationsModule
DiscordNotificationsModule,
],
exports: [IProductsService],
})
Expand Down
15 changes: 5 additions & 10 deletions server/ecommerce/src/products/products.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ import * as sharp from 'sharp';
import { randomUUID } from 'crypto';
import { UsersService } from 'src/users/users.service';
import 'dotenv/config';
import { ItemNotifierService } from 'src/discord-bot/src/commands/notifiers/item-notifier.service';
import { User } from 'src/utils/entities/user.entity';
import { IProductsService } from 'src/spi/products';
import { DiscordGuildService } from 'src/discord-guild/discord-guild.service';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { GeneralEvents } from 'src/events/constants/events';

const s3 = new S3Client({
region: process.env.BUCKET_REGION,
Expand All @@ -40,8 +39,7 @@ export class ProductsService implements IProductsService {
@InjectRepository(Image)
private readonly imageRepository: Repository<Image>,
private usersService: UsersService,

private itemNotifierService: ItemNotifierService,
private eventEmitter: EventEmitter2,
) {
this.logger = new Logger(ProductsService.name);
}
Expand Down Expand Up @@ -225,12 +223,9 @@ export class ProductsService implements IProductsService {
Body: buffer,
ContentType: file.mimetype,
} as PutObjectCommandInput;
await this.productsNotificationService.notifyFollowersAboutNewProduct(
newProduct,
);

const command = new PutObjectCommand(paramsToS3);
const foundProduct = await this.findProduct(newProduct.id);
await this.itemNotifierService.notifyUsers(userId, foundProduct);
this.eventEmitter.emit(GeneralEvents.ProductCreated, newProduct);
try {
await s3.send(command);
} catch (error) {
Expand Down
Loading

0 comments on commit c364226

Please sign in to comment.