issue # 이메일 인증 코드 발송 로직 구현
This commit is contained in:
2
.env
2
.env
@@ -19,7 +19,7 @@ GMAIL_USER=bkd.scheduler@gmail.com
|
||||
GMAIL_PASS= # 앱 비밀번호 또는 OAuth2 토큰
|
||||
GMAIL_CLIENT_ID=688417162908-iqvnj4ceb8t1dkbjr70dtcafo27m8kqe.apps.googleusercontent.com
|
||||
GMAIL_CLIENT_SECRET=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
|
||||
GMAIL_REFRESH_TOKEN=1//04_pSivNoGpPUCgYIARAAGAQSNwF-L9IrO0Kx6jSzq_eQNjdl65f0O2iqKSNpFeZ3gtIGMhOk0oiZsnKrPfWs8jvuEic1NhUoZ0g
|
||||
GMAIL_REFRESH_TOKEN=1//04P8ekVQmkdtnCgYIARAAGAQSNwF-L9IrqPOyH8oYB-mdjUqw9jGHienVLBTWFdiZgpRnPgFmYnAdbjnstd9RkRVeJErB0NRAwg4
|
||||
|
||||
# SMTP 추가 옵션
|
||||
SMTP_AUTH=true
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-kit": "^0.31.7",
|
||||
"drizzle-orm": "^0.44.7",
|
||||
"googleapis": "^166.0.0",
|
||||
"ioredis": "^5.8.2",
|
||||
"nodemailer": "^7.0.10",
|
||||
"pg": "^8.16.3",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1"
|
||||
@@ -43,6 +45,7 @@
|
||||
"@types/ioredis": "^5.0.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/nodemailer": "^7.0.4",
|
||||
"@types/pg": "^8.15.6",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"eslint": "^9.18.0",
|
||||
|
||||
@@ -3,9 +3,11 @@ import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { DbModule } from './db/db.module';
|
||||
import { RedisModule } from './redis/redis.module';
|
||||
import { AccountModule } from './modules/account/account.module';
|
||||
import { MailerModule } from './util/mailer/mailer.module';
|
||||
|
||||
@Module({
|
||||
imports: [DbModule, RedisModule],
|
||||
imports: [DbModule, RedisModule, MailerModule, AccountModule],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
import { Controller, Get, Post, Query } from "@nestjs/common";
|
||||
import { Body, Controller, Get, Post, Query } from "@nestjs/common";
|
||||
import { CheckDuplicationRequestDto } from "./dto/checkDuplication/check-duplication-request.dto";
|
||||
import { CheckDuplicationResponseDto } from "./dto/checkDuplication/check-duplication-response.dto";
|
||||
import { AccountService } from "./account.service";
|
||||
import { SendVerificationCodeRequestDto } from "./dto/checkDuplication/send-verification-code-request.dto";
|
||||
import { SendVerificationCodeResponseDto } from "./dto/checkDuplication/send-verification-code-response.dto";
|
||||
|
||||
@Controller('account')
|
||||
export class AccountController {
|
||||
constructor(private readonly accountService: AccountService) {}
|
||||
|
||||
@Get('/')
|
||||
async test() {
|
||||
return "Test"
|
||||
}
|
||||
|
||||
@Get('check-duplication')
|
||||
async checkDuplication(@Query() query: CheckDuplicationRequestDto): Promise<CheckDuplicationResponseDto> {
|
||||
return this.accountService.checkDuplication(query);
|
||||
return await this.accountService.checkDuplication(query);
|
||||
}
|
||||
|
||||
@Post('send-verification-code')
|
||||
async sendVerificationCode(@Body() body: SendVerificationCodeRequestDto): Promise<SendVerificationCodeResponseDto> {
|
||||
const result = await this.accountService.sendVerificationCode(body);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { AccountService } from "./account.service";
|
||||
|
||||
@Module({
|
||||
controllers: [AccountController],
|
||||
providers: [AccountService, AccountRepo]
|
||||
providers: [AccountService, AccountRepo],
|
||||
exports: [AccountService, AccountRepo]
|
||||
})
|
||||
export class AccountModule {}
|
||||
@@ -2,14 +2,33 @@ import { Injectable } from "@nestjs/common";
|
||||
import { AccountRepo } from "./account.repo";
|
||||
import { CheckDuplicationRequestDto } from "./dto/checkDuplication/check-duplication-request.dto";
|
||||
import { CheckDuplicationResponseDto } from "./dto/checkDuplication/check-duplication-response.dto";
|
||||
import { SendVerificationCodeRequestDto } from "./dto/checkDuplication/send-verification-code-request.dto";
|
||||
import { MailerService } from "src/util/mailer/mailer.service";
|
||||
import { Generator } from "src/util/generator";
|
||||
import { SendVerificationCodeResponseDto } from "./dto/checkDuplication/send-verification-code-response.dto";
|
||||
|
||||
@Injectable()
|
||||
export class AccountService {
|
||||
constructor(private readonly accountRepo: AccountRepo) {}
|
||||
constructor(
|
||||
private readonly accountRepo: AccountRepo
|
||||
, private readonly mailerService: MailerService
|
||||
) {}
|
||||
|
||||
async checkDuplication(data: CheckDuplicationRequestDto): Promise<CheckDuplicationResponseDto> {
|
||||
const count = await this.accountRepo.checkDuplication(data.type, data.value);
|
||||
|
||||
return { isDuplicated: count > 0 };
|
||||
}
|
||||
|
||||
async sendVerificationCode(data: SendVerificationCodeRequestDto): Promise<SendVerificationCodeResponseDto> {
|
||||
const code = Generator.getVerificationCode();
|
||||
const html = `<p>Your verification code is: <strong style="font-size:16px;">${code}</strong></p>`;
|
||||
const result = await this.mailerService.sendMail(data.email, "<Scheduler> 이메일 인증 코드", html);
|
||||
|
||||
if (result.rejected.length > 0) {
|
||||
return { success: false, error: result.response }
|
||||
} else {
|
||||
return { success: true, message: "이메일 발송 완료" };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { IsEmail } from "@nestjs/class-validator";
|
||||
|
||||
export class SendVerificationCodeRequestDto {
|
||||
@IsEmail()
|
||||
email: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export class SendVerificationCodeResponseDto {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
0
src/util/converter.ts
Normal file
0
src/util/converter.ts
Normal file
5
src/util/generator.ts
Normal file
5
src/util/generator.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export class Generator {
|
||||
static getVerificationCode() {
|
||||
return Math.random().toString().slice(2, 8);
|
||||
}
|
||||
}
|
||||
9
src/util/mailer/mailer.module.ts
Normal file
9
src/util/mailer/mailer.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Module, Global } from '@nestjs/common';
|
||||
import { MailerService } from './mailer.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [MailerService],
|
||||
exports: [MailerService]
|
||||
})
|
||||
export class MailerModule {}
|
||||
46
src/util/mailer/mailer.service.ts
Normal file
46
src/util/mailer/mailer.service.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import nodemailer from 'nodemailer';
|
||||
import { google } from 'googleapis';
|
||||
import SMTPTransport from 'nodemailer/lib/smtp-transport';
|
||||
|
||||
@Injectable()
|
||||
export class MailerService {
|
||||
private oauth2Client = new google.auth.OAuth2(
|
||||
process.env.GMAIL_CLIENT_ID,
|
||||
process.env.GMAIL_CLIENT_SECRET,
|
||||
'https://developers.google.com/oauthplayground'
|
||||
);
|
||||
|
||||
constructor() {
|
||||
this.oauth2Client.setCredentials({
|
||||
refresh_token: process.env.GMAIL_REFRESH_TOKEN
|
||||
});
|
||||
}
|
||||
|
||||
async sendMail(to: string, subject: string, html: string) {
|
||||
const accessToken = await this.oauth2Client.getAccessToken();
|
||||
console.log(accessToken);
|
||||
const options: SMTPTransport.Options = {
|
||||
host: "smtp.gmail.com",
|
||||
port: 465,
|
||||
secure: true,
|
||||
auth: {
|
||||
type: "OAuth2",
|
||||
user: process.env.GMAIL_USER,
|
||||
clientId: process.env.GMAIL_CLIENT_ID,
|
||||
clientSecret: process.env.GMAIL_CLIENT_SECRET,
|
||||
refreshToken: process.env.GMAIL_REFRESH_TOKEN,
|
||||
accessToken: accessToken?.token || ''
|
||||
}
|
||||
}
|
||||
|
||||
const transporter = nodemailer.createTransport(options);
|
||||
|
||||
return transporter.sendMail({
|
||||
from: `Scheduler ${process.env.GMAIL_USER}>`,
|
||||
to,
|
||||
subject,
|
||||
html
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user