diff --git a/src/controllers/gupshup-webhook.controller.ts b/src/controllers/gupshup-webhook.controller.ts deleted file mode 100644 index ba7ab5d1..00000000 --- a/src/controllers/gupshup-webhook.controller.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { - Body, - Controller, - HttpCode, - HttpStatus, - Logger, - Post, - Req, -} from "@nestjs/common"; -import { ApiTags } from "@nestjs/swagger"; -import { Request } from "express"; -import { Auth } from "src/decorators/auth.decorator"; -import { Public } from "src/decorators/public.decorator"; -import { AuthType } from "src/enums/auth-type.enum"; - -@Auth(AuthType.None) -@Controller("webhook/whatsapp/gupshup") -@ApiTags("Solid Core") -export class GupshupWebhookController { - private readonly logger = new Logger(GupshupWebhookController.name); - - @Public() - @Post() - @HttpCode(HttpStatus.OK) - async receiveWebhook(@Req() req: Request, @Body() body: unknown) { - const userAgent = req.headers["user-agent"] ?? null; - this.logger.log( - `Received Gupshup WhatsApp webhook${userAgent ? ` from ${userAgent}` : ""}`, - ); - this.logger.debug(`Gupshup webhook payload: ${JSON.stringify(body)}`); - - const statusInfo = this.extractStatusInfo(body); - if (statusInfo) { - this.logger.log( - `Gupshup delivery update: status=${statusInfo.status ?? "unknown"}, messageId=${statusInfo.messageId ?? "n/a"}, destination=${statusInfo.destination ?? "n/a"}, reason=${statusInfo.reason ?? "n/a"}`, - ); - } - - return { - success: true, - message: "Webhook received", - }; - } - - private extractStatusInfo(body: unknown): { - status?: string; - messageId?: string; - destination?: string; - reason?: string; - } | null { - if (!body || typeof body !== "object") { - return null; - } - - const payload = body as Record; - - const status = - this.asString(payload.status) || - this.asString(payload.messageStatus) || - this.asString((payload.payload as Record)?.status) || - this.asString((payload.payload as Record)?.type); - - const messageId = - this.asString(payload.messageId) || - this.asString(payload.id) || - this.asString((payload.payload as Record)?.id) || - this.asString((payload.payload as Record)?.messageId); - - const destination = - this.asString(payload.destination) || - this.asString(payload.phone) || - this.asString((payload.payload as Record)?.destination) || - this.asString((payload.payload as Record)?.phone); - - const reason = - this.asString(payload.reason) || - this.asString(payload.error) || - this.asString((payload.payload as Record)?.reason) || - this.asString((payload.payload as Record)?.error); - - if (!status && !messageId && !destination && !reason) { - return null; - } - - return { status, messageId, destination, reason }; - } - - private asString(value: unknown): string | undefined { - return typeof value === "string" && value.trim() ? value.trim() : undefined; - } -} diff --git a/src/controllers/meta-cloud-whatsapp-webhook.controller.ts b/src/controllers/meta-cloud-whatsapp-webhook.controller.ts deleted file mode 100644 index 1c97c706..00000000 --- a/src/controllers/meta-cloud-whatsapp-webhook.controller.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { - Body, - Controller, - Get, - HttpCode, - HttpStatus, - Logger, - Post, - Query, - Res, -} from "@nestjs/common"; -import { ApiTags } from "@nestjs/swagger"; -import { Response } from "express"; -import { Auth } from "src/decorators/auth.decorator"; -import { Public } from "src/decorators/public.decorator"; -import { AuthType } from "src/enums/auth-type.enum"; -import { SettingService } from "src/services/setting.service"; -import type { SolidCoreSetting } from "src/services/settings/default-settings-provider.service"; - -@Auth(AuthType.None) -@Controller("webhook/whatsapp/meta-cloud") -@ApiTags("Solid Core") -export class MetaCloudWhatsappWebhookController { - private readonly logger = new Logger(MetaCloudWhatsappWebhookController.name); - - constructor(private readonly settingService: SettingService) {} - - @Public() - @Get() - verifyWebhook(@Query() query: Record, @Res() res: Response) { - const mode = this.resolveQueryValue(query, "hub.mode", "hub_mode", "mode"); - const verifyToken = this.resolveQueryValue( - query, - "hub.verify_token", - "hub_verify_token", - "verify_token", - ); - const challenge = this.resolveQueryValue( - query, - "hub.challenge", - "hub_challenge", - "challenge", - ); - - const configuredVerifyToken = - this.settingService.getConfigValue( - "metaWhatsappWebhookVerifyToken", - ) || process.env.COMMON_META_WHATSAPP_WEBHOOK_VERIFY_TOKEN; - - const isVerificationCall = mode === "subscribe"; - const tokenMatches = - !!configuredVerifyToken && verifyToken === configuredVerifyToken; - - if (isVerificationCall && tokenMatches && challenge) { - this.logger.log("Meta Cloud WhatsApp webhook verified successfully."); - res.writeHead(HttpStatus.OK, { - "Content-Type": "text/plain", - "Content-Length": Buffer.byteLength(String(challenge)), - }); - res.write(String(challenge)); - return res.end(); - } - - this.logger.warn( - `Meta Cloud webhook verification failed. mode=${mode ?? "n/a"}, tokenMatch=${tokenMatches}`, - ); - - res.writeHead(HttpStatus.FORBIDDEN, { "Content-Type": "text/plain" }); - return res.end("Webhook verification failed"); - } - - @Public() - @Post() - @HttpCode(HttpStatus.OK) - async receiveWebhook(@Body() body: unknown) { - this.logger.log("Received Meta Cloud WhatsApp webhook"); - this.logger.debug(`Meta Cloud webhook payload: ${JSON.stringify(body)}`); - - const statusInfo = this.extractStatusInfo(body); - if (statusInfo) { - this.logger.log( - `Meta Cloud delivery update: status=${statusInfo.status ?? "unknown"}, messageId=${statusInfo.messageId ?? "n/a"}, destination=${statusInfo.destination ?? "n/a"}, reason=${statusInfo.reason ?? "n/a"}`, - ); - } - - return { - success: true, - message: "Webhook received", - }; - } - - private extractStatusInfo(body: unknown): { - status?: string; - messageId?: string; - destination?: string; - reason?: string; - } | null { - if (!body || typeof body !== "object") { - return null; - } - - const payload = body as Record; - const entries = payload.entry as Array> | undefined; - const changes = entries?.[0]?.changes as Array> | undefined; - const value = changes?.[0]?.value as Record | undefined; - const statuses = value?.statuses as Array> | undefined; - const status = statuses?.[0]; - - if (!status) { - return null; - } - - const errors = status.errors as Array> | undefined; - - return { - status: this.asString(status.status), - messageId: this.asString(status.id), - destination: this.asString(status.recipient_id), - reason: - this.asString(errors?.[0]?.title) || this.asString(errors?.[0]?.message), - }; - } - - private asString(value: unknown): string | undefined { - return typeof value === "string" && value.trim() ? value.trim() : undefined; - } - - private resolveQueryValue( - query: Record, - ...keys: string[] - ): string | undefined { - for (const key of keys) { - const directValue = this.asString(query[key]); - if (directValue) { - return directValue; - } - } - - const hubRaw = query.hub; - if (hubRaw && typeof hubRaw === "object" && !Array.isArray(hubRaw)) { - const hub = hubRaw as Record; - for (const key of ["mode", "verify_token", "challenge"]) { - const value = this.asString(hub[key]); - if ( - value && - keys.some((candidate) => candidate.endsWith(key) || candidate === key) - ) { - return value; - } - } - } - - return undefined; - } -} diff --git a/src/factories/whatsapp.factory.ts b/src/factories/whatsapp.factory.ts index 9938c17c..fc1b4949 100644 --- a/src/factories/whatsapp.factory.ts +++ b/src/factories/whatsapp.factory.ts @@ -1,43 +1,42 @@ -import { Injectable, Logger } from "@nestjs/common"; +import { Inject, Injectable, Logger } from "@nestjs/common"; +import { ConfigType } from "@nestjs/config"; import { ModuleRef } from "@nestjs/core"; import { SolidRegistry } from "src/helpers/solid-registry"; import { IWhatsAppTransport } from "src/interfaces"; import { SettingService } from "src/services/setting.service"; import type { SolidCoreSetting } from "src/services/settings/default-settings-provider.service"; +function norm(s?: string) { + return s?.trim().toLowerCase(); +} + +// This factory will be use to return a mail service instance, using the configured environment variables @Injectable() export class WhatsAppFactory { - private readonly logger = new Logger(WhatsAppFactory.name); - - constructor( - private readonly moduleRef: ModuleRef, - private readonly solidRegistry: SolidRegistry, - private readonly settingService: SettingService, - ) {} - - getWhatsappService(name?: string): IWhatsAppTransport { - const providerKey = - name || - this.settingService.getConfigValue("whatsappProvider"); - - if (!providerKey) { - throw new Error("Unable to resolve whatsapp provider"); - } - - const whatsappProviders = this.solidRegistry.getWhatsappProviders(); - - if (!whatsappProviders.length) { - throw new Error("No whatsapp providers are registered."); - } - - const whatsappServiceProvider = whatsappProviders.find((provider) => - provider.name?.toLowerCase().includes(providerKey.toLowerCase()), - ); - - if (!whatsappServiceProvider) { - throw new Error(`WhatsApp provider '${providerKey}' not found`); + private readonly logger = new Logger(this.constructor.name); + constructor( + private readonly moduleRef: ModuleRef, // Use the module ref to dynamically resolve the mail service + private readonly solidRegistry: SolidRegistry, + private readonly settingService: SettingService, + ) { } + + getWhatsappService(name: string = null): IWhatsAppTransport { + // This is the default provider + const whatsappServiceName = name || this.settingService.getConfigValue("whatsappProvider"); + if (!whatsappServiceName) { + throw new Error("Unable to resolve whatsapp provider") + } + const whatsappProviders = this.solidRegistry.getWhatsappProviders(); + + // Return the instance which matches the whatsappServiceName + if (!whatsappProviders.length) { + // throw new Error("No mail providers are registered."); + this.logger.error("No whatsapp providers are registered."); + } + + const whatsappServiceProvider = whatsappProviders.find(provider => provider.name === whatsappServiceName); + + return whatsappServiceProvider.instance as IWhatsAppTransport; } - return whatsappServiceProvider.instance as IWhatsAppTransport; - } -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 800b4617..4ff238df 100755 --- a/src/index.ts +++ b/src/index.ts @@ -323,7 +323,6 @@ export * from './services/solid-introspect.service' export * from './services/user.service' export * from './services/view-metadata.service' export * from './services/whatsapp/Msg91WhatsappService' //rename -export * from './services/whatsapp/GupshupOtpWhatsappService' export * from './services/setting.service' export * from './services/encryption.service' export * from './services/info.service' diff --git a/src/listeners/user-registration.listener.ts b/src/listeners/user-registration.listener.ts index 9915aa83..91703e9f 100755 --- a/src/listeners/user-registration.listener.ts +++ b/src/listeners/user-registration.listener.ts @@ -1,57 +1,14 @@ + import { User } from "../entities/user.entity"; import { OnEvent } from "@nestjs/event-emitter"; import { Injectable, Logger } from "@nestjs/common"; import { EventDetails, EventType } from "../interfaces"; -import { WhatsAppFactory } from "src/factories/whatsapp.factory"; @Injectable() export class UserRegistrationListener { - private readonly logger = new Logger(UserRegistrationListener.name); - - constructor(private readonly whatsAppFactory: WhatsAppFactory) {} - - @OnEvent(EventType.USER_REGISTERED) - async handleUserRegistration(event: EventDetails) { - this.logger.log(`User registered with details: ${JSON.stringify(event.payload)}`); - - const notifyTo = process.env.WHATSAPP_EVENT_NOTIFY_TO; - if (!notifyTo) { - this.logger.debug("WHATSAPP_EVENT_NOTIFY_TO not set. Skipping registration WhatsApp notification."); - return; - } - - try { - const whatsappService = this.whatsAppFactory.getWhatsappService(); - const username = event.payload?.username || "User"; - const userId = event.payload?.id || "N/A"; - - await whatsappService.sendWhatsAppMessage( - notifyTo, - "registration_event", - { - payload: { - channel: "whatsapp", - source: process.env.COMMON_GUPSHUP_WHATSAPP_SOURCE, - destination: notifyTo, - "src.name": process.env.COMMON_GUPSHUP_APP_NAME || "solidx", - message: { - type: "text", - text: `New user registered: ${username} (id: ${userId})`, - }, - }, - }, - ); - - this.logger.log(`Sent registration WhatsApp notification to ${notifyTo}`); - } catch (error: any) { - const status = error?.response?.status; - const responseData = error?.response?.data; - const errorMessage = error?.message; - const stack = error?.stack; - - this.logger.error( - `Failed to send registration WhatsApp notification to ${notifyTo}. status=${status ?? "unknown"}, response=${typeof responseData === "object" ? JSON.stringify(responseData) : responseData}, message=${errorMessage}, stack=${stack}`, - ); + private logger = new Logger(UserRegistrationListener.name); + @OnEvent(EventType.USER_REGISTERED) + handleUserRegistration(event: EventDetails) { + this.logger.log(`User registered with details: ${JSON.stringify(event.payload)}`); } - } -} +} \ No newline at end of file diff --git a/src/services/authentication.service.ts b/src/services/authentication.service.ts index 4d46daa2..4c98bd02 100755 --- a/src/services/authentication.service.ts +++ b/src/services/authentication.service.ts @@ -50,7 +50,6 @@ import { SettingService } from "./setting.service"; import { UserActivityHistoryService } from "./user-activity-history.service"; import { UserService } from "./user.service"; import { SmsFactory } from "src/factories/sms.factory"; -import { WhatsAppFactory } from "src/factories/whatsapp.factory"; import { SolidRegistry } from "src/helpers/solid-registry"; enum LoginProvider { @@ -80,7 +79,6 @@ export class AuthenticationService { private readonly mailServiceFactory: MailFactory, // private readonly smsService: Msg91OTPService, private readonly smsFactory: SmsFactory, - private readonly whatsAppFactory: WhatsAppFactory, private readonly eventEmitter: EventEmitter2, private readonly settingService: SettingService, private readonly roleMetadataService: RoleMetadataService, @@ -195,22 +193,11 @@ export class AuthenticationService { return this.performSignUp(signUpDto, new User(), this.userRepository); } - private async performSignUp( - signUpDto: SignUpDto, - entity: T, - repo: Repository, - ): Promise { + private async performSignUp(signUpDto: SignUpDto, entity: T, repo: Repository): Promise { try { - const onForcePasswordChange = - this.settingService.getConfigValue( - "forceChangePasswordOnFirstLogin", - ); - const activateUserOnRegistration = - this.settingService.getConfigValue( - "activateUserOnRegistration", - ); - const defaultRole = - this.settingService.getConfigValue("defaultRole"); + const onForcePasswordChange = this.settingService.getConfigValue("forceChangePasswordOnFirstLogin"); + const activateUserOnRegistration = this.settingService.getConfigValue("activateUserOnRegistration"); + const defaultRole = this.settingService.getConfigValue("defaultRole"); var { user, pwd, autoGeneratedPwd } = await this.populateForSignup( entity, @@ -224,19 +211,14 @@ export class AuthenticationService { } const savedUser = await repo.save(user); const userRoles = signUpDto.roles ?? []; - if ( - (signUpDto.roles?.length ?? 0) === 0 && - signUpDto.username !== "sa" && - defaultRole - ) { + if ((signUpDto.roles?.length ?? 0) === 0 && signUpDto.username !== "sa" && defaultRole) { userRoles.push(defaultRole); } await this.handlePostSignup(savedUser, userRoles, pwd, autoGeneratedPwd); - await this.handlePasswordlessSignupOtp(savedUser, signUpDto, autoGeneratedPwd, repo); - this.triggerRegistrationEvent(savedUser); return savedUser; - } catch (err: any) { + } + catch (err: any) { const pgUniqueViolationErrorCode = "23505"; if (err.code === pgUniqueViolationErrorCode) { throw new ConflictException( @@ -249,42 +231,6 @@ export class AuthenticationService { } } - private async handlePasswordlessSignupOtp( - user: T, - signUpDto: SignUpDto, - autoGeneratedPwd: string, - repo: Repository, - ): Promise { - const isPasswordProvided = !!signUpDto.password; - const isAutoGeneratedPassword = !!autoGeneratedPwd; - if (isPasswordProvided || isAutoGeneratedPassword) { - return; - } - - if (!user.mobile) { - this.logger.warn( - `Skipping passwordless signup OTP WhatsApp notification for user ${user.username}: mobile is missing.`, - ); - return; - } - - const isPasswordlessRegistrationEnabled = - await this.isPasswordlessRegistrationEnabled(); - if (!isPasswordlessRegistrationEnabled) { - return; - } - - await this.assignRegistrationOtp( - PasswordlessRegistrationValidateWhatSources.MOBILE, - user, - ); - await repo.save(user); - await this.notifyUserOnOtpInitiateRegistration( - user, - PasswordlessRegistrationValidateWhatSources.MOBILE, - ); - } - /** @deprecated Use IExtensionUserCreationProvider instead. Kept for backward compatibility. */ async signupForExtensionUser( signUpDto: SignUpDto, @@ -656,7 +602,7 @@ export class AuthenticationService { const companyLogo = await this.getCompanyLogo(); if ( registrationValidationSource === - PasswordlessRegistrationValidateWhatSources.EMAIL + PasswordlessLoginValidateWhatSources.EMAIL ) { const mailService = this.mailServiceFactory.getMailService(); mailService.sendEmailUsingTemplate( @@ -686,141 +632,25 @@ export class AuthenticationService { } if ( registrationValidationSource === - PasswordlessRegistrationValidateWhatSources.MOBILE + PasswordlessLoginValidateWhatSources.MOBILE ) { - const templateParams = { - solidAppName: - this.settingService.getConfigValue("appTitle"), - otp: user.mobileVerificationTokenOnRegistration, - mobileVerificationTokenOnRegistration: - user.mobileVerificationTokenOnRegistration, - firstName: user.username, - fullName: user.fullName ? user.fullName : user.username, - companyLogoUrl: companyLogo, - }; - - const whatsappDestination = this.normalizeWhatsAppDestination( + const smsService = this.smsFactory.getSmsService(); + smsService.sendSMSUsingTemplate( user.mobile, + "otp-on-register", + { + solidAppName: + this.settingService.getConfigValue("appTitle"), + otp: user.mobileVerificationTokenOnRegistration, + mobileVerificationTokenOnRegistration: + user.mobileVerificationTokenOnRegistration, + firstName: user.username, + fullName: user.fullName ? user.fullName : user.username, + companyLogoUrl: companyLogo, + }, + this.settingService.getConfigValue("shouldQueueSms"), ); - const gupshupTemplateAppName = - process.env.COMMON_GUPSHUP_APP_NAME || "Gupshup"; - const whatsappTemplateId = - this.settingService.getConfigValue( - "otpWhatsappTemplateId", - ) || "common_otp"; - const whatsappIndependentEnabled = - this.settingService.getConfigValue( - "otpWhatsappIndependentEnabled", - ) !== false; - - let smsSent = false; - let whatsappSent = false; - let smsErrorMessage: string | undefined; - let whatsappErrorMessage: string | undefined; - - this.logger.debug( - `OTP SMS send attempt: destination=${user.mobile}, whatsappDestination=${whatsappDestination}`, - ); - - try { - const smsService = this.smsFactory.getSmsService(); - await smsService.sendSMSUsingTemplate( - user.mobile, - "otp-on-register", - templateParams, - false, - ); - smsSent = true; - } catch (smsError: any) { - smsErrorMessage = smsError?.message; - this.logger.warn( - `OTP SMS failed: destination=${user.mobile}, message=${smsErrorMessage}`, - ); - } - - if (whatsappIndependentEnabled) { - if (!whatsappDestination) { - whatsappErrorMessage = "Normalized WhatsApp destination is empty"; - this.logger.error( - `Independent OTP WhatsApp skipped: destination=${user.mobile}, message=${whatsappErrorMessage}`, - ); - } else { - this.logger.debug( - `Independent OTP WhatsApp send attempt: destination=${user.mobile}, whatsappDestination=${whatsappDestination}, templateId=${whatsappTemplateId}`, - ); - try { - await this.sendOtpToWhatsappProvider( - whatsappDestination, - String(whatsappTemplateId), - String(gupshupTemplateAppName), - String(templateParams.otp || ""), - ); - whatsappSent = true; - this.logger.log( - `Independent OTP WhatsApp success: destination=${user.mobile}, whatsappDestination=${whatsappDestination}, templateId=${whatsappTemplateId}`, - ); - } catch (waError: any) { - whatsappErrorMessage = waError?.message; - this.logger.error( - `Independent OTP WhatsApp failed: destination=${user.mobile}, whatsappDestination=${whatsappDestination}, templateId=${whatsappTemplateId}, message=${whatsappErrorMessage}`, - ); - } - } - } - - if (!smsSent && !whatsappSent) { - throw new Error( - `OTP delivery failed on both channels. smsError=${smsErrorMessage || "unknown"}, whatsappError=${whatsappErrorMessage || "disabled/unknown"}`, - ); - } - } - } - - private normalizeWhatsAppDestination(rawMobile: string): string { - const raw = (rawMobile || "").trim(); - let sanitized = raw.replace(/[^\d+]/g, ""); - - if (sanitized.startsWith("00")) { - sanitized = `+${sanitized.slice(2)}`; - } - - const defaultDialCode = String( - this.settingService.getConfigValue( - "otpDefaultCountryDialCode", - ) || "", - ).replace(/\D/g, ""); - - if (sanitized.startsWith("+")) { - const e164Digits = sanitized.slice(1).replace(/\D/g, ""); - if (e164Digits.length >= 8 && e164Digits.length <= 15) { - return e164Digits; - } - } - - const digits = sanitized.replace(/\D/g, ""); - - if (digits.length >= 11 && digits.length <= 15) { - return digits; } - - if (digits.length === 10 && defaultDialCode) { - return `${defaultDialCode}${digits}`; - } - - return digits; - } - - private async sendOtpToWhatsappProvider( - destination: string, - templateId: string, - appName: string, - otp: string, - ): Promise { - const whatsappService = this.whatsAppFactory.getWhatsappService(); - await whatsappService.sendWhatsAppMessage(destination, null, { - type: "text", - text: `${appName} OTP is ${otp}. It is valid for 10 mins.`, - }); } async otpConfirmRegistration(confirmSignUpDto: OTPConfirmOTPDto) { @@ -923,7 +753,7 @@ export class AuthenticationService { this.resolvePasswordlessValidationSource(); if ( registrationValidationSource === - PasswordlessRegistrationValidateWhatSources.EMAIL + PasswordlessLoginValidateWhatSources.EMAIL ) { if (!user.emailVerifiedOnRegistrationAt) { return false; @@ -931,7 +761,7 @@ export class AuthenticationService { } if ( registrationValidationSource === - PasswordlessRegistrationValidateWhatSources.MOBILE + PasswordlessLoginValidateWhatSources.MOBILE ) { if (!user.mobileVerifiedOnRegistrationAt) { return false; @@ -1046,7 +876,7 @@ export class AuthenticationService { const dummyOtp = this.getDummyOtpForUser(user); if (!dummyOtp) { await this.assignLoginOtp(user, type); - await this.notifyUserOnOtpInititateLogin(user, type); + this.notifyUserOnOtpInititateLogin(user, type); } return this.buildLoginOtpResponse(user, type); } @@ -1171,88 +1001,21 @@ export class AuthenticationService { ); } if (loginType === PasswordlessLoginValidateWhatSources.MOBILE) { - const templateParams = { - solidAppName: - this.settingService.getConfigValue("appTitle"), - otp: user.mobileVerificationTokenOnLogin, - mobileVerificationTokenOnLogin: user.mobileVerificationTokenOnLogin, - firstName: user.username, - fullName: user.fullName ? user.fullName : user.username, - companyLogoUrl: companyLogo, - }; - - const whatsappDestination = this.normalizeWhatsAppDestination(user.mobile); - const gupshupTemplateAppName = - process.env.COMMON_GUPSHUP_APP_NAME || "Gupshup"; - const whatsappTemplateId = - this.settingService.getConfigValue( - "otpWhatsappTemplateId", - ) || "common_otp"; - const whatsappIndependentEnabled = - this.settingService.getConfigValue( - "otpWhatsappIndependentEnabled", - ) !== false; - - let smsSent = false; - let whatsappSent = false; - let smsErrorMessage: string | undefined; - let whatsappErrorMessage: string | undefined; - - this.logger.debug( - `OTP LOGIN SMS send attempt: destination=${user.mobile}, whatsappDestination=${whatsappDestination}`, + const smsService = this.smsFactory.getSmsService(); + smsService.sendSMSUsingTemplate( + user.mobile, + "otp-on-login", + { + solidAppName: + this.settingService.getConfigValue("appTitle"), + otp: user.mobileVerificationTokenOnLogin, + mobileVerificationTokenOnLogin: user.mobileVerificationTokenOnLogin, + firstName: user.username, + fullName: user.fullName ? user.fullName : user.username, + companyLogoUrl: companyLogo, + }, + this.settingService.getConfigValue("shouldQueueSms"), ); - - try { - const smsService = this.smsFactory.getSmsService(); - await smsService.sendSMSUsingTemplate( - user.mobile, - "otp-on-login", - templateParams, - false, - ); - smsSent = true; - } catch (smsError: any) { - smsErrorMessage = smsError?.message; - this.logger.warn( - `OTP LOGIN SMS failed: destination=${user.mobile}, message=${smsErrorMessage}`, - ); - } - - if (whatsappIndependentEnabled) { - if (!whatsappDestination) { - whatsappErrorMessage = "Normalized WhatsApp destination is empty"; - this.logger.error( - `OTP LOGIN WhatsApp skipped: destination=${user.mobile}, message=${whatsappErrorMessage}`, - ); - } else { - this.logger.debug( - `OTP LOGIN WhatsApp send attempt: destination=${user.mobile}, whatsappDestination=${whatsappDestination}, templateId=${whatsappTemplateId}`, - ); - try { - await this.sendOtpToWhatsappProvider( - whatsappDestination, - String(whatsappTemplateId), - String(gupshupTemplateAppName), - String(templateParams.otp || ""), - ); - whatsappSent = true; - this.logger.log( - `OTP LOGIN WhatsApp success: destination=${user.mobile}, whatsappDestination=${whatsappDestination}, templateId=${whatsappTemplateId}`, - ); - } catch (waError: any) { - whatsappErrorMessage = waError?.message; - this.logger.error( - `OTP LOGIN WhatsApp failed: destination=${user.mobile}, whatsappDestination=${whatsappDestination}, templateId=${whatsappTemplateId}, message=${whatsappErrorMessage}`, - ); - } - } - } - - if (!smsSent && !whatsappSent) { - throw new Error( - `OTP LOGIN delivery failed on both channels. smsError=${smsErrorMessage || "unknown"}, whatsappError=${whatsappErrorMessage || "disabled/unknown"}`, - ); - } } } @@ -1531,7 +1294,7 @@ export class AuthenticationService { // Assuming all users do not have mobile as mandatory. if ( forgotPasswordSendVerificationTokenOn == - ForgotPasswordSendVerificationTokenOn.MOBILE && + ForgotPasswordSendVerificationTokenOn.MOBILE && user.mobile ) { const smsService = this.smsFactory.getSmsService(); @@ -1560,10 +1323,12 @@ export class AuthenticationService { const user = await this.resolveUserByVerificationToken( confirmForgotPasswordDto.verificationToken, ); - if (!user) throw new UnauthorizedException("Invalid verification token"); + if (!user) + throw new UnauthorizedException("Invalid verification token"); if (user.lastLoginProvider !== "local") throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS); - if (!user.active) throw new UnauthorizedException("User is inactive"); + if (!user.active) + throw new UnauthorizedException("User is inactive"); // 1) Atomically consume the token (only one request can succeed) const { affected } = await m @@ -1655,7 +1420,7 @@ export class AuthenticationService { // Assuming all users do not have mobile as mandatory. if ( forgotPasswordSendVerificationTokenOn == - ForgotPasswordSendVerificationTokenOn.MOBILE && + ForgotPasswordSendVerificationTokenOn.MOBILE && user.mobile ) { const smsService = this.smsFactory.getSmsService(); diff --git a/src/services/settings/default-settings-provider.service.ts b/src/services/settings/default-settings-provider.service.ts index bdb7d4f3..5a1ac4b1 100644 --- a/src/services/settings/default-settings-provider.service.ts +++ b/src/services/settings/default-settings-provider.service.ts @@ -779,46 +779,6 @@ const getSolidCoreSettings = (isProd: boolean) => value: parseInt(process.env.IAM_OTP_EXPIRY ?? "10"), level: SettingLevel.SystemEnv, }, - { - moduleName: "solid-core", - key: "otpWhatsappFallbackEnabled", - value: (process.env.IAM_OTP_WHATSAPP_FALLBACK_ENABLED ?? "true") === "true", - level: SettingLevel.SystemAdminEditable, - label: "OTP WhatsApp Fallback Enabled", - group: "authentication-settings", - sortOrder: 85, - controlType: "boolean", - }, - { - moduleName: "solid-core", - key: "otpWhatsappTemplateId", - value: process.env.IAM_OTP_WHATSAPP_TEMPLATE_ID ?? "common_otp", - level: SettingLevel.SystemAdminEditable, - label: "OTP WhatsApp Template ID", - group: "authentication-settings", - sortOrder: 86, - controlType: "shortText", - }, - { - moduleName: "solid-core", - key: "otpWhatsappIndependentEnabled", - value: (process.env.IAM_OTP_WHATSAPP_INDEPENDENT_ENABLED ?? "true") === "true", - level: SettingLevel.SystemAdminEditable, - label: "OTP WhatsApp Independent Enabled", - group: "authentication-settings", - sortOrder: 87, - controlType: "boolean", - }, - { - moduleName: "solid-core", - key: "otpDefaultCountryDialCode", - value: process.env.IAM_OTP_DEFAULT_COUNTRY_DIAL_CODE ?? "", - level: SettingLevel.SystemAdminEditable, - label: "OTP Default Country Dial Code", - group: "authentication-settings", - sortOrder: 88, - controlType: "shortText", - }, { moduleName: "solid-core", key: "forgotPasswordVerificationTokenExpiry", @@ -1218,64 +1178,6 @@ const getSolidCoreSettings = (isProd: boolean) => sortOrder: 30, controlType: "shortText", }, - { - moduleName: "solid-core", - key: "metaWhatsappApiUrl", - value: process.env.COMMON_META_WHATSAPP_API_URL || "https://graph.facebook.com", - level: SettingLevel.SystemAdminReadonly, - label: "Meta WhatsApp API URL", - group: "whatsapp-settings", - sortOrder: 40, - controlType: "shortText", - }, - { - moduleName: "solid-core", - key: "metaWhatsappApiVersion", - value: process.env.COMMON_META_WHATSAPP_API_VERSION || "v23.0", - level: SettingLevel.SystemAdminReadonly, - label: "Meta WhatsApp API Version", - group: "whatsapp-settings", - sortOrder: 50, - controlType: "shortText", - }, - { - moduleName: "solid-core", - key: "metaWhatsappPhoneNumberId", - value: process.env.COMMON_META_WHATSAPP_PHONE_NUMBER_ID, - level: SettingLevel.SystemAdminReadonly, - label: "Meta WhatsApp Phone Number ID", - group: "whatsapp-settings", - sortOrder: 60, - controlType: "shortText", - }, - { - moduleName: "solid-core", - key: "metaWhatsappBusinessAccountId", - value: process.env.COMMON_META_WHATSAPP_BUSINESS_ACCOUNT_ID, - level: SettingLevel.SystemAdminReadonly, - label: "Meta WhatsApp Business Account ID", - group: "whatsapp-settings", - sortOrder: 70, - controlType: "shortText", - }, - { - moduleName: "solid-core", - key: "metaWhatsappAccessToken", - value: process.env.COMMON_META_WHATSAPP_ACCESS_TOKEN, - level: SettingLevel.SystemEnv, - }, - { - moduleName: "solid-core", - key: "metaWhatsappWebhookVerifyToken", - value: process.env.COMMON_META_WHATSAPP_WEBHOOK_VERIFY_TOKEN, - level: SettingLevel.SystemEnv, - }, - { - moduleName: "solid-core", - key: "metaWhatsappAppSecret", - value: process.env.COMMON_META_WHATSAPP_APP_SECRET, - level: SettingLevel.SystemEnv, - }, ] as const satisfies SettingDefinition[]; // 2. diff --git a/src/services/user.service.ts b/src/services/user.service.ts index b527ef68..d13e96d3 100755 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -285,7 +285,7 @@ export class UserService extends CRUDService { } async resolveUserOnOauthFacebook(oauthUserDto: OauthUserDto): Promise { - const normalizedEmail = oauthUserDto.email?.trim().toLowerCase(); + const normalizedEmail = oauthUserDto.email?.trim().toLowerCase() || null; let user: User | null = null; if (oauthUserDto.providerId) { diff --git a/src/services/whatsapp/GupshupOtpWhatsappService.ts b/src/services/whatsapp/GupshupOtpWhatsappService.ts deleted file mode 100644 index fccfc12b..00000000 --- a/src/services/whatsapp/GupshupOtpWhatsappService.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { HttpService } from "@nestjs/axios"; -import { Injectable, Logger } from "@nestjs/common"; -import { AxiosError } from "axios"; -import { WhatsAppProvider } from "src/decorators/whatsapp-provider.decorator"; -import { IWhatsAppTransport } from "src/interfaces"; - -@Injectable() -@WhatsAppProvider() -export class GupshupOtpWhatsappService implements IWhatsAppTransport { - private readonly logger = new Logger(GupshupOtpWhatsappService.name); - - constructor(private readonly httpService: HttpService) {} - - async sendWhatsAppMessage( - to: string, - templateId: string, - parameters: any, - parentEntity?: any, - parentEntityId?: any, - ): Promise { - if (!to) { - throw new Error("WhatsApp destination number is required"); - } - - const payload = parameters?.payload; - if (payload?.message?.type === "text" && payload?.message?.text) { - await this.sendTextMessage( - payload.destination || to, - payload.message.text, - payload.source, - payload["src.name"], - ); - return { to, templateId, parameters, parentEntity, parentEntityId }; - } - - if (parameters?.type === "text" && parameters?.text) { - await this.sendTextMessage(to, parameters.text); - return { to, templateId, parameters, parentEntity, parentEntityId }; - } - - if (!templateId) { - throw new Error("WhatsApp templateId is required for template message"); - } - - const bodyParams = Array.isArray(parameters) - ? parameters - : Array.isArray(parameters?.body) - ? parameters.body - : []; - - await this.sendOtpTemplate(to, templateId, bodyParams.map((x) => String(x))); - return { to, templateId, parameters, parentEntity, parentEntityId }; - } - - private async sendTextMessage( - destination: string, - text: string, - sourceOverride?: string, - appNameOverride?: string, - ): Promise { - const apiKey = - process.env.COMMON_GUPSHUP_WHATSAPP_API_KEY || - process.env.GUPSHUP_API_KEY; - const msgUrl = - process.env.COMMON_GUPSHUP_WHATSAPP_API_URL || - process.env.GUPSHUP_API_URL || - "https://api.gupshup.io/wa/api/v1/msg"; - const source = - sourceOverride || - process.env.COMMON_GUPSHUP_WHATSAPP_SOURCE || - process.env.GUPSHUP_SOURCE_NUMBER; - const appName = - appNameOverride || process.env.COMMON_GUPSHUP_APP_NAME || "solidx"; - - if (!apiKey || !msgUrl || !source) { - throw new Error("Missing Gupshup WhatsApp configuration for text message"); - } - - const rawDestination = destination.replace(/\D/g, ""); - const params = new URLSearchParams(); - params.append("channel", "whatsapp"); - params.append("source", source); - params.append("destination", rawDestination); - params.append("src.name", appName); - params.append("message", JSON.stringify({ type: "text", text })); - - await this.httpService.axiosRef.post(msgUrl, params.toString(), { - headers: { - apikey: apiKey, - "Content-Type": "application/x-www-form-urlencoded", - }, - }); - } - - async sendOtpTemplate( - destination: string, - templateId: string, - bodyParams: string[], - ): Promise { - const apiKey = - process.env.COMMON_GUPSHUP_WHATSAPP_API_KEY || - process.env.GUPSHUP_API_KEY; - const baseUrl = - process.env.COMMON_GUPSHUP_WHATSAPP_API_URL || - process.env.GUPSHUP_API_URL || - "https://api.gupshup.io/wa/api/v1/msg"; - const templateUrl = - process.env.COMMON_GUPSHUP_WHATSAPP_TEMPLATE_API_URL || - baseUrl.replace(/\/msg$/, "/template/msg"); - const source = - process.env.COMMON_GUPSHUP_WHATSAPP_SOURCE || - process.env.GUPSHUP_SOURCE_NUMBER; - const appName = process.env.COMMON_GUPSHUP_APP_NAME || "solidx"; - - if (!apiKey || !templateUrl || !source) { - throw new Error("Missing Gupshup OTP WhatsApp configuration"); - } - - if (!destination || !String(destination).trim()) { - throw new Error("WhatsApp destination is empty"); - } - - try { - const rawDestination = destination.replace(/\D/g, ""); - const params = new URLSearchParams(); - params.append("channel", "whatsapp"); - params.append("source", source); - params.append("destination", rawDestination); - params.append( - "to", - rawDestination.startsWith("+") - ? rawDestination - : `+${rawDestination}`, - ); - params.append("src.name", appName); - params.append( - "template", - JSON.stringify({ - id: templateId, - params: bodyParams, - }), - ); - - this.logger.debug( - `Gupshup OTP outbound (template): endpoint=${templateUrl}, source=${source}, destination=${rawDestination}, to=${rawDestination.startsWith("+") ? rawDestination : `+${rawDestination}`}, templateId=${templateId}, params=${JSON.stringify(bodyParams)}`, - ); - - const response = await this.httpService.axiosRef.post( - templateUrl, - params.toString(), - { - headers: { - apikey: apiKey, - "Content-Type": "application/x-www-form-urlencoded", - }, - }, - ); - - this.logger.debug( - `Gupshup response: ${response.status}, data=${JSON.stringify(response.data)}`, - ); - - this.logger.debug( - `Independent OTP WhatsApp sent to ${rawDestination} template=${templateId} via template endpoint`, - ); - } catch (error) { - const axiosError = error as AxiosError; - this.logger.error( - `Independent OTP WhatsApp failed: destination=${destination}, templateId=${templateId}, status=${axiosError.response?.status ?? "unknown"}, response=${typeof axiosError.response?.data === "object" ? JSON.stringify(axiosError.response?.data) : axiosError.response?.data}, url=${templateUrl}`, - ); - throw error; - } - } -} diff --git a/src/services/whatsapp/MetaCloudWhatsappService.ts b/src/services/whatsapp/MetaCloudWhatsappService.ts deleted file mode 100644 index c709766b..00000000 --- a/src/services/whatsapp/MetaCloudWhatsappService.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { HttpService } from "@nestjs/axios"; -import { Injectable, Logger } from "@nestjs/common"; -import { AxiosError } from "axios"; -import { WhatsAppProvider } from "src/decorators/whatsapp-provider.decorator"; -import { IWhatsAppTransport } from "src/interfaces"; -import { QueueMessage } from "src/interfaces/mq"; -import { SettingService } from "src/services/setting.service"; -import type { SolidCoreSetting } from "src/services/settings/default-settings-provider.service"; - -type MetaTemplatePayload = { - type?: "template"; - templateName?: string; - templateId?: string; - languageCode?: string; - body?: string[]; - headerText?: string; - imageLink?: string; -}; - -type MetaTextPayload = { - type?: "text"; - text?: string; - previewUrl?: boolean; -}; - -@Injectable() -@WhatsAppProvider() -export class MetaCloudWhatsappService implements IWhatsAppTransport { - readonly logger = new Logger(MetaCloudWhatsappService.name); - - constructor( - private readonly httpService: HttpService, - private readonly settingService: SettingService, - ) {} - - async sendWhatsAppMessage( - to: string, - templateId: string, - parameters: any, - parentEntity?: any, - parentEntityId?: any, - ): Promise { - const message: QueueMessage = { - payload: { - to, - templateId, - ...parameters, - }, - parentEntity, - parentEntityId, - }; - - await this.sendWhatsAppMessageSynchronously(message); - return message; - } - - async sendWhatsAppMessageSynchronously(message: QueueMessage): Promise { - const phoneNumberId = this.settingService.getConfigValue( - "metaWhatsappPhoneNumberId", - ); - const apiVersion = this.settingService.getConfigValue( - "metaWhatsappApiVersion", - ); - const apiBaseUrl = this.settingService.getConfigValue( - "metaWhatsappApiUrl", - ); - const accessToken = this.settingService.getConfigValue( - "metaWhatsappAccessToken", - ); - - if (!phoneNumberId || !apiVersion || !apiBaseUrl || !accessToken) { - throw new Error( - "Missing Meta WhatsApp configuration. Set metaWhatsappApiUrl, metaWhatsappApiVersion, metaWhatsappPhoneNumberId, metaWhatsappAccessToken.", - ); - } - - const requestBody = this.createWhatsappRequest(message); - const url = `${String(apiBaseUrl).replace(/\/$/, "")}/${apiVersion}/${phoneNumberId}/messages`; - - try { - await this.httpService.axiosRef.post(url, requestBody, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Content-Type": "application/json", - }, - }); - this.logger.debug( - `Sent Meta WhatsApp message to ${message.payload?.to} with type ${requestBody.type}`, - ); - } catch (error) { - const axiosError = error as AxiosError; - const status = axiosError.response?.status; - const data = axiosError.response?.data; - this.logger.error( - `Meta WhatsApp send failed: status=${status ?? "unknown"}, url=${url}, response=${typeof data === "object" ? JSON.stringify(data) : data}`, - ); - throw error; - } - } - - private createWhatsappRequest(message: QueueMessage): any { - const payload = message?.payload ?? {}; - - if (payload?.payload) { - const normalizedFromWrappedPayload = this.normalizeWrappedPayload(payload.payload); - if (normalizedFromWrappedPayload) { - return normalizedFromWrappedPayload; - } - return payload.payload; - } - - const to = this.normalizePhone(payload.to); - const templatePayload: MetaTemplatePayload = payload; - const textPayload: MetaTextPayload = payload; - - if (textPayload.type === "text" || textPayload.text) { - return { - messaging_product: "whatsapp", - recipient_type: "individual", - to, - type: "text", - text: { - body: textPayload.text ?? "", - preview_url: Boolean(textPayload.previewUrl), - }, - }; - } - - const templateName = payload.templateId || templatePayload.templateId || templatePayload.templateName; - if (!templateName) { - throw new Error( - "Meta WhatsApp template name is missing. Provide templateId or parameters.templateName.", - ); - } - - const components: any[] = []; - if (templatePayload.headerText) { - components.push({ - type: "header", - parameters: [ - { - type: "text", - text: templatePayload.headerText, - }, - ], - }); - } else if (templatePayload.imageLink) { - components.push({ - type: "header", - parameters: [ - { - type: "image", - image: { link: templatePayload.imageLink }, - }, - ], - }); - } - - if (Array.isArray(templatePayload.body) && templatePayload.body.length > 0) { - components.push({ - type: "body", - parameters: templatePayload.body.map((entry) => ({ - type: "text", - text: String(entry), - })), - }); - } - - return { - messaging_product: "whatsapp", - recipient_type: "individual", - to, - type: "template", - template: { - name: templateName, - language: { - code: templatePayload.languageCode || "en", - }, - ...(components.length > 0 ? { components } : {}), - }, - }; - } - - private normalizeWrappedPayload(payload: any): any | null { - if (!payload || typeof payload !== "object") { - return null; - } - - if (payload.messaging_product && payload.to && payload.type) { - return payload; - } - - const destination = payload.destination || payload.to; - const message = payload.message || {}; - if (!destination || !message.type) { - return null; - } - - if (message.type === "text" && message.text) { - return { - messaging_product: "whatsapp", - recipient_type: "individual", - to: this.normalizePhone(destination), - type: "text", - text: { - body: String(message.text), - preview_url: false, - }, - }; - } - - if (message.type === "template" && message.template?.id) { - const params = Array.isArray(message.template?.params) - ? message.template.params - : []; - return { - messaging_product: "whatsapp", - recipient_type: "individual", - to: this.normalizePhone(destination), - type: "template", - template: { - name: String(message.template.id), - language: { - code: "en", - }, - ...(params.length > 0 - ? { - components: [ - { - type: "body", - parameters: params.map((entry: any) => ({ - type: "text", - text: String(entry), - })), - }, - ], - } - : {}), - }, - }; - } - - return null; - } - - private normalizePhone(phone: string): string { - const digits = String(phone || "").replace(/\D/g, ""); - if (!digits) { - throw new Error("Destination phone number is required for WhatsApp message."); - } - return digits; - } -} diff --git a/src/solid-core.module.ts b/src/solid-core.module.ts index a2a640d5..0baf971b 100755 --- a/src/solid-core.module.ts +++ b/src/solid-core.module.ts @@ -1,7 +1,7 @@ -import "multer"; -import { Global, MiddlewareConsumer, Module, NestModule } from "@nestjs/common"; -import * as express from "express"; -import { ConfigModule, ConfigService } from "@nestjs/config"; +import 'multer'; +import { Global, MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; +import * as express from 'express'; +import { ConfigModule, ConfigService } from '@nestjs/config'; import { APP_FILTER, APP_GUARD, @@ -9,141 +9,136 @@ import { DiscoveryService, MetadataScanner, Reflector, -} from "@nestjs/core"; -import { MulterModule } from "@nestjs/platform-express"; -import { TypeOrmModule } from "@nestjs/typeorm"; -import { RemoveFieldsCommand } from "./commands/remove-fields.command"; -import { FieldMetadataController } from "./controllers/field-metadata.controller"; -import { MediaStorageProviderMetadataController } from "./controllers/media-storage-provider-metadata.controller"; -import { ModelMetadataController } from "./controllers/model-metadata.controller"; -import { ModuleMetadataController } from "./controllers/module-metadata.controller"; -import { TestController } from "./controllers/test.controller"; -import { FieldMetadata } from "./entities/field-metadata.entity"; -import { ListOfValues } from "./entities/list-of-values.entity"; -import { MediaStorageProviderMetadata } from "./entities/media-storage-provider-metadata.entity"; -import { Media } from "./entities/media.entity"; -import { ModelMetadata } from "./entities/model-metadata.entity"; -import { ModuleMetadata } from "./entities/module-metadata.entity"; -import { CommandService } from "./helpers/command.service"; -import { SchematicService } from "./helpers/schematic.service"; -import { ListOfValuesSelectionProvider } from "./services/selection-providers/list-of-values-selection-providers.service"; -import { PseudoForeignKeySelectionProvider } from "./services/selection-providers/pseudo-foreign-key-selection-provider.service"; -import { ModuleMetadataSeederService } from "./seeders/module-metadata-seeder.service"; -import { ModuleTestDataService } from "./seeders/module-test-data.service"; -import { CrudHelperService } from "./services/crud-helper.service"; -import { FieldMetadataService } from "./services/field-metadata.service"; -import { ListOfValuesService } from "./services/list-of-values.service"; +} from '@nestjs/core'; +import { MulterModule } from '@nestjs/platform-express'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { RemoveFieldsCommand } from './commands/remove-fields.command'; +import { FieldMetadataController } from './controllers/field-metadata.controller'; +import { MediaStorageProviderMetadataController } from './controllers/media-storage-provider-metadata.controller'; +import { ModelMetadataController } from './controllers/model-metadata.controller'; +import { ModuleMetadataController } from './controllers/module-metadata.controller'; +import { TestController } from './controllers/test.controller'; +import { FieldMetadata } from './entities/field-metadata.entity'; +import { ListOfValues } from './entities/list-of-values.entity'; +import { MediaStorageProviderMetadata } from './entities/media-storage-provider-metadata.entity'; +import { Media } from './entities/media.entity'; +import { ModelMetadata } from './entities/model-metadata.entity'; +import { ModuleMetadata } from './entities/module-metadata.entity'; +import { CommandService } from './helpers/command.service'; +import { SchematicService } from './helpers/schematic.service'; +import { ListOfValuesSelectionProvider } from './services/selection-providers/list-of-values-selection-providers.service'; +import { PseudoForeignKeySelectionProvider } from './services/selection-providers/pseudo-foreign-key-selection-provider.service'; +import { ModuleMetadataSeederService } from './seeders/module-metadata-seeder.service'; +import { ModuleTestDataService } from './seeders/module-test-data.service'; +import { CrudHelperService } from './services/crud-helper.service'; +import { FieldMetadataService } from './services/field-metadata.service'; +import { ListOfValuesService } from './services/list-of-values.service'; // import { MediaStorageProviderMetadataSeederService } from './services/media-storage-provider-metadata-seeder.service'; -import { MediaStorageProviderMetadataService } from "./services/media-storage-provider-metadata.service"; -import { MediaService } from "./services/media.service"; -import { ModelMetadataService } from "./services/model-metadata.service"; -import { ModuleMetadataService } from "./services/module-metadata.service"; -import { SolidIntrospectService } from "./services/solid-introspect.service"; +import { MediaStorageProviderMetadataService } from './services/media-storage-provider-metadata.service'; +import { MediaService } from './services/media.service'; +import { ModelMetadataService } from './services/model-metadata.service'; +import { ModuleMetadataService } from './services/module-metadata.service'; +import { SolidIntrospectService } from './services/solid-introspect.service'; // import { ListOfComputedFieldProvider } from './providers/list-of-computed-field-provider.service'; -import { ServeStaticModule } from "@nestjs/serve-static"; -import { join } from "path"; -import { RefreshModelCommand } from "./commands/refresh-model.command"; -import { MediaController } from "./controllers/media.controller"; +import { ServeStaticModule } from '@nestjs/serve-static'; +import { join } from 'path'; +import { RefreshModelCommand } from './commands/refresh-model.command'; +import { MediaController } from './controllers/media.controller'; -import { RefreshModuleCommand } from "./commands/refresh-module.command"; -import { ModelMetadataSubscriber } from "./subscribers/model-metadata.subscriber"; +import { RefreshModuleCommand } from './commands/refresh-module.command'; +import { ModelMetadataSubscriber } from './subscribers/model-metadata.subscriber'; -import { ViewMetadataController } from "./controllers/view-metadata.controller"; -import { ViewMetadata } from "./entities/view-metadata.entity"; -import { ViewMetadataService } from "./services/view-metadata.service"; +import { ViewMetadataController } from './controllers/view-metadata.controller'; +import { ViewMetadata } from './entities/view-metadata.entity'; +import { ViewMetadataService } from './services/view-metadata.service'; -import { ActionMetadataController } from "./controllers/action-metadata.controller"; -import { ActionMetadata } from "./entities/action-metadata.entity"; -import { ActionMetadataService } from "./services/action-metadata.service"; +import { ActionMetadataController } from './controllers/action-metadata.controller'; +import { ActionMetadata } from './entities/action-metadata.entity'; +import { ActionMetadataService } from './services/action-metadata.service'; -import { FacebookAuthenticationController } from "./controllers/facebook-authentication.controller"; -import { MicrosoftAuthenticationController } from "./controllers/microsoft-authentication.controller"; -import { FacebookOAuthStrategy } from "./passport-strategies/facebook-oauth.strategy"; -import { MicrosoftOAuthStrategy } from "./passport-strategies/microsoft-oauth.strategy"; +import { FacebookAuthenticationController } from './controllers/facebook-authentication.controller'; +import { MicrosoftAuthenticationController } from './controllers/microsoft-authentication.controller'; +import { FacebookOAuthStrategy } from './passport-strategies/facebook-oauth.strategy'; +import { MicrosoftOAuthStrategy } from './passport-strategies/microsoft-oauth.strategy'; -import { GupshupOtpWhatsappService } from "./services/whatsapp/GupshupOtpWhatsappService"; -import { MetaCloudWhatsappService } from "./services/whatsapp/MetaCloudWhatsappService"; -import { GupshupWebhookController } from "./controllers/gupshup-webhook.controller"; -import { MetaCloudWhatsappWebhookController } from "./controllers/meta-cloud-whatsapp-webhook.controller"; - -import { HttpModule } from "@nestjs/axios"; -import { JwtModule } from "@nestjs/jwt"; -import { SeedCommand } from "./commands/seed.command"; -import { TestDataCommand } from "./commands/test-data.command"; -import { TestRunCommand } from "./commands/run-tests.command"; -import { TestCommand } from "./commands/test.command"; -import { AuthenticationController } from "./controllers/authentication.controller"; -import { EmailTemplateController } from "./controllers/email-template.controller"; -import { GoogleAuthenticationController } from "./controllers/google-authentication.controller"; -import { MenuItemMetadataController } from "./controllers/menu-item-metadata.controller"; -import { MqMessageQueueController } from "./controllers/mq-message-queue.controller"; -import { MqMessageController } from "./controllers/mq-message.controller"; -import { OTPAuthenticationController } from "./controllers/otp-authentication.controller"; -import { ServiceController } from "./controllers/service.controller"; -import { SmsTemplateController } from "./controllers/sms-template.controller"; -import { TestQueueController } from "./controllers/test-queue.controller"; -import { EmailAttachment } from "./entities/email-attachment.entity"; -import { EmailTemplate } from "./entities/email-template.entity"; -import { MenuItemMetadata } from "./entities/menu-item-metadata.entity"; -import { MqMessageQueue } from "./entities/mq-message-queue.entity"; -import { MqMessage } from "./entities/mq-message.entity"; -import { SmsTemplate } from "./entities/sms-template.entity"; -import { AccessTokenGuard } from "./guards/access-token.guard"; -import { ApiKeyGuard } from "./guards/api-key.guard"; -import { AuthenticationGuard } from "./guards/authentication.guard"; -import { PermissionsGuard } from "./guards/permissions.guard"; -import { SolidRegistry } from "./helpers/solid-registry"; -import { LoggingInterceptor } from "./interceptors/logging.interceptor"; -import { ApiEmailQueuePublisher } from "./jobs/rabbitmq/api-email-publisher.service"; -import { ApiEmailQueueSubscriber } from "./jobs/rabbitmq/api-email-subscriber.service"; -import { TestQueuePublisherDatabase } from "./jobs/database/test-queue-publisher-database.service"; -import { TestQueueSubscriberDatabase } from "./jobs/database/test-queue-subscriber-database.service"; -import { TestQueuePublisherRedis } from "./jobs/redis/test-queue-publisher-redis.service"; -import { TestQueueSubscriberRedis } from "./jobs/redis/test-queue-subscriber-redis.service"; -import { Msg91WhatsappQueuePublisher } from "./jobs/rabbitmq/msg91-whatsapp-publisher.service"; -import { Msg91WhatsappQueueSubscriber } from "./jobs/rabbitmq/msg91-whatsapp-subscriber.service"; -import { Msg91OTPQueuePublisher } from "./jobs/rabbitmq/msg91-otp-publisher.service"; -import { Msg91OTPQueueSubscriber } from "./jobs/rabbitmq/msg91-otp-subscriber.service"; -import { Msg91SmsQueuePublisher } from "./jobs/rabbitmq/msg91-sms-publisher.service"; -import { Msg91SmsQueueSubscriber } from "./jobs/rabbitmq/msg91-sms-subscriber.service"; -import { SmtpEmailQueuePublisherRabbitmq } from "./jobs/rabbitmq/smtp-email-publisher.service"; -import { SmtpEmailQueueSubscriberRabbitmq } from "./jobs/rabbitmq/smtp-email-subscriber.service"; -import { TestQueuePublisher } from "./jobs/rabbitmq/test-queue-publisher.service"; -import { TestQueueSubscriber } from "./jobs/rabbitmq/test-queue-subscriber.service"; -import { ChatterQueuePublisherRabbitmq } from "./jobs/rabbitmq/chatter-queue-publisher.service"; -import { ChatterQueueSubscriberRabbitmq } from "./jobs/rabbitmq/chatter-queue-subscriber.service"; -import { ChatterQueuePublisherDatabase } from "./jobs/database/chatter-queue-publisher-database.service"; -import { ChatterQueueSubscriberDatabase } from "./jobs/database/chatter-queue-subscriber-database.service"; -import { ApiEmailQueuePublisherRedis } from "./jobs/redis/api-email-publisher-redis.service"; -import { ApiEmailQueueSubscriberRedis } from "./jobs/redis/api-email-subscriber-redis.service"; -import { ChatterQueuePublisherRedis } from "./jobs/redis/chatter-queue-publisher-redis.service"; -import { ChatterQueueSubscriberRedis } from "./jobs/redis/chatter-queue-subscriber-redis.service"; -import { ComputedFieldEvaluationPublisherRedis } from "./jobs/redis/computed-field-evaluation-publisher-redis.service"; -import { ComputedFieldEvaluationSubscriberRedis } from "./jobs/redis/computed-field-evaluation-subscriber-redis.service"; -import { GenerateCodePublisherRedis } from "./jobs/redis/generate-code-publisher-redis.service"; -import { GenerateCodeSubscriberRedis } from "./jobs/redis/generate-code-subscriber-redis.service"; -import { Msg91OTPQueuePublisherRedis } from "./jobs/redis/msg91-otp-publisher-redis.service"; -import { Msg91OTPQueueSubscriberRedis } from "./jobs/redis/msg91-otp-subscriber-redis.service"; -import { Msg91SmsQueuePublisherRedis } from "./jobs/redis/msg91-sms-publisher-redis.service"; -import { Msg91SmsQueueSubscriberRedis } from "./jobs/redis/msg91-sms-subscriber-redis.service"; -import { Msg91WhatsappQueuePublisherRedis } from "./jobs/redis/msg91-whatsapp-publisher-redis.service"; -import { Msg91WhatsappQueueSubscriberRedis } from "./jobs/redis/msg91-whatsapp-subscriber-redis.service"; -import { SmtpEmailQueuePublisherRedis } from "./jobs/redis/smtp-email-publisher-redis.service"; -import { SmtpEmailQueueSubscriberRedis } from "./jobs/redis/smtp-email-subscriber-redis.service"; -import { Three60WhatsappQueuePublisherRedis } from "./jobs/redis/three60-whatsapp-publisher-redis.service"; -import { Three60WhatsappQueueSubscriberRedis } from "./jobs/redis/three60-whatsapp-subscriber-redis.service"; -import { TriggerMcpClientPublisherRedis } from "./jobs/redis/trigger-mcp-client-publisher-redis.service"; -import { TriggerMcpClientSubscriberRedis } from "./jobs/redis/trigger-mcp-client-subscriber-redis.service"; -import { TwilioSmsQueuePublisherRedis } from "./jobs/redis/twilio-sms-publisher-redis.service"; -import { TwilioSmsQueueSubscriberRedis } from "./jobs/redis/twilio-sms-subscriber-redis.service"; -import { UserRegistrationListener } from "./listeners/user-registration.listener"; -import { GoogleOauthStrategy } from "./passport-strategies/google-oauth.strategy"; -import { ApiKeyService } from "./services/api-key.service"; -import { AuthenticationService } from "./services/authentication.service"; -import { BcryptService } from "./services/bcrypt.service"; -import { UuidExternalIdEntityComputedFieldProvider } from "./services/computed-fields/entity/uuid-externalid-entity-computed-field-provider.service"; -import { UuidExternalIdComputedFieldProvider } from "./services/computed-fields/uuid-external-id-computed-field-provider.service"; -import { EmailTemplateService } from "./services/email-template.service"; +import { HttpModule } from '@nestjs/axios'; +import { JwtModule } from '@nestjs/jwt'; +import { SeedCommand } from './commands/seed.command'; +import { TestDataCommand } from './commands/test-data.command'; +import { TestRunCommand } from './commands/run-tests.command'; +import { TestCommand } from './commands/test.command'; +import { AuthenticationController } from './controllers/authentication.controller'; +import { EmailTemplateController } from './controllers/email-template.controller'; +import { GoogleAuthenticationController } from './controllers/google-authentication.controller'; +import { MenuItemMetadataController } from './controllers/menu-item-metadata.controller'; +import { MqMessageQueueController } from './controllers/mq-message-queue.controller'; +import { MqMessageController } from './controllers/mq-message.controller'; +import { OTPAuthenticationController } from './controllers/otp-authentication.controller'; +import { ServiceController } from './controllers/service.controller'; +import { SmsTemplateController } from './controllers/sms-template.controller'; +import { TestQueueController } from './controllers/test-queue.controller'; +import { EmailAttachment } from './entities/email-attachment.entity'; +import { EmailTemplate } from './entities/email-template.entity'; +import { MenuItemMetadata } from './entities/menu-item-metadata.entity'; +import { MqMessageQueue } from './entities/mq-message-queue.entity'; +import { MqMessage } from './entities/mq-message.entity'; +import { SmsTemplate } from './entities/sms-template.entity'; +import { AccessTokenGuard } from './guards/access-token.guard'; +import { ApiKeyGuard } from './guards/api-key.guard'; +import { AuthenticationGuard } from './guards/authentication.guard'; +import { PermissionsGuard } from './guards/permissions.guard'; +import { SolidRegistry } from './helpers/solid-registry'; +import { LoggingInterceptor } from './interceptors/logging.interceptor'; +import { ApiEmailQueuePublisher } from './jobs/rabbitmq/api-email-publisher.service'; +import { ApiEmailQueueSubscriber } from './jobs/rabbitmq/api-email-subscriber.service'; +import { TestQueuePublisherDatabase } from './jobs/database/test-queue-publisher-database.service'; +import { TestQueueSubscriberDatabase } from './jobs/database/test-queue-subscriber-database.service'; +import { TestQueuePublisherRedis } from './jobs/redis/test-queue-publisher-redis.service'; +import { TestQueueSubscriberRedis } from './jobs/redis/test-queue-subscriber-redis.service'; +import { Msg91WhatsappQueuePublisher } from './jobs/rabbitmq/msg91-whatsapp-publisher.service'; +import { Msg91WhatsappQueueSubscriber } from './jobs/rabbitmq/msg91-whatsapp-subscriber.service'; +import { Msg91OTPQueuePublisher } from './jobs/rabbitmq/msg91-otp-publisher.service'; +import { Msg91OTPQueueSubscriber } from './jobs/rabbitmq/msg91-otp-subscriber.service'; +import { Msg91SmsQueuePublisher } from './jobs/rabbitmq/msg91-sms-publisher.service'; +import { Msg91SmsQueueSubscriber } from './jobs/rabbitmq/msg91-sms-subscriber.service'; +import { SmtpEmailQueuePublisherRabbitmq } from './jobs/rabbitmq/smtp-email-publisher.service'; +import { SmtpEmailQueueSubscriberRabbitmq } from './jobs/rabbitmq/smtp-email-subscriber.service'; +import { TestQueuePublisher } from './jobs/rabbitmq/test-queue-publisher.service'; +import { TestQueueSubscriber } from './jobs/rabbitmq/test-queue-subscriber.service'; +import { ChatterQueuePublisherRabbitmq } from './jobs/rabbitmq/chatter-queue-publisher.service'; +import { ChatterQueueSubscriberRabbitmq } from './jobs/rabbitmq/chatter-queue-subscriber.service'; +import { ChatterQueuePublisherDatabase } from './jobs/database/chatter-queue-publisher-database.service'; +import { ChatterQueueSubscriberDatabase } from './jobs/database/chatter-queue-subscriber-database.service'; +import { ApiEmailQueuePublisherRedis } from './jobs/redis/api-email-publisher-redis.service'; +import { ApiEmailQueueSubscriberRedis } from './jobs/redis/api-email-subscriber-redis.service'; +import { ChatterQueuePublisherRedis } from './jobs/redis/chatter-queue-publisher-redis.service'; +import { ChatterQueueSubscriberRedis } from './jobs/redis/chatter-queue-subscriber-redis.service'; +import { ComputedFieldEvaluationPublisherRedis } from './jobs/redis/computed-field-evaluation-publisher-redis.service'; +import { ComputedFieldEvaluationSubscriberRedis } from './jobs/redis/computed-field-evaluation-subscriber-redis.service'; +import { GenerateCodePublisherRedis } from './jobs/redis/generate-code-publisher-redis.service'; +import { GenerateCodeSubscriberRedis } from './jobs/redis/generate-code-subscriber-redis.service'; +import { Msg91OTPQueuePublisherRedis } from './jobs/redis/msg91-otp-publisher-redis.service'; +import { Msg91OTPQueueSubscriberRedis } from './jobs/redis/msg91-otp-subscriber-redis.service'; +import { Msg91SmsQueuePublisherRedis } from './jobs/redis/msg91-sms-publisher-redis.service'; +import { Msg91SmsQueueSubscriberRedis } from './jobs/redis/msg91-sms-subscriber-redis.service'; +import { Msg91WhatsappQueuePublisherRedis } from './jobs/redis/msg91-whatsapp-publisher-redis.service'; +import { Msg91WhatsappQueueSubscriberRedis } from './jobs/redis/msg91-whatsapp-subscriber-redis.service'; +import { SmtpEmailQueuePublisherRedis } from './jobs/redis/smtp-email-publisher-redis.service'; +import { SmtpEmailQueueSubscriberRedis } from './jobs/redis/smtp-email-subscriber-redis.service'; +import { Three60WhatsappQueuePublisherRedis } from './jobs/redis/three60-whatsapp-publisher-redis.service'; +import { Three60WhatsappQueueSubscriberRedis } from './jobs/redis/three60-whatsapp-subscriber-redis.service'; +import { TriggerMcpClientPublisherRedis } from './jobs/redis/trigger-mcp-client-publisher-redis.service'; +import { TriggerMcpClientSubscriberRedis } from './jobs/redis/trigger-mcp-client-subscriber-redis.service'; +import { TwilioSmsQueuePublisherRedis } from './jobs/redis/twilio-sms-publisher-redis.service'; +import { TwilioSmsQueueSubscriberRedis } from './jobs/redis/twilio-sms-subscriber-redis.service'; +import { UserRegistrationListener } from './listeners/user-registration.listener'; +import { GoogleOauthStrategy } from './passport-strategies/google-oauth.strategy'; +import { ApiKeyService } from './services/api-key.service'; +import { AuthenticationService } from './services/authentication.service'; +import { BcryptService } from './services/bcrypt.service'; +import { UuidExternalIdEntityComputedFieldProvider } from './services/computed-fields/entity/uuid-externalid-entity-computed-field-provider.service'; +import { UuidExternalIdComputedFieldProvider } from './services/computed-fields/uuid-external-id-computed-field-provider.service'; +import { EmailTemplateService } from './services/email-template.service'; import { DiskFileService, S3FileService, @@ -151,38 +146,38 @@ import { DiskStoragePathBuilder, S3StoragePathBuilder, StoragePathBuilderFactory, -} from "./services/file"; -import { HashingService } from "./services/hashing.service"; -import { ElasticEmailService } from "./services/mail/elastic-email.service"; -import { SMTPEMailService } from "./services/mail/smtp-email.service"; -import { MenuItemMetadataService } from "./services/menu-item-metadata.service"; -import { MqMessageQueueService } from "./services/mq-message-queue.service"; -import { MqMessageService } from "./services/mq-message.service"; -import { PdfService } from "./services/pdf.service"; -import { RefreshTokenIdsStorageService } from "./services/refresh-token-ids-storage.service"; -import { SsoCodeStorageService } from "./services/sso-code-storage.service"; -import { ListOfModelsSelectionProvider } from "./services/selection-providers/list-of-models-selection-provider.service"; -import { TinyUrlService } from "./services/short-url/tiny-url.service"; -import { SmsTemplateService } from "./services/sms-template.service"; -import { Msg91OTPService } from "./services/sms/Msg91OTPService"; -import { Msg91SMSService } from "./services/sms/Msg91SMSService"; +} from './services/file'; +import { HashingService } from './services/hashing.service'; +import { ElasticEmailService } from './services/mail/elastic-email.service'; +import { SMTPEMailService } from './services/mail/smtp-email.service'; +import { MenuItemMetadataService } from './services/menu-item-metadata.service'; +import { MqMessageQueueService } from './services/mq-message-queue.service'; +import { MqMessageService } from './services/mq-message.service'; +import { PdfService } from './services/pdf.service'; +import { RefreshTokenIdsStorageService } from './services/refresh-token-ids-storage.service'; +import { SsoCodeStorageService } from './services/sso-code-storage.service'; +import { ListOfModelsSelectionProvider } from './services/selection-providers/list-of-models-selection-provider.service'; +import { TinyUrlService } from './services/short-url/tiny-url.service'; +import { SmsTemplateService } from './services/sms-template.service'; +import { Msg91OTPService } from './services/sms/Msg91OTPService'; +import { Msg91SMSService } from './services/sms/Msg91SMSService'; // import { UserService } from './services/user.service'; -import { Msg91WhatsappService } from "./services/whatsapp/Msg91WhatsappService"; -import { SoftDeleteAwareEventSubscriber } from "./subscribers/soft-delete-aware-event.subscriber"; +import { Msg91WhatsappService } from './services/whatsapp/Msg91WhatsappService'; +import { SoftDeleteAwareEventSubscriber } from './subscribers/soft-delete-aware-event.subscriber'; -import { PermissionMetadataController } from "./controllers/permission-metadata.controller"; -import { PermissionMetadata } from "./entities/permission-metadata.entity"; -import { PermissionMetadataService } from "./services/permission-metadata.service"; +import { PermissionMetadataController } from './controllers/permission-metadata.controller'; +import { PermissionMetadata } from './entities/permission-metadata.entity'; +import { PermissionMetadataService } from './services/permission-metadata.service'; -import { ScheduleModule } from "@nestjs/schedule"; -import { ClsModule } from "nestjs-cls"; -import { AiInteractionController } from "./controllers/ai-interaction.controller"; -import { ChatterMessageDetailsController } from "./controllers/chatter-message-details.controller"; -import { ChatterMessageController } from "./controllers/chatter-message.controller"; -import { DashboardQuestionSqlDatasetConfigController } from "./controllers/dashboard-question-sql-dataset-config.controller"; -import { DashboardQuestionController } from "./controllers/dashboard-question.controller"; -import { DashboardVariableController } from "./controllers/dashboard-variable.controller"; -import { DashboardLayoutController } from "./controllers/dashboard-layout.controller"; +import { ScheduleModule } from '@nestjs/schedule'; +import { ClsModule } from 'nestjs-cls'; +import { AiInteractionController } from './controllers/ai-interaction.controller'; +import { ChatterMessageDetailsController } from './controllers/chatter-message-details.controller'; +import { ChatterMessageController } from './controllers/chatter-message.controller'; +import { DashboardQuestionSqlDatasetConfigController } from './controllers/dashboard-question-sql-dataset-config.controller'; +import { DashboardQuestionController } from './controllers/dashboard-question.controller'; +import { DashboardVariableController } from './controllers/dashboard-variable.controller'; +import { DashboardLayoutController } from './controllers/dashboard-layout.controller'; import { DashboardController } from './controllers/dashboard.controller'; import { ExportTemplateController } from './controllers/export-template.controller'; @@ -246,41 +241,41 @@ import { Msg91SmsQueueSubscriberDatabase } from './jobs/database/msg91-sms-subsc import { SmtpEmailQueuePublisherDatabase } from './jobs/database/smtp-email-publisher-database.service'; import { SmtpEmailQueueSubscriberDatabase } from './jobs/database/smtp-email-subscriber-database.service'; -import { TwilioSmsQueuePublisherDatabase } from "./jobs/database/twilio-sms-publisher-database.service"; -import { TwilioSmsQueueSubscriberDatabase } from "./jobs/database/twilio-sms-subscriber-database.service"; +import { TwilioSmsQueuePublisherDatabase } from './jobs/database/twilio-sms-publisher-database.service'; +import { TwilioSmsQueueSubscriberDatabase } from './jobs/database/twilio-sms-subscriber-database.service'; // import { ThrottlerModule } from '@nestjs/throttler'; -import { IngestCommand } from "./commands/ingest.command"; -import { MailFactory } from "./factories/mail.factory"; -import { ErrorMapperService } from "./helpers/error-mapper.service"; -import { SolidCoreErrorCodesProvider } from "./helpers/solid-core-error-codes-provider.service"; -import { ComputedFieldEvaluationPublisherRabbitmq } from "./jobs/rabbitmq/computed-field-evaluation-publisher.service"; -import { ComputedFieldEvaluationSubscriberRabbitmq } from "./jobs/rabbitmq/computed-field-evaluation-subscriber.service"; -import { Msg91WhatsappQueuePublisherDatabase } from "./jobs/database/msg91-whatsapp-publisher-database.service"; -import { Msg91WhatsappQueueSubscriberDatabase } from "./jobs/database/msg91-whatsapp-subscriber-database.service"; -import { Three60WhatsappQueuePublisherDatabase } from "./jobs/database/three60-whatsapp-publisher-database.service"; -import { Three60WhatsappQueueSubscriberDatabase } from "./jobs/database/three60-whatsapp-subscriber-database.service"; -import { TriggerMcpClientPublisherDatabase } from "./jobs/database/trigger-mcp-client-publisher-database.service"; -import { TriggerMcpClientSubscriberDatabase } from "./jobs/database/trigger-mcp-client-subscriber-database.service"; -import { GenerateCodePublisherRabbitmq } from "./jobs/rabbitmq/generate-code-publisher.service"; -import { GenerateCodeSubscriberRabbitmq } from "./jobs/rabbitmq/generate-code-subscriber.service"; -import { Three60WhatsappQueuePublisher } from "./jobs/rabbitmq/three60-whatsapp-publisher.service"; -import { Three60WhatsappQueueSubscriber } from "./jobs/rabbitmq/three60-whatsapp-subscriber.service"; -import { TriggerMcpClientPublisherRabbitmq } from "./jobs/rabbitmq/trigger-mcp-client-publisher.service"; -import { TriggerMcpClientSubscriberRabbitmq } from "./jobs/rabbitmq/trigger-mcp-client-subscriber.service"; -import { TwilioSmsQueuePublisherRabbitmq } from "./jobs/rabbitmq/twilio-sms-publisher.service"; -import { TwilioSmsQueueSubscriberRabbitmq } from "./jobs/rabbitmq/twilio-sms-subscriber.service"; -import { DashboardMapper } from "./mappers/dashboard-mapper"; -import { ListOfValuesMapper } from "./mappers/list-of-values-mapper"; -import { ActionMetadataRepository } from "./repository/action-metadata.repository"; -import { AiInteractionRepository } from "./repository/ai-interaction.repository"; -import { ChatterMessageDetailsRepository } from "./repository/chatter-message-details.repository"; -import { ChatterMessageRepository } from "./repository/chatter-message.repository"; -import { DashboardQuestionSqlDatasetConfigRepository } from "./repository/dashboard-question-sql-dataset-config.repository"; -import { DashboardQuestionRepository } from "./repository/dashboard-question.repository"; -import { DashboardVariableRepository } from "./repository/dashboard-variable.repository"; -import { DashboardRepository } from "./repository/dashboard.repository"; -import { DashboardLayoutRepository } from "./repository/dashboard-layout.repository"; +import { IngestCommand } from './commands/ingest.command'; +import { MailFactory } from './factories/mail.factory'; +import { ErrorMapperService } from './helpers/error-mapper.service'; +import { SolidCoreErrorCodesProvider } from './helpers/solid-core-error-codes-provider.service'; +import { ComputedFieldEvaluationPublisherRabbitmq } from './jobs/rabbitmq/computed-field-evaluation-publisher.service'; +import { ComputedFieldEvaluationSubscriberRabbitmq } from './jobs/rabbitmq/computed-field-evaluation-subscriber.service'; +import { Msg91WhatsappQueuePublisherDatabase } from './jobs/database/msg91-whatsapp-publisher-database.service'; +import { Msg91WhatsappQueueSubscriberDatabase } from './jobs/database/msg91-whatsapp-subscriber-database.service'; +import { Three60WhatsappQueuePublisherDatabase } from './jobs/database/three60-whatsapp-publisher-database.service'; +import { Three60WhatsappQueueSubscriberDatabase } from './jobs/database/three60-whatsapp-subscriber-database.service'; +import { TriggerMcpClientPublisherDatabase } from './jobs/database/trigger-mcp-client-publisher-database.service'; +import { TriggerMcpClientSubscriberDatabase } from './jobs/database/trigger-mcp-client-subscriber-database.service'; +import { GenerateCodePublisherRabbitmq } from './jobs/rabbitmq/generate-code-publisher.service'; +import { GenerateCodeSubscriberRabbitmq } from './jobs/rabbitmq/generate-code-subscriber.service'; +import { Three60WhatsappQueuePublisher } from './jobs/rabbitmq/three60-whatsapp-publisher.service'; +import { Three60WhatsappQueueSubscriber } from './jobs/rabbitmq/three60-whatsapp-subscriber.service'; +import { TriggerMcpClientPublisherRabbitmq } from './jobs/rabbitmq/trigger-mcp-client-publisher.service'; +import { TriggerMcpClientSubscriberRabbitmq } from './jobs/rabbitmq/trigger-mcp-client-subscriber.service'; +import { TwilioSmsQueuePublisherRabbitmq } from './jobs/rabbitmq/twilio-sms-publisher.service'; +import { TwilioSmsQueueSubscriberRabbitmq } from './jobs/rabbitmq/twilio-sms-subscriber.service'; +import { DashboardMapper } from './mappers/dashboard-mapper'; +import { ListOfValuesMapper } from './mappers/list-of-values-mapper'; +import { ActionMetadataRepository } from './repository/action-metadata.repository'; +import { AiInteractionRepository } from './repository/ai-interaction.repository'; +import { ChatterMessageDetailsRepository } from './repository/chatter-message-details.repository'; +import { ChatterMessageRepository } from './repository/chatter-message.repository'; +import { DashboardQuestionSqlDatasetConfigRepository } from './repository/dashboard-question-sql-dataset-config.repository'; +import { DashboardQuestionRepository } from './repository/dashboard-question.repository'; +import { DashboardVariableRepository } from './repository/dashboard-variable.repository'; +import { DashboardRepository } from './repository/dashboard.repository'; +import { DashboardLayoutRepository } from './repository/dashboard-layout.repository'; import { EmailTemplateRepository } from './repository/email-template.repository'; import { ExportTemplateRepository } from './repository/export-template.repository'; @@ -451,13 +446,13 @@ import { Entity } from 'typeorm'; CacheModule.registerAsync(CacheManagerOptions), ScheduleModule.forRoot(), ServeStaticModule.forRoot({ - rootPath: join(process.cwd(), "media-files-storage"), - serveRoot: "/media-files-storage", + rootPath: join(process.cwd(), 'media-files-storage'), + serveRoot: '/media-files-storage', serveStaticOptions: { setHeaders: (res /*, path, stat*/) => { // Allow use of these files from a different origin (e.g., :3000 UI) // Use 'same-site' if both origins are on the same site (localhost:* counts as same-site) - res.setHeader("Cross-Origin-Resource-Policy", "cross-origin"); // or 'same-site' + res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin'); // or 'same-site' // If you need to load into without tainting or fetch images via XHR, // you can also expose CORS here (not needed for simple ): @@ -468,7 +463,7 @@ import { Entity } from 'typeorm'; MulterModule.registerAsync({ imports: [ConfigModule], useFactory: async (configService: ConfigService) => ({ - dest: process.env.AB_MEDIA_UPLOAD_DIR ?? "media-uploads", + dest: process.env.AB_MEDIA_UPLOAD_DIR ?? 'media-uploads', }), inject: [ConfigService], }), @@ -508,8 +503,6 @@ import { Entity } from 'typeorm'; ModuleMetadataController, MqMessageController, MqMessageQueueController, - GupshupWebhookController, - MetaCloudWhatsappWebhookController, OTPAuthenticationController, PermissionMetadataController, RoleMetadataController, @@ -606,8 +599,6 @@ import { Entity } from 'typeorm'; Msg91SMSService, Msg91OTPService, Msg91WhatsappService, - MetaCloudWhatsappService, - GupshupOtpWhatsappService, TwilioSMSService, SmsTemplateService, EmailTemplateService, @@ -906,9 +897,9 @@ export class SolidCoreModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply( - express.json({ limit: "10mb" }), - express.urlencoded({ limit: "10mb", extended: true }), + express.json({ limit: '10mb' }), + express.urlencoded({ limit: '10mb', extended: true }), ) - .forRoutes("*"); + .forRoutes('*'); } }