bizmatch-project/bizmatch-server/src/mail/mail.service.ts

188 lines
6.9 KiB
TypeScript

import { MailerService } from '@nestjs-modules/mailer';
import { BadRequestException, Injectable } from '@nestjs/common';
import { getAuth } from 'firebase-admin/auth';
import { join } from 'path';
import { ZodError } from 'zod';
import { SenderSchema, ShareByEMail, ShareByEMailSchema, User } from '../models/db.model';
import { ErrorResponse, MailInfo, isEmpty } from '../models/main.model';
import { UserService } from '../user/user.service';
// const __filename = fileURLToPath(import.meta.url);
// const __dirname = path.dirname(__filename);
@Injectable()
export class MailService {
constructor(
private mailerService: MailerService,
private userService: UserService,
) {}
async sendInquiry(mailInfo: MailInfo): Promise<void | ErrorResponse> {
try {
SenderSchema.parse(mailInfo.sender);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
}
throw error;
}
const user = await this.userService.getUserByMail(mailInfo.email);
if (isEmpty(mailInfo.sender.name)) {
return { fields: [{ fieldname: 'name', message: 'Required' }] };
}
await this.mailerService.sendMail({
to: user.email,
from: '"Bizmatch Team" <info@bizmatch.net>', // override default from
subject: `Inquiry from ${mailInfo.sender.name}`,
//template: './inquiry', // `.hbs` extension is appended automatically
template: join(__dirname, '../..', 'mail/templates/inquiry.hbs'),
context: {
// ✏️ filling curly brackets with content
name: user.firstname,
inquiry: mailInfo.sender.comments,
internalListingNumber: mailInfo.listing.internalListingNumber,
title: mailInfo.listing.title,
iname: mailInfo.sender.name,
phone: mailInfo.sender.phoneNumber,
email: mailInfo.sender.email,
id: mailInfo.listing.id,
url: mailInfo.url,
},
});
}
async sendVerificationEmail(
email: string,
redirectConfig: { protocol: string, hostname: string, port?: number }
): Promise<void | ErrorResponse> {
try {
// Firebase Auth-Instanz holen
const auth = getAuth();
// Baue den Redirect-URL aus den übergebenen Parametern
let continueUrl = `${redirectConfig.protocol}://${redirectConfig.hostname}`;
if (redirectConfig.port) {
continueUrl += `:${redirectConfig.port}`;
}
continueUrl += '/auth/verify-email-success'; // Beispiel für einen Weiterleitungspfad
// Custom Verification Link generieren
const firebaseActionLink = await auth.generateEmailVerificationLink(email, {
url: continueUrl,
handleCodeInApp: false,
});
// Extrahiere den oobCode aus dem Firebase Link
const actionLinkUrl = new URL(firebaseActionLink);
const oobCode = actionLinkUrl.searchParams.get('oobCode');
if (!oobCode) {
throw new BadRequestException('Failed to generate verification code');
}
// Erstelle die benutzerdefinierte URL mit dem oobCode
let customActionLink = `${redirectConfig.protocol}://${redirectConfig.hostname}`;
if (redirectConfig.port) {
customActionLink += `:${redirectConfig.port}`;
}
// Ersetze die Platzhalter mit den tatsächlichen Werten
customActionLink += `/email-authorized?email=${encodeURIComponent(email)}&mode=verifyEmail&oobCode=${oobCode}`;
// Zufallszahl für die E-Mail generieren
const randomNumber = Math.floor(Math.random() * 10000);
// E-Mail senden
await this.mailerService.sendMail({
to: email,
from: '"Bizmatch Team" <info@bizmatch.net>',
subject: 'Verify your email address',
template: join(__dirname, '../..', 'mail/templates/email-verification.hbs'),
context: {
actionLink: customActionLink,
randomNumber: randomNumber
},
});
return;
} catch (error) {
console.error('Error sending verification email:', error);
throw new BadRequestException('Failed to send verification email');
}
}
async sendRequest(mailInfo: MailInfo): Promise<void | ErrorResponse> {
try {
SenderSchema.parse(mailInfo.sender);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
}
throw error;
}
await this.mailerService.sendMail({
to: 'support@bizmatch.net',
from: `"Bizmatch Support Team" <info@bizmatch.net>`,
subject: `Support Request from ${mailInfo.sender.name}`,
//template: './inquiry', // `.hbs` extension is appended automatically
template: join(__dirname, '../..', 'mail/templates/request.hbs'),
context: {
// ✏️ filling curly brackets with content
request: mailInfo.sender.comments,
iname: mailInfo.sender.name,
phone: mailInfo.sender.phoneNumber,
email: mailInfo.sender.email,
},
});
}
async sendSubscriptionConfirmation(user: User): Promise<void> {
await this.mailerService.sendMail({
to: user.email,
from: `"Bizmatch Support Team" <info@bizmatch.net>`,
subject: `Subscription Confirmation`,
//template: './inquiry', // `.hbs` extension is appended automatically
template: join(__dirname, '../..', 'mail/templates/subscriptionConfirmation.hbs'),
context: {
// ✏️ filling curly brackets with content
firstname: user.firstname,
lastname: user.lastname,
subscriptionPlan: user.subscriptionPlan,
},
});
}
async send2Friend(shareByEMail: ShareByEMail): Promise<void | ErrorResponse> {
try {
ShareByEMailSchema.parse(shareByEMail);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
}
throw error;
}
await this.mailerService.sendMail({
to: shareByEMail.recipientEmail,
from: `"Bizmatch.net" <info@bizmatch.net>`,
subject: `${shareByEMail.type === 'business' ? 'Business' : 'Commercial Property'} For Sale: ${shareByEMail.listingTitle}`,
//template: './inquiry', // `.hbs` extension is appended automatically
template: join(__dirname, '../..', 'mail/templates/send2Friend.hbs'),
context: {
name: shareByEMail.yourName,
email: shareByEMail.yourEmail,
listingTitle: shareByEMail.listingTitle,
url: shareByEMail.url,
id: shareByEMail.id,
type: shareByEMail.type,
},
});
}
}