feat: choosable email
This commit is contained in:
parent
129b21b46b
commit
940fc7e583
|
|
@ -8,11 +8,15 @@ import { ForgotReturnPasswordDto } from '@gitroom/nestjs-libraries/dtos/auth/for
|
|||
import { ForgotPasswordDto } from '@gitroom/nestjs-libraries/dtos/auth/forgot.password.dto';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { getCookieUrlFromDomain } from '@gitroom/helpers/subdomain/subdomain.management';
|
||||
import { EmailService } from '@gitroom/nestjs-libraries/services/email.service';
|
||||
|
||||
@ApiTags('Auth')
|
||||
@Controller('/auth')
|
||||
export class AuthController {
|
||||
constructor(private _authService: AuthService) {}
|
||||
constructor(
|
||||
private _authService: AuthService,
|
||||
private _emailService: EmailService
|
||||
) {}
|
||||
@Post('/register')
|
||||
async register(
|
||||
@Req() req: Request,
|
||||
|
|
@ -30,7 +34,7 @@ export class AuthController {
|
|||
getOrgFromCookie
|
||||
);
|
||||
|
||||
const activationRequired = body.provider === 'LOCAL' && !!process.env.RESEND_API_KEY;
|
||||
const activationRequired = body.provider === 'LOCAL' && this._emailService.hasProvider();
|
||||
|
||||
if (activationRequired) {
|
||||
response.header('activate', 'true');
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ export class ConfigurationChecker {
|
|||
this.checkIsValidUrl('FRONTEND_URL')
|
||||
this.checkIsValidUrl('NEXT_PUBLIC_BACKEND_URL')
|
||||
this.checkIsValidUrl('BACKEND_INTERNAL_URL')
|
||||
this.checkNonEmpty('RESEND_API_KEY', 'Needed to send user activation emails.')
|
||||
this.checkNonEmpty('CLOUDFLARE_ACCOUNT_ID', 'Needed to setup providers.')
|
||||
this.checkNonEmpty('CLOUDFLARE_ACCESS_KEY', 'Needed to setup providers.')
|
||||
this.checkNonEmpty('CLOUDFLARE_SECRET_ACCESS_KEY', 'Needed to setup providers.')
|
||||
|
|
|
|||
|
|
@ -40,4 +40,8 @@ export class NotificationService {
|
|||
async sendEmail(to: string, subject: string, html: string) {
|
||||
await this._emailService.sendEmail(to, subject, html);
|
||||
}
|
||||
|
||||
hasEmailProvider() {
|
||||
return this._emailService.hasProvider();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,8 @@ export class OrganizationRepository {
|
|||
}
|
||||
|
||||
async createOrgAndUser(
|
||||
body: Omit<CreateOrgUserDto, 'providerToken'> & { providerId?: string }
|
||||
body: Omit<CreateOrgUserDto, 'providerToken'> & { providerId?: string },
|
||||
hasEmail: boolean
|
||||
) {
|
||||
return this._organization.model.organization.create({
|
||||
data: {
|
||||
|
|
@ -187,7 +188,7 @@ export class OrganizationRepository {
|
|||
role: Role.SUPERADMIN,
|
||||
user: {
|
||||
create: {
|
||||
activated: body.provider !== 'LOCAL' || !process.env.RESEND_API_KEY,
|
||||
activated: body.provider !== 'LOCAL' || !hasEmail,
|
||||
email: body.email,
|
||||
password: body.password
|
||||
? AuthService.hashPassword(body.password)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export class OrganizationService {
|
|||
async createOrgAndUser(
|
||||
body: Omit<CreateOrgUserDto, 'providerToken'> & { providerId?: string }
|
||||
) {
|
||||
return this._organizationRepository.createOrgAndUser(body);
|
||||
return this._organizationRepository.createOrgAndUser(body, this._notificationsService.hasEmailProvider());
|
||||
}
|
||||
|
||||
addUserToOrg(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
export interface EmailInterface {
|
||||
name: string;
|
||||
validateEnvKeys: string[];
|
||||
sendEmail(to: string, subject: string, html: string, emailFromName: string, emailFromAddress: string): Promise<any>;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { EmailInterface } from "./email.interface";
|
||||
|
||||
export class EmptyProvider implements EmailInterface {
|
||||
name = 'no provider';
|
||||
validateEnvKeys = [];
|
||||
async sendEmail(to: string, subject: string, html: string) {
|
||||
return `No email provider found, email was supposed to be sent to ${to} with subject: ${subject} and ${html}, html`;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import nodemailer from 'nodemailer';
|
||||
import { EmailInterface } from '@gitroom/nestjs-libraries/emails/email.interface';
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.EMAIL_HOST,
|
||||
port: +process.env.EMAIL_PORT!,
|
||||
secure: process.env.EMAIL_SECURE === 'true',
|
||||
auth: {
|
||||
user: process.env.EMAIL_USER,
|
||||
pass: process.env.EMAIL_PASS,
|
||||
},
|
||||
});
|
||||
|
||||
export class NodeMailerProvider implements EmailInterface {
|
||||
name = 'nodemailer';
|
||||
validateEnvKeys = [
|
||||
'EMAIL_HOST',
|
||||
'EMAIL_PORT',
|
||||
'EMAIL_SECURE',
|
||||
'EMAIL_USER',
|
||||
'EMAIL_PASS',
|
||||
];
|
||||
async sendEmail(
|
||||
to: string,
|
||||
subject: string,
|
||||
html: string,
|
||||
emailFromName: string,
|
||||
emailFromAddress: string
|
||||
) {
|
||||
const sends = await transporter.sendMail({
|
||||
from:`${emailFromName} <${emailFromAddress}>`, // sender address
|
||||
to: to, // list of receivers
|
||||
subject: subject, // Subject line
|
||||
text: html, // plain text body
|
||||
html: html, // html body
|
||||
});
|
||||
|
||||
return sends;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { Resend } from 'resend';
|
||||
import { EmailInterface } from '@gitroom/nestjs-libraries/emails/email.interface';
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY || 're_132');
|
||||
|
||||
export class ResendProvider implements EmailInterface {
|
||||
name = 'resend';
|
||||
validateEnvKeys = ['RESEND_API_KEY'];
|
||||
async sendEmail(to: string, subject: string, html: string, emailFromName: string, emailFromAddress: string) {
|
||||
const sends = await resend.emails.send({
|
||||
from: `${emailFromName} <${emailFromAddress}>`,
|
||||
to,
|
||||
subject,
|
||||
html,
|
||||
});
|
||||
|
||||
return sends;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,52 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY || 're_132');
|
||||
import { EmailInterface } from '@gitroom/nestjs-libraries/emails/email.interface';
|
||||
import { ResendProvider } from '@gitroom/nestjs-libraries/emails/resend.provider';
|
||||
import { EmptyProvider } from '@gitroom/nestjs-libraries/emails/empty.provider';
|
||||
import { NodeMailerProvider } from '@gitroom/nestjs-libraries/emails/node.mailer.provider';
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
emailService: EmailInterface;
|
||||
constructor() {
|
||||
this.emailService = this.selectProvider(process.env.EMAIL_PROVIDER!);
|
||||
console.log('Email service provider:', this.emailService.name);
|
||||
for (const key of this.emailService.validateEnvKeys) {
|
||||
if (!process.env[key]) {
|
||||
console.error(`Missing environment variable: ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasProvider() {
|
||||
return !(this.emailService instanceof EmptyProvider);
|
||||
}
|
||||
|
||||
selectProvider(provider: string) {
|
||||
switch (provider) {
|
||||
case 'resend':
|
||||
return new ResendProvider();
|
||||
case 'nodemailer':
|
||||
return new NodeMailerProvider();
|
||||
default:
|
||||
return new EmptyProvider();
|
||||
}
|
||||
}
|
||||
|
||||
async sendEmail(to: string, subject: string, html: string) {
|
||||
if (!process.env.RESEND_API_KEY) {
|
||||
console.log('No Resend API Key found, skipping email sending');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!process.env.EMAIL_FROM_ADDRESS || !process.env.EMAIL_FROM_NAME) {
|
||||
console.log('Email sender information not found in environment variables');
|
||||
console.log(
|
||||
'Email sender information not found in environment variables'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Sending email to', to);
|
||||
const sends = await resend.emails.send({
|
||||
from: `${process.env.EMAIL_FROM_NAME} <${process.env.EMAIL_FROM_ADDRESS}>`,
|
||||
const sends = await this.emailService.sendEmail(
|
||||
to,
|
||||
subject,
|
||||
html,
|
||||
});
|
||||
|
||||
process.env.EMAIL_FROM_NAME,
|
||||
process.env.EMAIL_FROM_ADDRESS
|
||||
);
|
||||
console.log(sends);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
"@types/md5": "^2.3.5",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/multer": "^1.4.11",
|
||||
"@types/nodemailer": "^6.4.16",
|
||||
"@types/remove-markdown": "^0.3.4",
|
||||
"@types/sha256": "^0.2.2",
|
||||
"@types/stripe": "^8.0.417",
|
||||
|
|
@ -90,6 +91,7 @@
|
|||
"nestjs-command": "^3.1.4",
|
||||
"next": "14.2.3",
|
||||
"next-plausible": "^3.12.0",
|
||||
"nodemailer": "^6.9.15",
|
||||
"nx": "19.7.2",
|
||||
"openai": "^4.47.1",
|
||||
"polotno": "^2.10.5",
|
||||
|
|
@ -12973,6 +12975,14 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/nodemailer": {
|
||||
"version": "6.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.16.tgz",
|
||||
"integrity": "sha512-uz6hN6Pp0upXMcilM61CoKyjT7sskBoOWpptkjjJp8jIMlTdc3xG01U7proKkXzruMS4hS0zqtHNkNPFB20rKQ==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||
|
|
@ -29267,6 +29277,14 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.9.15",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.15.tgz",
|
||||
"integrity": "sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@
|
|||
"@types/md5": "^2.3.5",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/multer": "^1.4.11",
|
||||
"@types/nodemailer": "^6.4.16",
|
||||
"@types/remove-markdown": "^0.3.4",
|
||||
"@types/sha256": "^0.2.2",
|
||||
"@types/stripe": "^8.0.417",
|
||||
|
|
@ -110,6 +111,7 @@
|
|||
"nestjs-command": "^3.1.4",
|
||||
"next": "14.2.3",
|
||||
"next-plausible": "^3.12.0",
|
||||
"nodemailer": "^6.9.15",
|
||||
"nx": "19.7.2",
|
||||
"openai": "^4.47.1",
|
||||
"polotno": "^2.10.5",
|
||||
|
|
|
|||
Loading…
Reference in New Issue