|
1 | 1 | import get from 'lodash/get'; |
2 | | -import { randomId } from '@imports/utils/random'; |
3 | 2 | import { MetaObject } from '@imports/model/MetaObject'; |
4 | 3 | import { User } from '@imports/model/User'; |
5 | | -import { DataDocument } from '@imports/types/data'; |
6 | 4 | import { logger } from '@imports/utils/logger'; |
7 | 5 | import queueManager from '@imports/queue/QueueManager'; |
8 | 6 | import { sendOtpViaWhatsApp, WhatsAppConfig } from './whatsapp'; |
9 | 7 | import { OTP_DEFAULT_EXPIRATION_MINUTES } from '../../consts'; |
| 8 | +import { create } from '@imports/data/data'; |
| 9 | +import { renderTemplate } from '@imports/template'; |
| 10 | +import { randomId } from '@imports/utils/random'; |
10 | 11 |
|
11 | 12 | export interface DeliveryResult { |
12 | 13 | success: boolean; |
@@ -163,36 +164,73 @@ async function sendViaEmail(phoneNumber: string | undefined, otpCode: string, us |
163 | 164 | } |
164 | 165 |
|
165 | 166 | const expirationMinutes = MetaObject.Namespace.otpConfig?.expirationMinutes ?? OTP_DEFAULT_EXPIRATION_MINUTES; |
166 | | - const templateId = MetaObject.Namespace.otpConfig?.emailTemplateId ?? 'email/otp.html'; |
| 167 | + const templateId = MetaObject.Namespace.otpConfig?.emailTemplateId ?? 'email/otp.hbs'; |
167 | 168 | const emailFrom = MetaObject.Namespace.otpConfig?.emailFrom ?? 'Konecty <support@konecty.com>'; |
168 | 169 |
|
169 | | - // Fetch user name for email template |
170 | | - const user = (await MetaObject.Collections.User.findOne({ _id: userId }, { projection: { name: 1 } })) as Pick<User, 'name'> | null; |
| 170 | + // Fetch user for contextUser and email template |
| 171 | + const user = (await MetaObject.Collections.User.findOne({ _id: userId }, { projection: { _id: 1, name: 1 } })) as Pick<User, '_id' | 'name'> | null; |
| 172 | + |
| 173 | + if (user == null) { |
| 174 | + return { |
| 175 | + success: false, |
| 176 | + error: 'User not found', |
| 177 | + }; |
| 178 | + } |
| 179 | + |
| 180 | + // Prepare template data |
| 181 | + const templateData = { |
| 182 | + otpCode, |
| 183 | + ...(phoneNumber != null && { phoneNumber }), |
| 184 | + ...(emailAddress != null && { email: emailAddress }), |
| 185 | + expirationMinutes, |
| 186 | + expiresAt: expiresAt.toISOString(), |
| 187 | + name: user.name, |
| 188 | + }; |
| 189 | + |
| 190 | + // Process template to generate body before creating message |
| 191 | + // This is required because email-service doesn't process templates |
| 192 | + let emailBody: string; |
| 193 | + const emailSubject = '[Konecty] Código de Verificação OTP'; |
| 194 | + |
| 195 | + try { |
| 196 | + const messageId = randomId(); |
| 197 | + emailBody = await renderTemplate(templateId, { message: { _id: messageId }, ...templateData }); |
| 198 | + } catch (error) { |
| 199 | + logger.error({ template: templateId, error: (error as Error).message }, 'Error rendering OTP email template'); |
| 200 | + return { |
| 201 | + success: false, |
| 202 | + error: `Failed to render email template: ${(error as Error).message}`, |
| 203 | + }; |
| 204 | + } |
171 | 205 |
|
172 | 206 | const messageData = { |
173 | | - _id: randomId(), |
174 | 207 | from: emailFrom, |
175 | 208 | to: emailAddress, |
176 | | - subject: '[Konecty] Código de Verificação OTP', |
| 209 | + subject: emailSubject, |
177 | 210 | type: 'Email', |
178 | 211 | status: 'Send', |
179 | | - template: templateId, |
| 212 | + body: emailBody, |
180 | 213 | discard: true, |
181 | | - _createdAt: new Date(), |
182 | | - _updatedAt: new Date(), |
183 | | - data: { |
184 | | - otpCode, |
185 | | - ...(phoneNumber != null && { phoneNumber }), |
186 | | - ...(emailAddress != null && { email: emailAddress }), |
187 | | - expirationMinutes, |
188 | | - expiresAt: expiresAt.toISOString(), |
189 | | - name: user?.name, |
190 | | - }, |
| 214 | + _user: [{ _id: userId }], |
| 215 | + data: templateData, |
191 | 216 | }; |
192 | 217 |
|
193 | 218 | try { |
194 | | - await MetaObject.Collections.Message.insertOne(messageData as DataDocument); |
195 | | - return { success: true, method: 'email' }; |
| 219 | + // Use data.create() instead of insertOne() to trigger events |
| 220 | + const result = await create({ |
| 221 | + document: 'Message', |
| 222 | + data: messageData, |
| 223 | + contextUser: user as User, |
| 224 | + } as any); |
| 225 | + |
| 226 | + if (result.success) { |
| 227 | + return { success: true, method: 'email' }; |
| 228 | + } |
| 229 | + |
| 230 | + return { |
| 231 | + success: false, |
| 232 | + error: Array.isArray(result.errors) ? result.errors.join(', ') : 'Failed to create message', |
| 233 | + }; |
196 | 234 | } catch (error) { |
197 | 235 | logger.error(error, 'Error sending OTP via email'); |
198 | 236 | return { |
|
0 commit comments