typeorm#EntitySubscriberInterface TypeScript Examples

The following examples show how to use typeorm#EntitySubscriberInterface. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: comments.entity.ts    From NestJs-youtube with MIT License 6 votes vote down vote up
// tslint:disable-next-line: max-classes-per-file
@EventSubscriber()
@Injectable()
export class CommentSubscriber
  implements EntitySubscriberInterface<CommentEntity> {
  /**
   * Indicates that this subscriber only listen to Post events.
   */
  listenTo() {
    return CommentEntity;
  }

  /**
   * Called before post insertion.
   */

  async afterInsert(event: InsertEvent<CommentEntity>) {
    const postRepo: Repository<PostEntity> = event.connection.manager.getRepository<
      PostEntity
    >('posts');
    const commentRepo: Repository<CommentEntity> = event.connection.manager.getRepository<
      CommentEntity
    >('comments');
    commentRepo
      .count({
        where: { post: { id: event.entity.post.id } },
      })
      .then((count: number) => {
        postRepo.update({ id: event.entity.post.id }, { comments_num: count });
      });
  }
}
Example #2
Source File: user-auth-forgotten-password.subscriber.ts    From bank-server with MIT License 6 votes vote down vote up
@EventSubscriber()
export class UserAuthForgottenPasswordSubscriber
  implements EntitySubscriberInterface<UserAuthForgottenPasswordEntity> {
  listenTo() {
    return UserAuthForgottenPasswordEntity;
  }

  async beforeInsert({
    entity,
  }: InsertEvent<UserAuthForgottenPasswordEntity>): Promise<void> {
    if (entity.hashedToken) {
      /**
       * the token is longer than 72 characters, so it needs to be encoded first with sha256
       */
      const hashedToken = UtilsService.encodeString(entity.hashedToken);

      entity.hashedToken = await UtilsService.generateHash(hashedToken);
    }
  }

  async beforeUpdate({
    entity,
  }: UpdateEvent<UserAuthForgottenPasswordEntity>): Promise<void> {
    if (entity.hashedToken) {
      /**
       * the hashedToken is longer than 72 characters, so it needs to be encoded first with sha256
       */
      const hashedToken = UtilsService.encodeString(entity.hashedToken);

      entity.hashedToken = await UtilsService.generateHash(hashedToken);
    }
  }
}
Example #3
Source File: user-auth.subscriber.ts    From bank-server with MIT License 6 votes vote down vote up
@EventSubscriber()
export class UserAuthSubscriber
  implements EntitySubscriberInterface<UserAuthEntity> {
  listenTo() {
    return UserAuthEntity;
  }

  beforeInsert(event: InsertEvent<UserAuthEntity>): void {
    if (event.entity.password) {
      event.entity.password = UtilsService.generateHash(event.entity.password);
    }
  }

  beforeUpdate(event: UpdateEvent<UserAuthEntity>): void {
    if (event.entity?.password !== event.databaseEntity?.password) {
      event.entity.password = UtilsService.generateHash(event.entity.password);
    }
  }
}
Example #4
Source File: user.subscriber.ts    From bank-server with MIT License 6 votes vote down vote up
@EventSubscriber()
export class UserSubscriber implements EntitySubscriberInterface<UserEntity> {
  listenTo() {
    return UserEntity;
  }

  beforeInsert(event: InsertEvent<UserEntity>): void {
    event.entity.firstName = UtilsService.capitalizeName(
      event.entity.firstName,
    );
    event.entity.lastName = UtilsService.capitalizeName(event.entity.lastName);
  }

  beforeUpdate(event: UpdateEvent<UserEntity>): void {
    if (event.entity?.lastName !== event.databaseEntity?.lastName) {
      event.entity.lastName = UtilsService.capitalizeName(
        event.entity.lastName,
      );
    }
  }
}
Example #5
Source File: desktop-notif-subscriber.ts    From office-hours with GNU General Public License v3.0 6 votes vote down vote up
@EventSubscriber()
export class DesktopNotifSubscriber
  implements EntitySubscriberInterface<DesktopNotifModel>
{
  notifService: NotificationService;
  constructor(connection: Connection, notifService: NotificationService) {
    this.notifService = notifService;
    connection.subscribers.push(this);
  }

  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  listenTo() {
    return DesktopNotifModel;
  }

  async afterInsert(event: InsertEvent<DesktopNotifModel>): Promise<void> {
    await this.notifService.notifyDesktop(
      event.entity,
      "You've successfully signed up for desktop notifications!",
    );
  }
}
Example #6
Source File: queue.subscriber.ts    From office-hours with GNU General Public License v3.0 6 votes vote down vote up
@EventSubscriber()
export class QueueSubscriber implements EntitySubscriberInterface<QueueModel> {
  private queueSSEService: QueueSSEService;
  constructor(connection: Connection, queueSSEService: QueueSSEService) {
    this.queueSSEService = queueSSEService;
    connection.subscribers.push(this);
  }

  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  listenTo() {
    return QueueModel;
  }

  async afterUpdate(event: UpdateEvent<QueueModel>): Promise<void> {
    if (event.entity) {
      // Send all listening clients an update
      await this.queueSSEService.updateQueue(event.entity.id);
    }
  }
}
Example #7
Source File: placement.subscriber.ts    From rest-api.ts with MIT License 5 votes vote down vote up
@EventSubscriber()
export class PlacementSubscriber
  implements EntitySubscriberInterface<Placement> {
  listenTo() {
    return Placement;
  }

  async afterInsert({entity, manager}: InsertEvent<Placement>) {
    const productId = entity.product.id;
    const product = await manager.findOneOrFail(Product, {id: productId});
    product.quantity -= entity.quantity;
    await manager.save(product);

    await this.updateOrderTotal(manager, entity.order);
  }

  async beforeRemove({entity, manager}: RemoveEvent<Placement>) {
    const productId = entity.product.id;
    const product = await manager.findOneOrFail(Product, {id: productId});
    product.quantity += entity.quantity;
    await manager.save(product);
  }

  async afterRemove({entity, manager}: RemoveEvent<Placement>) {
    await this.updateOrderTotal(manager, entity.order);
  }

  private async updateOrderTotal(manager: EntityManager, order: Order) {
    const result = await manager
      .createQueryBuilder(Placement, 'pl')
      .select('SUM(pl.quantity) * p.price', 'total')
      .innerJoin('pl.order', 'o')
      .innerJoin('pl.product', 'p')
      .where('o.id = :orderId', {orderId: order.id})
      .groupBy('o.id')
      .getRawOne();
    order.total = result?.total ?? 0;

    // const placements = await manager.find(Placement, {
    //   where: {order},
    //   relations: ['product'],
    // });

    // order.total = placements.reduce(
    //   (sum, placement) => sum + placement.quantity * placement.product.price,
    //   0,
    // );

    await manager.save(Order, order);
  }
}
Example #8
Source File: bill.subscriber.ts    From bank-server with MIT License 4 votes vote down vote up
@Injectable()
@EventSubscriber()
export class BillSubscriber implements EntitySubscriberInterface<BillEntity> {
  private readonly _developerAge = UtilsService.getAge(new Date(1997, 9, 16));
  private readonly _promotionValue = 10;
  private readonly _promotionTransferTitle = `Create an account`;
  private readonly _promotionKey = `PROMO10`;
  private readonly _messageValue = 5;
  private readonly _messageTransferTitle = `Thank you for registering! :)`;
  private readonly _messageKey = `WELCOME5`;
  private readonly _messageName = 'WELCOME_MESSAGE';
  private readonly _messageOptions = {
    en: {
      subject: 'Cooperation proposal',
      actions: [
        `<a href="mailto:[email protected]">I want to send you feedback now</a>`,
        `I'll do it in a moment`,
      ],
    },
    de: {
      subject: 'Kooperationsvorschlag',
      actions: [
        `<a href="mailto:[email protected]">Ich möchte Ihnen jetzt eine Meinung senden</a>`,
        `Ich werde meine Meinung gleich senden`,
      ],
    },
    pl: {
      subject: 'Propozycja współpracy',
      actions: [
        `<a href="mailto:[email protected]">Chcę przesłać opinię teraz</a>`,
        `Prześlę swoją opinię za chwilę`,
      ],
    },
  };

  private readonly _configService = new ConfigService();

  /*
    NOTE: It need to use different services,
    that's why this subscriber is connected by the constructor.
   */
  constructor(
    @InjectConnection() readonly connection: Connection,
    private readonly _messageService: MessageService,
    private readonly _messageKeyService: MessageKeyService,
    private readonly _userService: UserService,
    private readonly _userAuthService: UserAuthService,
    private readonly _languageService: LanguageService,
    private readonly _transactionService: TransactionService,
    private readonly _billService: BillService,
  ) {
    connection.subscribers.push(this);
  }

  public listenTo() {
    return BillEntity;
  }

  public async afterInsert(event: InsertEvent<BillEntity>): Promise<void> {
    const rootEmail = this._configService.get('BANK_ROOT_EMAIL');
    const authorEmail = this._configService.get('BANK_AUTHOR_EMAIL');

    if (![rootEmail, authorEmail].includes(event.entity.user.email)) {
      await this._initRegisterPromotion(event.entity);

      await Promise.all([
        this._initWelcomeMessage(event.entity.user),
        this._initWelcomeTransfer(event.entity),
      ]);
    }
  }

  private async _initWelcomeTransfer(recipientBill: BillEntity): Promise<void> {
    const transaction = await this._transactionService.getTransaction({
      recipient: recipientBill.user,
      authorizationKey: this._messageKey,
    });

    if (transaction) {
      return;
    }

    const sender = await this._userAuthService.findUserAuth({
      role: RoleType.ADMIN,
    });

    if (!sender) {
      return;
    }

    const senderBill = await this._billService.getBill(sender);

    const createdTransaction = {
      amountMoney: this._messageValue,
      transferTitle: this._messageTransferTitle,
      recipientBill: recipientBill.uuid,
      senderBill: senderBill.uuid,
      locale: Language.EN,
    };

    return this._makeTransfer(createdTransaction, sender, this._messageKey);
  }

  private async _initWelcomeMessage(recipient: UserEntity): Promise<void> {
    const message = await this._messageService.getMessageByMessageName({
      user: recipient,
      name: this._messageName,
    });

    if (message) {
      return;
    }

    const key = await this._messageKeyService.getMessageKey({
      name: this._messageName,
    });
    const languages = await this._languageService.getLanguages();
    const sender = await this._userAuthService.findUserAuth({
      role: RoleType.ADMIN,
    });
    const templates = await this._createMessageTemplates(languages);

    const createdMessage = this._getCreateMessage(
      key.uuid,
      sender.uuid,
      recipient.uuid,
      templates,
    );

    return this._makeMessage(createdMessage);
  }

  private async _initRegisterPromotion(
    recipientBill: BillEntity,
  ): Promise<void> {
    const transaction = await this._transactionService.getTransaction({
      recipient: recipientBill.user,
      authorizationKey: this._promotionKey,
      authorizationStatus: true,
    });

    if (transaction) {
      return;
    }

    const sender = await this._userAuthService.findUserAuth({
      role: RoleType.ROOT,
    });

    if (!sender) {
      return;
    }

    const senderBill = await this._billService.getBill(sender);

    const createdTransaction = {
      amountMoney: this._promotionValue,
      transferTitle: this._promotionTransferTitle,
      recipientBill: recipientBill.uuid,
      senderBill: senderBill.uuid,
      locale: Language.EN,
    };

    return this._makeTransfer(createdTransaction, sender, this._promotionKey);
  }

  private _getCreateMessage(
    key: string,
    sender: string,
    recipient: string,
    templates: CreateMessageTemplateDto[],
  ): CreateMessageDto {
    return { key, sender, recipient, templates };
  }

  /**
   * TODO: This method is re-declared somewhere and fails the DRY principle.
   * Transfer it to a separate service
   */
  private _getCompiledContent(
    content: string,
    variables: ICreatedMessage,
  ): any {
    const template = handlebars.compile(content.toString());

    return template(variables);
  }

  private async _createMessageTemplates(
    languages: LanguageEntity[],
  ): Promise<CreateMessageTemplateDto[]> {
    let messageTemplates = [];
    const customerCount = await this._userService.getUsersCount();

    for (const { uuid: language, code } of languages) {
      const content = await this._getWelcomeMessageContent(code);
      const compiledContent = this._getCompiledContent(content, {
        developerAge: this._developerAge,
        customerCount,
      });
      const messageTemplate = this._createMessageTemplate(
        language,
        compiledContent,
        this._messageOptions[code].subject,
        this._messageOptions[code].actions,
      );

      messageTemplates = [...messageTemplates, messageTemplate];
    }

    return messageTemplates;
  }

  private async _getWelcomeMessageContent(locale: string): Promise<string> {
    try {
      const data = await fs.promises.readFile(
        __dirname + `/../../message/templates/welcome.template.${locale}.hbs`,
        'utf8',
      );

      return data;
    } catch (error) {
      throw new Error(error);
    }
  }

  private _createMessageTemplate(
    language: string,
    content: string,
    subject: string,
    actions?: { param: string },
  ): CreateMessageTemplateDto {
    return { language, content, subject, actions };
  }

  private async _makeTransfer(
    createdTransaction: CreateTransactionDto,
    sender: UserEntity,
    authorizationKey: string,
  ): Promise<void> {
    await this._transactionService.createTransaction(
      sender,
      createdTransaction,
      authorizationKey,
    );
    await this._transactionService.confirmTransaction(sender, {
      authorizationKey,
    });
  }

  private async _makeMessage(createdMessage: CreateMessageDto): Promise<void> {
    return this._messageService.createMessage(createdMessage);
  }
}
Example #9
Source File: question.subscriber.ts    From office-hours with GNU General Public License v3.0 4 votes vote down vote up
@EventSubscriber()
export class QuestionSubscriber
  implements EntitySubscriberInterface<QuestionModel>
{
  private notifService: NotificationService;
  private queueSSEService: QueueSSEService;
  constructor(
    connection: Connection,
    notifService: NotificationService,
    queueSSEService: QueueSSEService,
  ) {
    this.notifService = notifService;
    this.queueSSEService = queueSSEService;
    connection.subscribers.push(this);
  }

  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  listenTo() {
    return QuestionModel;
  }

  async afterUpdate(event: UpdateEvent<QuestionModel>): Promise<void> {
    if (!event.entity) {
      // TODO: this is kinda janky maybe fix
      return;
    }

    await this.queueSSEService.updateQuestions(event.entity.queueId);
    // Send push notification to students when they are hit 3rd in line
    // if status updated to closed
    if (
      event.updatedColumns.find((c) => c.propertyName === 'status') &&
      event.entity.status in ClosedQuestionStatus
    ) {
      // get 3rd in queue before and after this update
      const previousThird = await QuestionModel.waitingInQueue(
        event.entity.queueId,
      )
        .offset(2)
        .getOne();
      const third = await QuestionModel.waitingInQueue(event.entity.queueId)
        .setQueryRunner(event.queryRunner) // Run in same transaction as the update
        .offset(2)
        .getOne();
      if (third && previousThird?.id !== third?.id) {
        const { creatorId } = third;
        this.notifService.notifyUser(creatorId, NotifMsgs.queue.THIRD_PLACE);
      }
    }
  }

  async afterInsert(event: InsertEvent<QuestionModel>): Promise<void> {
    const numberOfQuestions = await QuestionModel.waitingInQueue(
      event.entity.queueId,
    ).getCount();

    if (numberOfQuestions === 0) {
      const staff = (
        await QueueModel.findOne(event.entity.queueId, {
          relations: ['staffList'],
        })
      ).staffList;

      staff.forEach((staff) => {
        this.notifService.notifyUser(
          staff.id,
          NotifMsgs.ta.STUDENT_JOINED_EMPTY_QUEUE,
        );
      });
    }

    // Send all listening clients an update
    await this.queueSSEService.updateQuestions(event.entity.queueId);
  }

  async beforeRemove(event: RemoveEvent<QuestionModel>): Promise<void> {
    // due to cascades entity is not guaranteed to be loaded
    if (event.entity) {
      // Send all listening clients an update
      await this.queueSSEService.updateQuestions(event.entity.queueId);
    }
  }
}