diff --git a/.env.sample b/.env.sample index c262650..9815d27 100644 --- a/.env.sample +++ b/.env.sample @@ -13,10 +13,15 @@ CDAC_OTP_TEMPLATE_ID="123456" CDAC_OTP_TEMPLATE="Respected User, The OTP to reset password for %phone% is %code%." # SMS Adapter -SMS_ADAPTER_TYPE= # CDAC or GUPSHUP +SMS_ADAPTER_TYPE= # CDAC or GUPSHUP or RAJAI SMS_TOTP_SECRET= # any random string, needed for CDAC SMS_TOTP_EXPIRY=600 # in seconds, needed for CDAC +#RAJAI OTP Service +RAJAI_USERNAME= +RAJAI_PASSWORD= +RAJAI_BASEURL= + # Fusionauth FUSIONAUTH_APPLICATION_ID="f0ddb3f6-091b-45e4-8c0f-889f89d4f5da" FUSIONAUTH_SAMARTH_HP_APPLICATION_ID=f18c3f6f-45b8-4928-b978-a9906fd03f22 diff --git a/src/api/api.module.ts b/src/api/api.module.ts index a5e586c..445cb51 100644 --- a/src/api/api.module.ts +++ b/src/api/api.module.ts @@ -11,6 +11,7 @@ import { GupshupService } from './sms/gupshup/gupshup.service'; import { SmsService } from './sms/sms.service'; import got from 'got/dist/source'; import { CdacService } from './sms/cdac/cdac.service'; +import { RajaiOtpService } from '../user/sms/rajaiOtpService/rajaiOtpService.service'; const otpServiceFactory = { provide: OtpService, @@ -24,7 +25,21 @@ const otpServiceFactory = { }, inject: [], }.useFactory(); - } else { + } else if(config.get('SMS_ADAPTER_TYPE') == 'RAJAI'){ + factory = { + provide: 'OtpService', + useFactory: (username, password, baseUrl)=>{ + return new RajaiOtpService( + username, + password, + baseUrl, + got + ); + }, + inject: [], + }.useFactory(config.get('RAJAI_USERNAME'), config.get('RAJAI_PASSWORD'), config.get('RAJAI_BASEURL')); + } + else { factory = { provide: 'OtpService', useFactory: (username, password, baseUrl) => { diff --git a/src/user/sms/rajaiOtpService/rajaiOtpService.service.ts b/src/user/sms/rajaiOtpService/rajaiOtpService.service.ts new file mode 100644 index 0000000..a1d16de --- /dev/null +++ b/src/user/sms/rajaiOtpService/rajaiOtpService.service.ts @@ -0,0 +1,207 @@ +import { + OTPResponse, + SMS, + SMSData, + SMSError, + SMSProvider, + SMSResponse, + SMSResponseStatus, + SMSType, + TrackResponse, + } from '../sms.interface'; + + import { Injectable } from '@nestjs/common'; + import { SmsService } from '../sms.service'; + import { Got } from 'got/dist/source'; +import { json } from 'stream/consumers'; + + @Injectable() + export class RajaiOtpService extends SmsService implements SMS { + + otpApiConstants: any = { + srvnm: "ChatbotAPIs", + srvmethodnm: "" + }; + + auth: any = { + usrnm: '', + psw: '', + }; + + httpClient: Got; + + baseURL: string; + path = ''; + data: SMSData; + + constructor(username: string, password: string, baseURL: string, got: Got) { + super(); + this.auth.usrnm = username; + this.auth.psw = password; + this.baseURL = baseURL; + this.httpClient = got; + } + + send(data: SMSData): Promise { + if (!data) { + throw new Error('Data cannot be null'); + } + this.data = data; + if (this.data.type === SMSType.otp) return this.doOTPRequest(data); + else return this.doRequest(); + } + + doRequest(): Promise { + throw new Error('Method not implemented.'); + } + + track(data: SMSData): Promise { + if (!data) { + throw new Error('Data cannot be null'); + } + this.data = data; + if (this.data.type === SMSType.otp) return this.verifyOTP(data); + else return this.doRequest(); + } + + private doOTPRequest(data: SMSData): Promise { + this.otpApiConstants.srvmethodnm = 'ChatBotGenerateOtpMobile' + const body: any = { + obj: { + ...this.otpApiConstants, + ...this.auth, + mobileNo: data.phone, + } + } + const options = { + headers: { + 'Content-Type': 'application/json' + }, + json: body + }; + console.log(options) + const url = this.baseURL + '' + this.path; + console.log(url) + const status: OTPResponse = {} as OTPResponse; + status.provider = SMSProvider.rajai; + status.phone = data.phone; + + return this.httpClient + .post(url,options) + .then((response): OTPResponse => { + status.networkResponseCode = 200; + const r = this.parseResponse(response.body); + console.log("otp response", r); + status.messageID = r.messageID; + status.error = r.error; + status.providerResponseCode = r.providerResponseCode; + status.providerSuccessResponse = r.providerSuccessResponse; + status.status = r.status; + return status; + }) + .catch((e: Error): OTPResponse => { + console.log("otp response error", e); + const error: SMSError = { + errorText: `Uncaught Exception :: ${e.message}`, + errorCode: 'CUSTOM ERROR', + }; + status.networkResponseCode = 200; + status.messageID = null; + status.error = error; + status.providerResponseCode = null; + status.providerSuccessResponse = null; + status.status = SMSResponseStatus.failure; + return status; + }); + } + + verifyOTP(data: SMSData): Promise { + this.otpApiConstants.srvmethodnm = 'ChatBotVerifyOtpMobile' + console.log({ data }); + const body: any = { + obj: { + ...this.otpApiConstants, + ...this.auth, + mobileNo: data.phone, + otp: data.params.otp + } + } + const options = { + headers: { + 'Content-Type': 'application/json' + }, + json: body + }; + const url = this.baseURL + '' + this.path; + const status: TrackResponse = {} as TrackResponse; + status.provider = SMSProvider.rajai; + status.phone = data.phone; + + return this.httpClient + .post(url, options) + .then((response): OTPResponse => { + console.log(response.body); + status.networkResponseCode = 200; + const r = this.parseResponse(response.body); + status.messageID = r.messageID; + status.error = r.error; + status.providerResponseCode = r.providerResponseCode; + status.providerSuccessResponse = r.providerSuccessResponse; + status.status = r.status; + return status; + }) + .catch((e: Error): OTPResponse => { + const error: SMSError = { + errorText: `Uncaught Exception :: ${e.message}`, + errorCode: 'CUSTOM ERROR', + }; + status.networkResponseCode = 200; + status.messageID = null; + status.error = error; + status.providerResponseCode = null; + status.providerSuccessResponse = null; + status.status = SMSResponseStatus.failure; + return status; + }); + } + + parseResponse(response: string): any{ + try { + const responseData = JSON.parse(response); + if (responseData[0]["status"] === '0' || responseData[0]["message"] === 'OTP Verify Successfully' ) { + return { + providerResponseCode: null, + status: SMSResponseStatus.success, + messageID: responseData[0]["data"], + error: null, + providerSuccessResponse: responseData[0]["message"], + }; + } else { + const error: SMSError = { + errorText: responseData[0]["message"], + errorCode: responseData[0]["status"], + }; + return { + providerResponseCode: responseData[0]["message"], + status: SMSResponseStatus.failure, + messageID: null, + error, + providerSuccessResponse: null, + }; + } + } catch (e) { + const error: SMSError = { + errorText: `Gupshup response could not be parsed :: ${e.message}; Provider Response - ${response}`, + errorCode: 'CUSTOM ERROR', + }; + return { + providerResponseCode: null, + status: SMSResponseStatus.failure, + messageID: null, + error, + providerSuccessResponse: null, + }; + } + } + } + \ No newline at end of file diff --git a/src/user/sms/sms.interface.ts b/src/user/sms/sms.interface.ts index 4cd25f4..b2f8532 100644 --- a/src/user/sms/sms.interface.ts +++ b/src/user/sms/sms.interface.ts @@ -18,6 +18,7 @@ export enum SMSResponseStatus { export enum SMSProvider { gupshup = 'Gupshup', cdac = 'CDAC', + rajai = 'Rajai' } export type SMSError = {