feat: mejorar el envío de correos electrónicos y agregar validaciones en el adaptador de notificaciones
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
mO9PXuuYR05od8cMVCIXEw
|
||||||
Generated
-82
@@ -6648,38 +6648,6 @@
|
|||||||
"url": "https://opencollective.com/mongoose"
|
"url": "https://opencollective.com/mongoose"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mongoose/node_modules/gaxios": {
|
|
||||||
"version": "5.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz",
|
|
||||||
"integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"extend": "^3.0.2",
|
|
||||||
"https-proxy-agent": "^5.0.0",
|
|
||||||
"is-stream": "^2.0.0",
|
|
||||||
"node-fetch": "^2.6.9"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mongoose/node_modules/gcp-metadata": {
|
|
||||||
"version": "5.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz",
|
|
||||||
"integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"gaxios": "^5.0.0",
|
|
||||||
"json-bigint": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mongoose/node_modules/mongodb": {
|
"node_modules/mongoose/node_modules/mongodb": {
|
||||||
"version": "6.10.0",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz",
|
||||||
@@ -6731,56 +6699,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||||
},
|
},
|
||||||
"node_modules/mongoose/node_modules/node-fetch": {
|
|
||||||
"version": "2.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
|
||||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"whatwg-url": "^5.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "4.x || >=6.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"encoding": "^0.1.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"encoding": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mongoose/node_modules/tr46": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
|
||||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"node_modules/mongoose/node_modules/webidl-conversions": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
|
||||||
"license": "BSD-2-Clause",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"node_modules/mongoose/node_modules/whatwg-url": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"tr46": "~0.0.3",
|
|
||||||
"webidl-conversions": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mpath": {
|
"node_modules/mpath": {
|
||||||
"version": "0.9.0",
|
"version": "0.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||||
|
|||||||
@@ -3,13 +3,37 @@ import { INotificationsAdapter, NotificationDataEmail } from "./Notifications.In
|
|||||||
|
|
||||||
export class NotificationsDonWebAdapter implements INotificationsAdapter<NotificationDataEmail> {
|
export class NotificationsDonWebAdapter implements INotificationsAdapter<NotificationDataEmail> {
|
||||||
async send(data: NotificationDataEmail): Promise<void> {
|
async send(data: NotificationDataEmail): Promise<void> {
|
||||||
const dataEmail = {
|
if (data.context && data.substitutions) {
|
||||||
|
throw new Error("No se puede enviar un email con context y substitutions al mismo tiempo.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.templateId && !data.message) {
|
||||||
|
throw new Error("Debe indicarse el contenido del email mediante message o templateId.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataEmail: Record<string, unknown> = {
|
||||||
from: "norepply@turnosxpress.com.ar",
|
from: "norepply@turnosxpress.com.ar",
|
||||||
to: data.email,
|
to: data.email,
|
||||||
subject: data.subject,
|
|
||||||
html: data.message,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (data.templateId) {
|
||||||
|
dataEmail.templateID = data.templateId;
|
||||||
|
} else {
|
||||||
|
dataEmail.html = data.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.subject) {
|
||||||
|
dataEmail.subject = data.subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.context) {
|
||||||
|
dataEmail.context = data.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.substitutions) {
|
||||||
|
dataEmail.substitutions = data.substitutions;
|
||||||
|
}
|
||||||
|
|
||||||
const apiConfig = {
|
const apiConfig = {
|
||||||
method: "post",
|
method: "post",
|
||||||
maxBodyLength: Infinity,
|
maxBodyLength: Infinity,
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ export enum NOTIFICATION_TYPES {
|
|||||||
|
|
||||||
export type NotificationDataEmail = {
|
export type NotificationDataEmail = {
|
||||||
email: string;
|
email: string;
|
||||||
subject: string;
|
subject?: string;
|
||||||
message: string;
|
message?: string;
|
||||||
|
templateId?: string;
|
||||||
|
context?: Record<string, unknown>;
|
||||||
|
substitutions?: Record<string, string | number | boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NotificationDataWap = {
|
export type NotificationDataWap = {
|
||||||
|
|||||||
@@ -351,6 +351,28 @@ class UsersManager implements IUsersManager {
|
|||||||
.substring(0, 6);
|
.substring(0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async sendWelcomeEmail(email: string, firstName?: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await NotificationsManager.sendEmail({
|
||||||
|
email: cleanEmail(email),
|
||||||
|
templateId: "68139f23f3e003139b08b4f0",
|
||||||
|
context: {
|
||||||
|
username: firstName || cleanEmail(email),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (axios.isAxiosError(e)) {
|
||||||
|
console.error("Error enviando email de bienvenida:", {
|
||||||
|
status: e.response?.status,
|
||||||
|
data: e.response?.data,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error("Error enviando email de bienvenida:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async signUp(data: SignUpParams): Promise<IUser> {
|
public async signUp(data: SignUpParams): Promise<IUser> {
|
||||||
// Destructure email and password from the data object
|
// Destructure email and password from the data object
|
||||||
const {
|
const {
|
||||||
@@ -406,12 +428,13 @@ class UsersManager implements IUsersManager {
|
|||||||
|
|
||||||
const newUser = await this.users.create(newUserData);
|
const newUser = await this.users.create(newUserData);
|
||||||
|
|
||||||
const signUpUrl = "https://turnosxpress.com.ar/landing/login/verification";
|
|
||||||
|
|
||||||
await NotificationsManager.sendEmail({
|
await NotificationsManager.sendEmail({
|
||||||
email: cleanEmail(email),
|
email: cleanEmail(email),
|
||||||
subject: "TurnosXpress :: Bienvenido/a",
|
templateId: "6a85dd644ea98ccfcd05bdc7",
|
||||||
message: `Hola ${firstName}, Gracias por registrarte en turnosXpress. Primero debes activar tu cuenta ingresando en ${signUpUrl} . Tu código de verificación es: ${verificationCode}`,
|
context: {
|
||||||
|
username: firstName || cleanEmail(email),
|
||||||
|
verificationcode: verificationCode,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return newUser;
|
return newUser;
|
||||||
@@ -459,8 +482,11 @@ class UsersManager implements IUsersManager {
|
|||||||
|
|
||||||
await NotificationsManager.sendEmail({
|
await NotificationsManager.sendEmail({
|
||||||
email: cleanEmail(data.email),
|
email: cleanEmail(data.email),
|
||||||
subject: "TurnosXpress :: Recuperación de cuenta",
|
templateId: "6a85c7ad96475f2825015277",
|
||||||
message: `Hola ${user.firstName}, Te enviamos un código de verificación para recuperar tu cuenta. Tu código de verificación es: ${code}. Ingresa https://turnosxpress.com.ar/landing/recover-account/verify para establecer una nueva clave`,
|
context: {
|
||||||
|
username: user.firstName || cleanEmail(data.email),
|
||||||
|
verificationcode: code,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -515,10 +541,16 @@ class UsersManager implements IUsersManager {
|
|||||||
throw new Error("El código de verificación es incorrecto");
|
throw new Error("El código de verificación es incorrecto");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wasVerificated = Boolean(userTest.verificated);
|
||||||
|
|
||||||
userTest.verificated = true;
|
userTest.verificated = true;
|
||||||
|
|
||||||
await userTest.save();
|
await userTest.save();
|
||||||
|
|
||||||
|
if (!wasVerificated) {
|
||||||
|
await this.sendWelcomeEmail(userTest.email, userTest.firstName);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const freePlan = await PlansList.plans.findOne({ price: 0 });
|
const freePlan = await PlansList.plans.findOne({ price: 0 });
|
||||||
if (freePlan) {
|
if (freePlan) {
|
||||||
@@ -724,11 +756,17 @@ class UsersManager implements IUsersManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (userCheck) {
|
if (userCheck) {
|
||||||
|
const wasVerificated = Boolean(userCheck.verificated);
|
||||||
|
|
||||||
userCheck.external_id = googleUserId;
|
userCheck.external_id = googleUserId;
|
||||||
userCheck.external_service = "google";
|
userCheck.external_service = "google";
|
||||||
userCheck.verificated = true;
|
userCheck.verificated = true;
|
||||||
await userCheck.save();
|
await userCheck.save();
|
||||||
|
|
||||||
|
if (!wasVerificated) {
|
||||||
|
await this.sendWelcomeEmail(userCheck.email, userCheck.firstName);
|
||||||
|
}
|
||||||
|
|
||||||
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
||||||
sessionUser: userCheck.id,
|
sessionUser: userCheck.id,
|
||||||
});
|
});
|
||||||
@@ -770,6 +808,8 @@ class UsersManager implements IUsersManager {
|
|||||||
throw new Error("Error creating user");
|
throw new Error("Error creating user");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.sendWelcomeEmail(newUser.email, newUser.firstName);
|
||||||
|
|
||||||
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
||||||
sessionUser: newUser.id,
|
sessionUser: newUser.id,
|
||||||
});
|
});
|
||||||
@@ -821,11 +861,17 @@ class UsersManager implements IUsersManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (userCheck) {
|
if (userCheck) {
|
||||||
|
const wasVerificated = Boolean(userCheck.verificated);
|
||||||
|
|
||||||
userCheck.external_id = googleData.id;
|
userCheck.external_id = googleData.id;
|
||||||
userCheck.external_service = "google";
|
userCheck.external_service = "google";
|
||||||
userCheck.verificated = true;
|
userCheck.verificated = true;
|
||||||
await userCheck.save();
|
await userCheck.save();
|
||||||
|
|
||||||
|
if (!wasVerificated) {
|
||||||
|
await this.sendWelcomeEmail(userCheck.email, userCheck.firstName);
|
||||||
|
}
|
||||||
|
|
||||||
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
||||||
sessionUser: userCheck.id,
|
sessionUser: userCheck.id,
|
||||||
});
|
});
|
||||||
@@ -867,6 +913,8 @@ class UsersManager implements IUsersManager {
|
|||||||
throw new Error("Error creating user");
|
throw new Error("Error creating user");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.sendWelcomeEmail(newUser.email, newUser.firstName);
|
||||||
|
|
||||||
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({
|
||||||
sessionUser: newUser.id,
|
sessionUser: newUser.id,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user