mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 12:20:31 +00:00
fix: user invite email not sending and null variables
- Add missing BullModule queue registration and BullBoardModule to UsersModule - Add invitingUser to event payloads to track who sent the invite - Fix incorrect global variable in SendInviteUsersMailMessage (__views_dir -> __images_dirname) - Use invitingUser as fromUser instead of invited user in email - Update processors to use BullMQ pattern Fixes issues: 1. Email not sending due to missing queue/processor registration 2. Null variables in email (firstName/lastName) because fromUser was the invited user 3. Image attachment failing due to wrong path
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BullBoardModule } from '@bull-board/nestjs';
|
||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
||||
import { BullModule } from '@nestjs/bull';
|
||||
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||
import { BullModule } from '@nestjs/bullmq';
|
||||
import { PaymentReceivesController } from './PaymentsReceived.controller';
|
||||
import { PaymentReceivesApplication } from './PaymentReceived.application';
|
||||
import { CreatePaymentReceivedService } from './commands/CreatePaymentReceived.serivce';
|
||||
@@ -99,7 +99,7 @@ import { ValidateBulkDeletePaymentReceivedService } from './ValidateBulkDeletePa
|
||||
BullModule.registerQueue({ name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE }),
|
||||
BullBoardModule.forFeature({
|
||||
name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE,
|
||||
adapter: BullAdapter,
|
||||
adapter: BullMQAdapter,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { JOB_REF, Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||
import { Job } from 'bullmq';
|
||||
import { Scope } from '@nestjs/common';
|
||||
import { ClsService, UseCls } from 'nestjs-cls';
|
||||
import {
|
||||
SEND_PAYMENT_RECEIVED_MAIL_JOB,
|
||||
@@ -13,20 +13,18 @@ import { SendPaymentReceivedMailPayload } from '../types/PaymentReceived.types';
|
||||
name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE,
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class SendPaymentReceivedMailProcessor {
|
||||
export class SendPaymentReceivedMailProcessor extends WorkerHost {
|
||||
constructor(
|
||||
private readonly sendPaymentReceivedMail: SendPaymentReceiveMailNotification,
|
||||
private readonly clsService: ClsService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SendPaymentReceivedMailPayload>,
|
||||
) { }
|
||||
|
||||
@Process(SEND_PAYMENT_RECEIVED_MAIL_JOB)
|
||||
@UseCls()
|
||||
async handleSendMail() {
|
||||
async process(job: Job<SendPaymentReceivedMailPayload>) {
|
||||
const { messageOptions, paymentReceivedId, organizationId, userId } =
|
||||
this.jobRef.data;
|
||||
job.data;
|
||||
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BullBoardModule } from '@bull-board/nestjs';
|
||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
||||
import { BullModule } from '@nestjs/bull';
|
||||
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||
import { BullModule } from '@nestjs/bullmq';
|
||||
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||
import { TenancyDatabaseModule } from '../Tenancy/TenancyDB/TenancyDB.module';
|
||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||
@@ -58,7 +58,7 @@ import { SendSaleEstimateMailProcess } from './processes/SendSaleEstimateMail.pr
|
||||
BullModule.registerQueue({ name: SendSaleEstimateMailQueue }),
|
||||
BullBoardModule.forFeature({
|
||||
name: SendSaleEstimateMailQueue,
|
||||
adapter: BullAdapter,
|
||||
adapter: BullMQAdapter,
|
||||
}),
|
||||
],
|
||||
controllers: [SaleEstimatesController],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { InjectQueue } from '@nestjs/bullmq';
|
||||
import { Queue } from 'bull';
|
||||
import { Queue } from 'bullmq';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { ContactMailNotification } from '@/modules/MailNotification/ContactMailNotification';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { JOB_REF } from '@nestjs/bull';
|
||||
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||
import { Job } from 'bullmq';
|
||||
import { Scope } from '@nestjs/common';
|
||||
import {
|
||||
SendSaleEstimateMailJob,
|
||||
SendSaleEstimateMailQueue,
|
||||
@@ -13,18 +12,17 @@ import { ClsService, UseCls } from 'nestjs-cls';
|
||||
name: SendSaleEstimateMailQueue,
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class SendSaleEstimateMailProcess {
|
||||
export class SendSaleEstimateMailProcess extends WorkerHost {
|
||||
constructor(
|
||||
private readonly sendEstimateMailService: SendSaleEstimateMail,
|
||||
private readonly clsService: ClsService,
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job,
|
||||
) { }
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Process(SendSaleEstimateMailJob)
|
||||
@UseCls()
|
||||
async handleSendMail() {
|
||||
const { saleEstimateId, messageOptions, organizationId, userId } = this.jobRef.data;
|
||||
async process(job: Job) {
|
||||
const { saleEstimateId, messageOptions, organizationId, userId } = job.data;
|
||||
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
@@ -46,8 +46,8 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
||||
import { MailNotificationModule } from '../MailNotification/MailNotification.module';
|
||||
import { SendSaleInvoiceMailProcessor } from './processors/SendSaleInvoiceMail.processor';
|
||||
import { BullBoardModule } from '@bull-board/nestjs';
|
||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
||||
import { BullModule } from '@nestjs/bull';
|
||||
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||
import { BullModule } from '@nestjs/bullmq';
|
||||
import { SendSaleInvoiceQueue } from './constants';
|
||||
import { InvoicePaymentIntegrationSubscriber } from './subscribers/InvoicePaymentIntegrationSubscriber';
|
||||
import { InvoiceChangeStatusOnMailSentSubscriber } from './subscribers/InvoiceChangeStatusOnMailSentSubscriber';
|
||||
@@ -85,7 +85,7 @@ import { ValidateBulkDeleteSaleInvoicesService } from './ValidateBulkDeleteSaleI
|
||||
BullModule.registerQueue({ name: SendSaleInvoiceQueue }),
|
||||
BullBoardModule.forFeature({
|
||||
name: SendSaleInvoiceQueue,
|
||||
adapter: BullAdapter,
|
||||
adapter: BullMQAdapter,
|
||||
}),
|
||||
],
|
||||
controllers: [SaleInvoicesController],
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { JOB_REF, Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||
import { Job } from 'bullmq';
|
||||
import { SendSaleInvoiceMailJob, SendSaleInvoiceQueue } from '../constants';
|
||||
import { SendSaleInvoiceMail } from '../commands/SendSaleInvoiceMail';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
import { Scope } from '@nestjs/common';
|
||||
import { ClsService, UseCls } from 'nestjs-cls';
|
||||
import { SendSaleInvoiceMailJobPayload } from '../SaleInvoice.types';
|
||||
|
||||
@@ -11,20 +10,18 @@ import { SendSaleInvoiceMailJobPayload } from '../SaleInvoice.types';
|
||||
name: SendSaleInvoiceQueue,
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class SendSaleInvoiceMailProcessor {
|
||||
export class SendSaleInvoiceMailProcessor extends WorkerHost {
|
||||
constructor(
|
||||
private readonly sendSaleInvoiceMail: SendSaleInvoiceMail,
|
||||
@Inject(REQUEST) private readonly request: Request,
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SendSaleInvoiceMailJobPayload>,
|
||||
private readonly clsService: ClsService,
|
||||
) { }
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Process(SendSaleInvoiceMailJob)
|
||||
@UseCls()
|
||||
async handleSendInvoice() {
|
||||
async process(job: Job<SendSaleInvoiceMailJobPayload>) {
|
||||
const { messageOptions, saleInvoiceId, organizationId, userId } =
|
||||
this.jobRef.data;
|
||||
job.data;
|
||||
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BullBoardModule } from '@bull-board/nestjs';
|
||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
||||
import { BullModule } from '@nestjs/bull';
|
||||
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||
import { BullModule } from '@nestjs/bullmq';
|
||||
import { SaleReceiptApplication } from './SaleReceiptApplication.service';
|
||||
import { CreateSaleReceipt } from './commands/CreateSaleReceipt.service';
|
||||
import { EditSaleReceipt } from './commands/EditSaleReceipt.service';
|
||||
@@ -66,7 +66,7 @@ import { ValidateBulkDeleteSaleReceiptsService } from './ValidateBulkDeleteSaleR
|
||||
BullModule.registerQueue({ name: SendSaleReceiptMailQueue }),
|
||||
BullBoardModule.forFeature({
|
||||
name: SendSaleReceiptMailQueue,
|
||||
adapter: BullAdapter,
|
||||
adapter: BullMQAdapter,
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { InjectQueue } from '@nestjs/bull';
|
||||
import { InjectQueue } from '@nestjs/bullmq';
|
||||
import { Queue } from 'bullmq';
|
||||
import {
|
||||
DEFAULT_RECEIPT_MAIL_CONTENT,
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
import { Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { JOB_REF } from '@nestjs/bull';
|
||||
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||
import { Job } from 'bullmq';
|
||||
import { Scope } from '@nestjs/common';
|
||||
import { SendSaleReceiptMailQueue, SendSaleReceiptMailJob } from '../constants';
|
||||
import { SaleReceiptMailNotification } from '../commands/SaleReceiptMailNotification';
|
||||
import { SaleReceiptSendMailPayload } from '../types/SaleReceipts.types';
|
||||
import { ClsService, UseCls } from 'nestjs-cls';
|
||||
|
||||
@Processor({
|
||||
name: SendSaleReceiptMailQueue,
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class SendSaleReceiptMailProcess {
|
||||
export class SendSaleReceiptMailProcess extends WorkerHost {
|
||||
constructor(
|
||||
private readonly saleReceiptMailNotification: SaleReceiptMailNotification,
|
||||
private readonly clsService: ClsService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SaleReceiptSendMailPayload>,
|
||||
) { }
|
||||
|
||||
@Process(SendSaleReceiptMailJob)
|
||||
@UseCls()
|
||||
async handleSendMailJob() {
|
||||
async process(job: Job) {
|
||||
const { messageOpts, saleReceiptId, organizationId, userId } =
|
||||
this.jobRef.data;
|
||||
job.data;
|
||||
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BullModule } from '@nestjs/bullmq';
|
||||
import { BullBoardModule } from '@bull-board/nestjs';
|
||||
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||
import { ActivateUserService } from './commands/ActivateUser.service';
|
||||
import { DeleteUserService } from './commands/DeleteUser.service';
|
||||
import { EditUserService } from './commands/EditUser.service';
|
||||
@@ -18,11 +21,24 @@ import { AcceptInviteUserService } from './commands/AcceptInviteUser.service';
|
||||
import { InviteTenantUserService } from './commands/InviteUser.service';
|
||||
import { UsersInviteController } from './UsersInvite.controller';
|
||||
import { InjectSystemModel } from '../System/SystemModels/SystemModels.module';
|
||||
import { SendInviteUserMailQueue } from './Users.constants';
|
||||
import InviteSendMainNotificationSubscribe from './subscribers/InviteSendMailNotification.subscriber';
|
||||
import { SendInviteUserMailProcessor } from './processors/SendInviteUserMail.processor';
|
||||
import { SendInviteUsersMailMessage } from './commands/SendInviteUsersMailMessage.service';
|
||||
import { MailModule } from '../Mail/Mail.module';
|
||||
|
||||
const models = [InjectSystemModel(UserInvite)];
|
||||
|
||||
@Module({
|
||||
imports: [TenancyModule],
|
||||
imports: [
|
||||
TenancyModule,
|
||||
MailModule,
|
||||
BullModule.registerQueue({ name: SendInviteUserMailQueue }),
|
||||
BullBoardModule.forFeature({
|
||||
name: SendInviteUserMailQueue,
|
||||
adapter: BullMQAdapter,
|
||||
}),
|
||||
],
|
||||
exports: [...models],
|
||||
providers: [
|
||||
...models,
|
||||
@@ -39,6 +55,9 @@ const models = [InjectSystemModel(UserInvite)];
|
||||
SyncTenantUserMutateSubscriber,
|
||||
SyncSystemSendInviteSubscriber,
|
||||
SyncTenantAcceptInviteSubscriber,
|
||||
InviteSendMainNotificationSubscribe,
|
||||
SendInviteUserMailProcessor,
|
||||
SendInviteUsersMailMessage,
|
||||
UsersApplication
|
||||
],
|
||||
controllers: [UsersController, UsersInviteController],
|
||||
|
||||
@@ -32,10 +32,12 @@ export interface ITenantUserDeletedPayload {
|
||||
export interface IUserInvitedEventPayload {
|
||||
inviteToken: string;
|
||||
user: ModelObject<TenantUser>;
|
||||
invitingUser: ModelObject<TenantUser>;
|
||||
}
|
||||
export interface IUserInviteTenantSyncedEventPayload {
|
||||
invite: ModelObject<UserInvite>;
|
||||
user: ModelObject<TenantUser>;
|
||||
invitingUser: ModelObject<TenantUser>;
|
||||
}
|
||||
|
||||
export interface IUserInviteResendEventPayload {
|
||||
|
||||
@@ -15,11 +15,13 @@ import { events } from '@/common/events/events';
|
||||
import { Role } from '@/modules/Roles/models/Role.model';
|
||||
import { ModelObject } from 'objection';
|
||||
import { SendInviteUserDto } from '../dtos/InviteUser.dto';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
|
||||
@Injectable()
|
||||
export class InviteTenantUserService {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(TenantUser.name)
|
||||
private readonly tenantUserModel: TenantModelProxy<typeof TenantUser>,
|
||||
@@ -53,10 +55,18 @@ export class InviteTenantUserService {
|
||||
active: true,
|
||||
invitedAt: new Date(),
|
||||
});
|
||||
|
||||
// Retrieves the authorized user (inviting user).
|
||||
const authorizedUser = await this.tenancyContext.getSystemUser();
|
||||
const invitingUser = await this.tenantUserModel()
|
||||
.query()
|
||||
.findOne({ systemUserId: authorizedUser.id });
|
||||
|
||||
// Triggers `onUserSendInvite` event.
|
||||
await this.eventEmitter.emitAsync(events.inviteUser.sendInvite, {
|
||||
inviteToken,
|
||||
user,
|
||||
invitingUser,
|
||||
} as IUserInvitedEventPayload);
|
||||
|
||||
return { invitedUser: user };
|
||||
|
||||
@@ -27,7 +27,7 @@ export class SendInviteUsersMailMessage {
|
||||
invite: ModelObject<UserInvite>,
|
||||
) {
|
||||
const tenant = await this.tenancyContext.getTenant(true);
|
||||
const root = path.join(global.__views_dir, '/images/bigcapital.png');
|
||||
const root = path.join(global.__images_dirname, '/bigcapital.png');
|
||||
const baseURL = this.configService.get('baseURL');
|
||||
|
||||
const mail = new Mail()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { JOB_REF, Process, Processor } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||
import { Job } from 'bullmq';
|
||||
import { Scope } from '@nestjs/common';
|
||||
import { ClsService, UseCls } from 'nestjs-cls';
|
||||
import {
|
||||
SendInviteUserMailJob,
|
||||
@@ -14,19 +13,17 @@ import { SendInviteUsersMailMessage } from '../commands/SendInviteUsersMailMessa
|
||||
name: SendInviteUserMailQueue,
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class SendInviteUserMailProcessor {
|
||||
export class SendInviteUserMailProcessor extends WorkerHost {
|
||||
constructor(
|
||||
private readonly sendInviteUsersMailService: SendInviteUsersMailMessage,
|
||||
@Inject(REQUEST) private readonly request: Request,
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<SendInviteUserMailJobPayload>,
|
||||
private readonly clsService: ClsService,
|
||||
) { }
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Process(SendInviteUserMailJob)
|
||||
@UseCls()
|
||||
async handleSendInviteMail() {
|
||||
const { fromUser, invite, organizationId, userId } = this.jobRef.data;
|
||||
async process(job: Job<SendInviteUserMailJobPayload>) {
|
||||
const { fromUser, invite, organizationId, userId } = job.data;
|
||||
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectQueue } from '@nestjs/bull';
|
||||
import { Queue } from 'bull';
|
||||
import { InjectQueue } from '@nestjs/bullmq';
|
||||
import { Queue } from 'bullmq';
|
||||
import { events } from '@/common/events/events';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import {
|
||||
@@ -29,6 +29,7 @@ export default class InviteSendMainNotificationSubscribe {
|
||||
async sendMailNotification({
|
||||
invite,
|
||||
user,
|
||||
invitingUser,
|
||||
}: IUserInviteTenantSyncedEventPayload) {
|
||||
const tenant = await this.tenancyContext.getTenant();
|
||||
const authedUser = await this.tenancyContext.getSystemUser();
|
||||
@@ -37,7 +38,7 @@ export default class InviteSendMainNotificationSubscribe {
|
||||
const userId = authedUser.id;
|
||||
|
||||
this.sendInviteMailQueue.add(SendInviteUserMailJob, {
|
||||
fromUser: user,
|
||||
fromUser: invitingUser,
|
||||
invite,
|
||||
userId,
|
||||
organizationId,
|
||||
|
||||
@@ -33,7 +33,7 @@ export class SyncSystemSendInviteSubscriber {
|
||||
* @param {IUserInvitedEventPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.inviteUser.sendInvite)
|
||||
async syncSendInviteSystem({ inviteToken, user }: IUserInvitedEventPayload) {
|
||||
async syncSendInviteSystem({ inviteToken, user, invitingUser }: IUserInvitedEventPayload) {
|
||||
const authorizedUser = await this.tenancyContext.getSystemUser();
|
||||
const tenantId = authorizedUser.tenantId;
|
||||
|
||||
@@ -63,6 +63,7 @@ export class SyncSystemSendInviteSubscriber {
|
||||
{
|
||||
invite,
|
||||
user,
|
||||
invitingUser,
|
||||
} as IUserInviteTenantSyncedEventPayload,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user