const utils = require("@strapi/utils"); const _ = require("lodash"); const { sanitize } = utils; const { ApplicationError, ValidationError } = utils.errors; const { validateRegisterBody, } = require("@strapi/plugin-users-permissions/server/controllers/validation/auth"); const { getService } = require("@strapi/plugin-users-permissions/server/utils"); const sanitizeUser = (user, ctx) => { const { auth } = ctx.state; const userSchema = strapi.getModel("plugin::users-permissions.user"); return sanitize.contentAPI.output(user, userSchema, { auth }); }; const userPermissionExtension = (plugin) => { /** Example of overriding and adding a new endpoint, check the section where we have registered this as a route below. */ plugin.controllers.user.updateMe = (ctx) => { ctx.params.id = ctx.state.user.id; return plugin.controllers.user.update(ctx); }; plugin.controllers.user.startEndUserOtpLogin = async (ctx) => { const { emailAddress, mobileNumber } = ctx.request.body; if (!emailAddress || !mobileNumber) { throw new ValidationError( "Please specify both the email address & mobile numbers." ); } const pluginStore = await strapi.store({ type: "plugin", name: "users-permissions", }); const emailSettings = await pluginStore.get({ key: "email" }); // Find the channel partner first. // const endUser = await strapi.query("api::end-user.end-user").findOne({ // populate: ["user"], // where: { // $and: [ // { publishedAt: { $notNull: true } }, // { mobileNo: mobileNumber }, // ], // }, // }); const endUser = await strapi.query("api::end-user.end-user").findOne({ populate: ["user"], where: { $and: [{ publishedAt: { $notNull: true } }, { mobileNo: mobileNumber }], }, }); if (!endUser) { throw new ValidationError( "No end user registered with specified email address, mobile number combination." ); } // Find the linked user next. const user = await strapi .query("plugin::users-permissions.user") .findOne({ where: { id: endUser.user.id } }); if (!user || user.blocked) { throw new ValidationError("Unable to resolve user linked to end user."); } const resetPasswordSettings = _.get( emailSettings, "reset_password.options", {} ); const oneTimePassword = Math.floor(100000 + Math.random() * 900000); const emailToSend = { to: user.email, from: `contact@hiranandani.net`, oneTimePassword: oneTimePassword, replyTo: resetPasswordSettings.response_email, subject: `Your one time password is: ${oneTimePassword}`, text: `Hello ${endUser.fullName}, Your one time password to login to your partner portal is ${oneTimePassword}`, html: `<p>Dear ${endUser.fullName}, Your OTP for Hiranandani Exclusive website login is <strong>${oneTimePassword}</strong> . Valid for 10 minutes. Please do not share this OTP. Regards, Hiranandani Team.`, }; const finalData = { emailToSend: emailToSend, mobileNo: mobileNumber, fullName: endUser.fullName, }; // NOTE: Update the user before sending the email so an Admin can generate the link if the email fails // const headers = { "Content-Type": "application/json" }; // const otpDetails = { // api_key: process.env.SPERTO_API_KEY, // from_name: "Hiranandani", // from_mail: emailToSend.from, // to: emailToSend.to, // subject: emailToSend.subject, // body: emailToSend.html, // }; // await strapi.plugin("email").service("email").send(emailToSend); // await axios.get( // `http://vas.themultimedia.in/domestic/sendsms/bulksms.php?username=OSAPI&password=os123456&type=TEXT&sender=HROTPs&entityId=1101407690000029629&templateId=1507166789848358346&mobile=${mobileNumber}&message=Dear%20${endUser.fullName}%0AYour%20OTP%20for%20Hiranandani%20Exclusive%20website%20login%20is%20${oneTimePassword}%0AValid%20for%2010%20minute%20Please%20do%20not%20share%20this%20OTP.%0ARegards%2C%0AHiranandani%20Team.` // ); try { // const spertoResponse = await axios.post( // "https://net4hgc.sperto.co.in/_api/api_auth_send_mail.php", // otpDetails, // { headers: headers } // ); const spretoOTP = await strapi .service("api::end-user.end-user") .sendOTPToSpreto(finalData); // console.log("spretoOTP", spretoOTP); // EMAIL RESPONSE ctx.request.body.httpRequestEmailHeaders = JSON.stringify( spretoOTP.spertoEmailResponse.headers ); ctx.request.body.httpRequestEmailMethod = spretoOTP.spertoEmailResponse.config.method; ctx.request.body.httpRequestEmailUrl = spretoOTP.spertoEmailResponse.config.url; ctx.request.body.httpsRequestEmailBody = spretoOTP.spertoEmailResponse.config.data; ctx.request.body.httpResposneEmailBody = JSON.stringify( spretoOTP.spertoEmailResponse.data ); // SMS RESPONSE ctx.request.body.httpSMSRequestHeaders = JSON.stringify( spretoOTP.spertoSMSResponse.headers ); ctx.request.body.httpSMSRequestMethod = spretoOTP.spertoSMSResponse.config.method; ctx.request.body.httpSMSRequestUrl = spretoOTP.spertoSMSResponse.config.url; // ctx.request.body.httpsSMSRequestBody = spretoOTP.spertoSMSResponse.config.data; ctx.request.body.httpSMSResposneBody = JSON.stringify( spretoOTP.spertoSMSResponse.data ); ctx.request.body.thirdPartyApiError = false; // console.log("spretoOTP", spretoOTP); // return spretoOTP; } catch (error) { // Email errors ctx.request.body.httpRequestEmailHeaders = JSON.stringify( error.config.headers ); ctx.request.body.httpRequestEmailMethod = error.config.method; ctx.request.body.httpRequestEmailUrl = error.config.url; ctx.request.body.httpsRequestEmailBody = error.config.data; ctx.request.body.httpResposneEmailBody = JSON.stringify(error.message); // SMS headers ctx.request.body.httpSMSRequestHeaders = JSON.stringify( error.config.headers ); ctx.request.body.httpSMSRequestMethod = error.config.method; ctx.request.body.httpSMSRequestUrl = error.config.url; // ctx.request.body.httpsSMSRequestBody = error.config.data; ctx.request.body.httpSMSResposneBody = JSON.stringify(error.message); ctx.request.body.thirdPartyApiError = true; } const updateUser = await getService("user").edit(user.id, { oneTimePassword: `${oneTimePassword}`, }); await strapi.entityService.update("api::end-user.end-user", endUser.id, { data: { httpRequestIsVerifiedHeaders: ctx.request.body.httpRequestIsVerifiedHeaders, httpsRequestIsVerifiedBody: ctx.request.body.httpsRequestIsVerifiedBody, httpRequestIsVerifiedUrl: ctx.request.body.httpRequestIsVerifiedUrl, httpRequestIsVerifiedMethod: ctx.request.body.httpRequestIsVerifiedMethod, httpResposneIsVerifiedBody: ctx.request.body.httpResposneIsVerifiedBody, httpRequestIsVerifiedHeaders: ctx.request.body.httpRequestIsVerifiedHeaders, // httpsRequestIsVerifiedBody: ctx.request.body.httpsRequestIsVerifiedBody, httpSMSRequestUrl: ctx.request.body.httpSMSRequestUrl, httpSMSRequestMethod: ctx.request.body.httpSMSRequestMethod, httpSMSResposneBody: ctx.request.body.httpSMSResposneBody, httpSMSRequestHeaders: ctx.request.body.httpSMSRequestHeaders, }, }); ctx.send({ ok: true, message: "otp sent" }); // const updateUser = await getService("user").edit(user.id, { // oneTimePassword: `${oneTimePassword}`, // }); // Send an email to the user. // await getService("user").sendOTPOnEmail(emailToSend); // TODO: Send SMS. }; plugin.controllers.user.finishEndUserOtpLogin = async (ctx) => { const { oneTimePassword, emailAddress, mobileNumber } = ctx.request.body; console.log("ctx.request.body", ctx.request.body); if (!oneTimePassword || !mobileNumber || !emailAddress) { throw new ValidationError( "Please specify the oneTimePassword, email address and mobile numbers." ); } // Find the channel partner first. const endUser = await strapi.query("api::end-user.end-user").findOne({ populate: ["user"], where: { $and: [ { publishedAt: { $notNull: true } }, // { user: { email: emailAddress } }, { mobileNo: mobileNumber }, ], }, }); if (!endUser) { throw new ValidationError( "No end user registered with specified email address, mobile number combination." ); } // Find the linked user next. const user = await strapi.query("plugin::users-permissions.user").findOne({ where: { $and: [{ id: endUser.user.id }, { oneTimePassword: oneTimePassword }], }, }); if (!user || user.blocked) { throw new ValidationError("Code provided is not valid."); } await getService("user").edit(user.id, { oneTimePassword: null, password: oneTimePassword, }); ctx.send({ ok: true, message: "otp updated" }); }; plugin.controllers.user.startChannelPartnerOtpLogin = async (ctx) => { const { mahareraNumber, mobileNumber } = ctx.request.body; if (!mahareraNumber) { throw new ValidationError("Please specify the maharera number."); } // const pluginStore = await strapi.store({ // type: "plugin", // name: "users-permissions", // }); // const emailSettings = await pluginStore.get({ key: "email" }); // // Find the channel partner first. // const channelPartner = await strapi // .query("api::channel-partner.channel-partner") // .findOne({ // populate: ["user"], // where: { // reraNumber: mahareraNumber, // }, // }); // if (!channelPartner) { // throw new ValidationError( // "No channel partner registered with specified maharera number." // ); // } // // // Find the linked user next. // const user = await strapi // .query("plugin::users-permissions.user") // .findOne({ where: { id: channelPartner.user.id } }); // if (!user || user.blocked) { // throw new ValidationError( // "Unable to resolve user linked to channel partner." // ); // } // const resetPasswordSettings = _.get( // emailSettings, // "reset_password.options", // {} // ); let oneTimePassword; let responseBody; try { // console.log("entered catch",ctx.request.body); const spertoCPOtpData = await strapi .service("api::channel-partner.channel-partner") .getCPDataFromSperto(ctx.request.body); responseBody = spertoCPOtpData; // console.log("spertoCPOtpData >>>>>", spertoCPOtpData); ctx.request.body.httpThirdPartyOTPApiRequestHeaders = JSON.stringify( spertoCPOtpData.headers ); ctx.request.body.token = spertoCPOtpData.data.token; ctx.request.body.httpThirdPartyOTPApiRequestMethod = spertoCPOtpData.config.method; ctx.request.body.httpThirdPartyOTPApiRequestUrl = spertoCPOtpData.config.url; ctx.request.body.httpsThirdPartyOTPApiRequestBody = spertoCPOtpData.config.data; ctx.request.body.httpThirdPartyOTPApiResposneBody = JSON.stringify( spertoCPOtpData.data ); ctx.request.body.httpThirdPartyOTPApiError = false; // console.log(">>>>>",ctx.request.body.httpThirdPartyOTPApiError); oneTimePassword = spertoCPOtpData.data.otp; } catch (error) { ctx.request.body.data.httpThirdPartyOTPApiRequestHeaders = JSON.stringify( error.config.headers ); ctx.request.body.httpThirdPartyOTPApiRequestMethod = error.config.method; ctx.request.body.httpThirdPartyOTPApiRequestUrl = error.config.url; ctx.request.body.httpsThirdPartyOTPApiRequestBody = error.config.data; ctx.request.body.httpThirdPartyOTPApiResposneBody = JSON.stringify( error.message ); ctx.request.body.httpThirdPartyOTPApiError = true; } const emailToSend = { oneTimePassword: oneTimePassword, // to: user.email, from: `contact@hiranandani.net`, // replyTo: resetPasswordSettings.response_email, subject: `Your one time password is: ${oneTimePassword}`, // text: `Hello ${channelPartner.contactPersonName}, Your one time password to login to your partner portal is ${oneTimePassword}`, // html: `<p>Hello ${channelPartner.contactPersonName}, <br></br>Your one time password to login to your partner portal is ${oneTimePassword}</p><br /> Best Regards, <br /> Team Hiranandani.`, }; const finalData = { emailToSend: emailToSend, mobileNo: mobileNumber, fullName: '', }; try { // const spertoResponse = await axios.post( // "https://net4hgc.sperto.co.in/_api/api_auth_send_mail.php", // otpDetails, // { headers: headers } // ); const spretoOTP = await strapi .service("api::end-user.end-user") .sendOTPToSpreto(finalData); // console.log("spretoOTP", spretoOTP); // EMAIL RESPONSE ctx.request.body.httpEmailRequestHeaders = JSON.stringify( spretoOTP.spertoEmailResponse.headers ); ctx.request.body.httpEmailRequestMethod = spretoOTP.spertoEmailResponse.config.method; ctx.request.body.httpEmailRequestUrl = spretoOTP.spertoEmailResponse.config.url; ctx.request.body.httpsEmailRequestBody = spretoOTP.spertoEmailResponse.config.data; ctx.request.body.httpEmailResposneBody = JSON.stringify( spretoOTP.spertoEmailResponse.data ); // SMS RESPONSE ctx.request.body.httpSMSRequestHeaders = JSON.stringify( spretoOTP.spertoSMSResponse.headers ); ctx.request.body.httpSMSRequestMethod = spretoOTP.spertoSMSResponse.config.method; ctx.request.body.httpSMSRequestUrl = spretoOTP.spertoSMSResponse.config.url; // ctx.request.body.httpsSMSRequestBody = spretoOTP.spertoSMSResponse.config.data; ctx.request.body.httpSMSResposneBody = JSON.stringify( spretoOTP.spertoSMSResponse.data ); ctx.request.body.thirdPartyApiError = false; // console.log("spretoOTP", spretoOTP); // return spretoOTP; } catch (error) { // Email errors ctx.request.body.httpEmailRequestHeaders = JSON.stringify( error.config.headers ); ctx.request.body.httpEmailRequestMethod = error.config.method; ctx.request.body.httpEmailRequestUrl = error.config.url; ctx.request.body.httpsEmailRequestBody = error.config.data; ctx.request.body.httpEmailResposneBody = JSON.stringify(error.message); // SMS headers ctx.request.body.httpSMSRequestHeaders = JSON.stringify( error.config.headers ); ctx.request.body.httpSMSRequestMethod = error.config.method; ctx.request.body.httpSMSRequestUrl = error.config.url; // ctx.request.body.httpsSMSRequestBody = error.config.data; ctx.request.body.httpSMSResposneBody = JSON.stringify(error.message); ctx.request.body.thirdPartyApiError = true; } // NOTE: Update the user before sending the email so an Admin can generate the link if the email fails // await getService("user").edit(user.id, { // oneTimePassword: `${oneTimePassword}`, // }); // await strapi.entityService.update( // "api::channel-partner.channel-partner", // channelPartner.id, // { // data: { // // httpRequestIsVerifiedHeaders: // // ctx.request.body.httpRequestIsVerifiedHeaders, // // httpsRequestIsVerifiedBody: ctx.request.body.httpsRequestIsVerifiedBody, // // httpRequestIsVerifiedUrl: ctx.request.body.httpRequestIsVerifiedUrl, // // httpRequestIsVerifiedMethod: // // ctx.request.body.httpRequestIsVerifiedMethod, // // httpResposneIsVerifiedBody: ctx.request.body.httpResposneIsVerifiedBody, // // httpRequestIsVerifiedHeaders: // // ctx.request.body.httpRequestIsVerifiedHeaders, // // httpsRequestIsVerifiedBody: ctx.request.body.httpsRequestIsVerifiedBody, // httpSMSRequestUrl: ctx.request.body.httpSMSRequestUrl, // httpSMSRequestMethod: ctx.request.body.httpSMSRequestMethod, // httpSMSResposneBody: ctx.request.body.httpSMSResposneBody, // httpSMSRequestHeaders: ctx.request.body.httpSMSRequestHeaders, // httpsEmailRequestBody: ctx.request.body.httpsEmailRequestBody, // httpEmailRequestUrl: ctx.request.body.httpEmailRequestUrl, // httpEmailRequestMethod: ctx.request.body.httpEmailRequestMethod, // httpEmailResposneBody: ctx.request.body.httpEmailResposneBody, // httpEmailRequestHeaders: ctx.request.body.httpEmailRequestHeaders, // httpThirdPartyOTPApiRequestHeaders: // ctx.request.body.httpThirdPartyOTPApiRequestHeaders, // token: ctx.request.body.token, // httpThirdPartyOTPApiRequestMethod: // ctx.request.body.httpThirdPartyOTPApiRequestMethod, // httpThirdPartyOTPApiRequestUrl: // ctx.request.body.httpThirdPartyOTPApiRequestUrl, // httpsThirdPartyOTPApiRequestBody: // ctx.request.body.httpsThirdPartyOTPApiRequestBody, // httpThirdPartyOTPApiResposneBody: // ctx.request.body.httpThirdPartyOTPApiResposneBody, // }, // } // ); // Send an email to the user. // await strapi.plugin("email").service("email").send(emailToSend); // TODO: Send SMS. console.log("responseBody", responseBody); ctx.send({ data: responseBody.data }); }; plugin.controllers.user.finishChannelPartnerOtpLogin = async (ctx) => { const { oneTimePassword, mahareraNumber, mobileNumber } = ctx.request.body; if (!oneTimePassword || !mahareraNumber) { throw new ValidationError( "Please specify the oneTimePassword, maharera number and mobile numbers." ); } console.log("{ oneTimePassword, mahareraNumber, mobileNumber }", { oneTimePassword, mahareraNumber, }); // Find the channel partner first. const channelPartner = await strapi .query("api::channel-partner.channel-partner") .findOne({ populate: ["user"], where: { $and: [ { publishedAt: { $notNull: true } }, { reraNumber: mahareraNumber }, ], }, }); if (!channelPartner) { throw new ValidationError( "No channel partner registered with specified maharera number, mobile number combination." ); } // Find the linked user next. const user = await strapi.query("plugin::users-permissions.user").findOne({ where: { $and: [ { id: channelPartner.user.id }, { oneTimePassword: oneTimePassword }, ], }, }); if (!user || user.blocked) { throw new ValidationError("Code provided is not valid."); } await getService("user").edit(user.id, { oneTimePassword: null, password: oneTimePassword, }); console.log("ctx >>>>>>>>>", user); ctx.send({ ok: true, message: "otp updated", data: user }); }; /** Example of overriding an existing route. */ plugin.controllers.auth.register = async (ctx) => { const pluginStore = await strapi.store({ type: "plugin", name: "users-permissions", }); const settings = await pluginStore.get({ key: "advanced" }); if (!settings.allow_register) { throw new ApplicationError("Register action is currently disabled"); } const params = { ..._.omit(ctx.request.body, [ "confirmed", "blocked", "confirmationToken", "resetPasswordToken", "provider", ]), provider: "local", }; await validateRegisterBody(params); // We have added the ability to choose the role. // This is the customisation that we wanted to do to make this possible const newUserRole = params?.role ? params?.role : settings.default_role; // the query was also changed to apply a query on "name" rather than the default "type". const role = await strapi .query("plugin::users-permissions.role") .findOne({ where: { name: newUserRole } }); if (!role) { throw new ApplicationError("Impossible to find the default role"); } console.log("HERE ARE PARAMS >>>>>", params); // @ts-ignore const { email, username, provider } = params; const identifierFilter = { $or: [ // { email: email.toLowerCase() }, // { username: email.toLowerCase() }, { username }, // { email: username }, ], }; const conflictingUserCount = await strapi .query("plugin::users-permissions.user") .count({ where: { ...identifierFilter, provider }, }); if (conflictingUserCount > 0) { throw new ApplicationError("RERA Number already in use."); } // if (settings.unique_email) { // const conflictingUserCount = await strapi // .query("plugin::users-permissions.user") // .count({ // where: { ...identifierFilter }, // }); // if (conflictingUserCount > 0) { // throw new ApplicationError("Email or Username are already taken"); // } // } let newUser = { ...params, role: role.id, email: email.toLowerCase(), username, confirmed: !settings.email_confirmation, }; console.log("newUser 123456789>>>>>", newUser); const user = await strapi .plugin("users-permissions") .service("user") .add(newUser); const sanitizedUser = await sanitizeUser(user, ctx); // console.log("SANITIZE sanitizedUser", sanitizedUser); // if (settings.email_confirmation) { // try { // await strapi // .plugin("users-permissions") // .service("user") // .sendConfirmationEmail(sanitizedUser); // } catch (err) { // throw new ApplicationError(err.message); // } // return ctx.send({ user: sanitizedUser }); // } const jwt = strapi .plugin("users-permissions") .service("jwt") .issue(_.pick(user, ["id"])); console.log("jwt"); return ctx.send({ jwt, user: sanitizedUser, }); }; /** Endpoint used to allow edits on a user done by currently logged in user only their own record. */ plugin.routes["content-api"].routes.push({ method: "PUT", path: "/users/me", handler: "user.updateMe", }); /** Endpoints used to facilitate channel partner login with otp */ plugin.routes["content-api"].routes.push({ method: "POST", path: "/users/channel-partner/start-otp-login", handler: "user.startChannelPartnerOtpLogin", }); plugin.routes["content-api"].routes.push({ method: "POST", path: "/users/channel-partner/finish-otp-login", handler: "user.finishChannelPartnerOtpLogin", }); /** Endpoints used to facilitate end user login with otp */ plugin.routes["content-api"].routes.push({ method: "POST", path: "/users/end-user/start-otp-login", handler: "user.startEndUserOtpLogin", }); plugin.routes["content-api"].routes.push({ method: "POST", path: "/users/end-user/finish-otp-login", handler: "user.finishEndUserOtpLogin", }); return plugin; }; module.exports = userPermissionExtension;