208 lines
6.3 KiB
TypeScript
208 lines
6.3 KiB
TypeScript
import { Inject, Injectable } from "@nestjs/common";
|
|
import { AccountRepo } from "./account.repo";
|
|
import * as DTO from './dto';
|
|
import { MailerService } from "src/util/mailer/mailer.service";
|
|
import { Generator } from "src/util/generator";
|
|
import Redis from "ioredis";
|
|
import { Converter } from "src/util/converter";
|
|
import { AuthService } from "src/middleware/auth/auth.service";
|
|
|
|
@Injectable()
|
|
export class AccountService {
|
|
constructor(
|
|
private readonly accountRepo: AccountRepo
|
|
, private readonly mailerService: MailerService
|
|
, private readonly authService: AuthService
|
|
, @Inject("REDIS") private readonly redis: Redis
|
|
) {}
|
|
|
|
async checkDuplication(data: DTO.CheckDuplicationRequest): Promise<DTO.CheckDuplicationResponse> {
|
|
const { type, value } = data;
|
|
const count = await this.accountRepo.checkIdExists(type, value);
|
|
|
|
return { isDuplicated: count > 0, success: true };
|
|
}
|
|
|
|
async sendVerificationCode(data: DTO.SendEmailVerificationCodeRequest): Promise<DTO.SendEmailVerificationCodeResponse> {
|
|
const { email } = data;
|
|
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(email, "<Scheduler> 이메일 인증 코드", html);
|
|
|
|
if (result.rejected.length > 0) {
|
|
return { success: false, error: result.response }
|
|
} else {
|
|
await this.redis.set(`verify:${email}`, code, 'EX', 600);
|
|
|
|
return { success: true, message: "이메일 발송 완료" };
|
|
}
|
|
}
|
|
|
|
async verifyCode(data: DTO.VerifyEmailVerificationCodeRequest): Promise<DTO.VerifyEmailVerificationCodeResponse> {
|
|
const { email, code } = data;
|
|
|
|
const storedCode = await this.redis.get(`verify:${email}`);
|
|
|
|
if (!storedCode) {
|
|
return { verified: false, success: true, error: '잘못된 이메일이거나 코드가 만료되었습니다.'};
|
|
}
|
|
if (storedCode !== code) {
|
|
return { verified: false, success: true, error: "잘못된 코드입니다." };
|
|
}
|
|
|
|
await this.redis.del(`verify:${email}`);
|
|
return { verified: true, success: true, message: "이메일 인증이 완료되었습니다." };
|
|
}
|
|
|
|
async signup(data: DTO.SignupRequest): Promise<DTO.SignupResponse> {
|
|
const { accountId, name, nickname, email, password } = data;
|
|
const hashedPassword = Converter.getHashedPassword(password);
|
|
const result = await this.accountRepo.signup(accountId, name, nickname, email, hashedPassword);
|
|
|
|
if (result.rowCount) {
|
|
return {
|
|
success: true,
|
|
message: "회원가입이 완료되었습니다."
|
|
};
|
|
} else {
|
|
return {
|
|
success: false,
|
|
error: "회원가입에 실패하였습니다."
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
async login(data: DTO.LoginRequest): Promise<DTO.LoginResponse> {
|
|
const { type, id, password } = data;
|
|
const queryResult = await this.accountRepo.login(type, id);
|
|
const typeValue = type === 'email' ? '이메일' : '아이디';
|
|
|
|
|
|
console.log(queryResult);
|
|
|
|
if (!queryResult || (queryResult.length < 1)) {
|
|
return {
|
|
success: false,
|
|
message: `존재하지 않는 ${typeValue} 입니다.`
|
|
};
|
|
}
|
|
|
|
|
|
const hashedPassword = queryResult[0].password;
|
|
const isPasswordMatch = Converter.comparePassword(password, hashedPassword);
|
|
if (!isPasswordMatch) {
|
|
return {
|
|
success: false,
|
|
message: `비밀번호가 맞지 않습니다.`
|
|
};
|
|
}
|
|
|
|
{
|
|
const { id, accountId, status, isDeleted, birthday } = queryResult[0];
|
|
|
|
const payload = {
|
|
id, accountId, status, isDeleted, birthday
|
|
};
|
|
|
|
const { accessToken, refreshToken } = this.authService.generateTokens(payload);
|
|
|
|
return {
|
|
success: true,
|
|
accessToken: accessToken,
|
|
refreshToken: refreshToken
|
|
};
|
|
}
|
|
}
|
|
|
|
async refreshAccessToken(id: string): Promise<DTO.RefreshAccessTokenResponse> {
|
|
const { accessToken, refreshToken } = this.authService.refreshTokens(id);
|
|
return {
|
|
accessToken: accessToken,
|
|
refreshToken: refreshToken,
|
|
success: true
|
|
};
|
|
}
|
|
|
|
async sendResetPasswordCode(data: DTO.SendResetPasswordCodeRequest): Promise<DTO.SendResetPasswordCodeResponse> {
|
|
const { email } = data;
|
|
|
|
const count = await this.accountRepo.checkIdExists('email', email);
|
|
|
|
if (count === 0) {
|
|
return {
|
|
success: false,
|
|
error: "찾을 수 없는 사용자"
|
|
};
|
|
}
|
|
|
|
const code = Generator.getResetPasswordCode();
|
|
|
|
const html =
|
|
`<p>Your Password Reset Code is: <strong>${code}</strong></p>`
|
|
+ `<p>Please Enter this code in 5 minutes.</p>`;
|
|
const result = await this.mailerService.sendMail(email, "<Scheduler> 비밀번호 초기화 코드", html);
|
|
|
|
if (result.rejected.length > 0) {
|
|
return {
|
|
success: false,
|
|
error: result.response
|
|
};
|
|
}
|
|
|
|
await this.redis.set(`resetPassword:${email}`, code, 'EX', 300);
|
|
|
|
return {
|
|
success: true,
|
|
message: "비밀번호 초기화 코드 발송 완료"
|
|
};
|
|
}
|
|
|
|
async verifyResetPasswordCode(data: DTO.VerifyResetPasswordCodeRequest): Promise<DTO.VerifyResetPasswordCodeResponse> {
|
|
const { email, code } = data;
|
|
|
|
const storedCode = await this.redis.get(`resetPassword:${email}`);
|
|
|
|
if (!storedCode) {
|
|
return {
|
|
success: false,
|
|
verified: false,
|
|
error: "잘못된 이메일이거나 코드가 만료되었습니다."
|
|
};
|
|
}
|
|
|
|
if (storedCode !== code) {
|
|
return {
|
|
success: false,
|
|
verified: false,
|
|
error: "잘못된 코드입니다."
|
|
};
|
|
}
|
|
|
|
await this.redis.del(`resetPassword:${email}`);
|
|
|
|
return {
|
|
success: true,
|
|
verified: true,
|
|
message: "비밀번호 초기화 코드 인증 완료"
|
|
};
|
|
}
|
|
|
|
async resetPassword(data: DTO.ResetPasswordRequest): Promise<DTO.ResetPasswordResponse> {
|
|
const { email, password } = data;
|
|
const hashedPassword = Converter.getHashedPassword(password);
|
|
const result = await this.accountRepo.updatePassword('email', email, hashedPassword);
|
|
|
|
if (!result.rowCount || result.rowCount === 0) {
|
|
return {
|
|
success: false,
|
|
error: "비밀번호 초기화 실패"
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
message: "비밀번호 초기화 성공"
|
|
};
|
|
}
|
|
} |