From ffa3768e1b050a2dfdb0313e10cb79a23577a4ac Mon Sep 17 00:00:00 2001 From: donghquinn Date: Thu, 7 Mar 2024 22:14:23 +0900 Subject: [PATCH 1/4] wip: seperate client search and star from client controller --- prisma/schema.prisma | 2 +- src/controllers/client/client.ctl.ts | 104 +-------------------------- src/controllers/client/search.ctl.ts | 53 ++++++++++++++ src/controllers/client/star.ctl.ts | 58 +++++++++++++++ src/modules/client/client.module.ts | 4 +- src/providers/client/client.pvd.ts | 1 - 6 files changed, 117 insertions(+), 105 deletions(-) create mode 100644 src/controllers/client/search.ctl.ts create mode 100644 src/controllers/client/star.ctl.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 23f1650..9d3b556 100755 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,7 +16,7 @@ model Client{ name String password String password_token String - is_logined Int @default(0) + is_logined Boolean @default(false) signed_in DateTime @default(now()) logined DateTime @updatedAt liked_hacker_posts Hacker_Liked[] diff --git a/src/controllers/client/client.ctl.ts b/src/controllers/client/client.ctl.ts index 82be718..7515c2f 100644 --- a/src/controllers/client/client.ctl.ts +++ b/src/controllers/client/client.ctl.ts @@ -1,27 +1,14 @@ import { Body, Controller, Post } from '@nestjs/common'; import { clientLoginValidator } from '@validators/client/login.validator'; import { clientLogoutValidator } from '@validators/client/logout.validator'; -import { clientMyPageStarNewsValidator, clientMyPageValidator } from '@validators/client/mypage.validator'; -import { - searchEmailRequestValidator, - searchPasswordRequestValidator, - validatePasswordTempKeyRequestValidator, -} from '@validators/client/search.validator'; +import { clientMyPageValidator } from '@validators/client/mypage.validator'; import { clientSignupValidator } from '@validators/client/signup.validator'; import { changePasswordValidator } from '@validators/client/user.validator'; import { SetErrorResponse, SetResponse } from 'dto/response.dto'; import { ClientProvider } from 'providers/client/client.pvd'; -import { - ClientLoginRequest, - ClientLogoutRequest, - ClientMyPageRequest, - ClientMyPageStarNewsRequest, - ClientSignupRequest, -} from 'types/client.type'; -import { SearchEmailRequest, SearchPasswordRequest, ValidatePasswordKeyRequest } from 'types/password.type'; +import { ClientLoginRequest, ClientLogoutRequest, ClientMyPageRequest, ClientSignupRequest } from 'types/client.type'; import { ChangePasswordRequest } from 'types/user.type'; -// TODO User 회원가입 / 로그인 / 로그아웃 / 회원 탈퇴 기능 구현 @Controller('users') export class ClientController { constructor(private readonly client: ClientProvider) {} @@ -86,93 +73,6 @@ export class ClientController { } } - @Post('star/hacker') - async getHackerStarNewsController(@Body() request: ClientMyPageStarNewsRequest) { - try { - const { uuid, page } = await clientMyPageStarNewsValidator(request); - - const { totalPosts, hackerNews: hackerStarredNews } = await this.client.myStarredHackerNews(uuid, page); - - return new SetResponse(200, { - totalPosts, - hackerStarredNews, - }); - } catch (error) { - return new SetErrorResponse(error); - } - } - - @Post('star/geek') - async getGeekStarNewsController(@Body() request: ClientMyPageStarNewsRequest) { - try { - const { uuid, page } = await clientMyPageStarNewsValidator(request); - - const { totalPosts, resultNewsArray: geekStarredNews } = await this.client.myStarredGeekNews(uuid, page); - - return new SetResponse(200, { - totalPosts, - geekStarredNews, - }); - } catch (error) { - return new SetErrorResponse(error); - } - } - - @Post('star/ml') - async getMlStarNewsController(@Body() request: ClientMyPageStarNewsRequest) { - try { - const { uuid, page } = await clientMyPageStarNewsValidator(request); - - const { totalPosts, mlNews: mlStarredNews } = await this.client.myStarredMlNews(uuid, page); - - return new SetResponse(200, { - totalPosts, - mlStarredNews, - }); - } catch (error) { - return new SetErrorResponse(error); - } - } - - @Post('search/email') - async searchEmailController(@Body() request: SearchEmailRequest) { - try { - const { name } = await searchEmailRequestValidator(request); - - const email = await this.client.searchEmail(name); - - return new SetResponse(200, { email }); - } catch (error) { - return new SetErrorResponse(error); - } - } - - @Post('search/password') - async searchPasswordController(@Body() request: SearchPasswordRequest) { - try { - const { name, email } = await searchPasswordRequestValidator(request); - - const message = await this.client.searchPassword(email, name); - - return new SetResponse(200, { message }); - } catch (error) { - return new SetErrorResponse(error); - } - } - - @Post('search/password/validate') - async validatePasswordTempKeyController(@Body() request: ValidatePasswordKeyRequest) { - try { - const { tempKey } = await validatePasswordTempKeyRequestValidator(request); - - const message = await this.client.validateSearchingPasswordKey(tempKey); - - return new SetResponse(200, { message }); - } catch (error) { - return new SetErrorResponse(error); - } - } - @Post('change/password') async changePasswordController(@Body() request: ChangePasswordRequest) { try { diff --git a/src/controllers/client/search.ctl.ts b/src/controllers/client/search.ctl.ts new file mode 100644 index 0000000..971f088 --- /dev/null +++ b/src/controllers/client/search.ctl.ts @@ -0,0 +1,53 @@ +import { Body, Controller, Post } from '@nestjs/common'; +import { + searchEmailRequestValidator, + searchPasswordRequestValidator, + validatePasswordTempKeyRequestValidator, +} from '@validators/client/search.validator'; +import { SetErrorResponse, SetResponse } from 'dto/response.dto'; +import { ClientProvider } from 'providers/client/client.pvd'; +import { SearchEmailRequest, SearchPasswordRequest, ValidatePasswordKeyRequest } from 'types/password.type'; + +@Controller('users/search') +export class ClientSearchController { + constructor(private readonly client: ClientProvider) {} + + @Post('email') + async searchEmailController(@Body() request: SearchEmailRequest) { + try { + const { name } = await searchEmailRequestValidator(request); + + const email = await this.client.searchEmail(name); + + return new SetResponse(200, { email }); + } catch (error) { + return new SetErrorResponse(error); + } + } + + @Post('password') + async searchPasswordController(@Body() request: SearchPasswordRequest) { + try { + const { name, email } = await searchPasswordRequestValidator(request); + + const message = await this.client.searchPassword(email, name); + + return new SetResponse(200, { message }); + } catch (error) { + return new SetErrorResponse(error); + } + } + + @Post('password/validate') + async validatePasswordTempKeyController(@Body() request: ValidatePasswordKeyRequest) { + try { + const { tempKey } = await validatePasswordTempKeyRequestValidator(request); + + const message = await this.client.validateSearchingPasswordKey(tempKey); + + return new SetResponse(200, { message }); + } catch (error) { + return new SetErrorResponse(error); + } + } +} diff --git a/src/controllers/client/star.ctl.ts b/src/controllers/client/star.ctl.ts new file mode 100644 index 0000000..1e6988b --- /dev/null +++ b/src/controllers/client/star.ctl.ts @@ -0,0 +1,58 @@ +import { Body, Controller, Post } from '@nestjs/common'; +import { clientMyPageStarNewsValidator } from '@validators/client/mypage.validator'; +import { SetErrorResponse, SetResponse } from 'dto/response.dto'; +import { ClientProvider } from 'providers/client/client.pvd'; +import { ClientMyPageStarNewsRequest } from 'types/client.type'; + +@Controller('users/star') +export class ClientStarController { + constructor(private readonly client: ClientProvider) {} + + @Post('star/hacker') + async getHackerStarNewsController(@Body() request: ClientMyPageStarNewsRequest) { + try { + const { uuid, page } = await clientMyPageStarNewsValidator(request); + + const { totalPosts, hackerNews: hackerStarredNews } = await this.client.myStarredHackerNews(uuid, page); + + return new SetResponse(200, { + totalPosts, + hackerStarredNews, + }); + } catch (error) { + return new SetErrorResponse(error); + } + } + + @Post('star/geek') + async getGeekStarNewsController(@Body() request: ClientMyPageStarNewsRequest) { + try { + const { uuid, page } = await clientMyPageStarNewsValidator(request); + + const { totalPosts, resultNewsArray: geekStarredNews } = await this.client.myStarredGeekNews(uuid, page); + + return new SetResponse(200, { + totalPosts, + geekStarredNews, + }); + } catch (error) { + return new SetErrorResponse(error); + } + } + + @Post('star/ml') + async getMlStarNewsController(@Body() request: ClientMyPageStarNewsRequest) { + try { + const { uuid, page } = await clientMyPageStarNewsValidator(request); + + const { totalPosts, mlNews: mlStarredNews } = await this.client.myStarredMlNews(uuid, page); + + return new SetResponse(200, { + totalPosts, + mlStarredNews, + }); + } catch (error) { + return new SetErrorResponse(error); + } + } +} diff --git a/src/modules/client/client.module.ts b/src/modules/client/client.module.ts index cd81dce..b7269e9 100644 --- a/src/modules/client/client.module.ts +++ b/src/modules/client/client.module.ts @@ -1,4 +1,6 @@ import { ClientController } from '@controllers/client/client.ctl'; +import { ClientSearchController } from '@controllers/client/search.ctl'; +import { ClientStarController } from '@controllers/client/star.ctl'; import { MailerModule } from '@modules/mailer.module'; import { Module } from '@nestjs/common'; import { ClientProvider } from 'providers/client/client.pvd'; @@ -8,6 +10,6 @@ import { ClientPrismaModule } from './client-prisma.module'; @Module({ providers: [ClientProvider], imports: [AccountManagerModule, ClientPrismaModule, MailerModule], - controllers: [ClientController], + controllers: [ClientController, ClientSearchController, ClientStarController], }) export class ClientModule {} diff --git a/src/providers/client/client.pvd.ts b/src/providers/client/client.pvd.ts index d628641..14d6681 100644 --- a/src/providers/client/client.pvd.ts +++ b/src/providers/client/client.pvd.ts @@ -366,7 +366,6 @@ export class ClientProvider { if (result === null) throw new NoUserError('[SEARCH_PASS] Search Password', 'No User Found'); - // TODO String Encoding const randomKey = randomBytes(8).toString('hex'); // const { encodedData: encodedPassword, dataToken: passwordToken } = cryptData(randomPassword); From cace8dcda48cdab6534ba6f9b0c53eaf50e41812 Mon Sep 17 00:00:00 2001 From: donghquinn Date: Thu, 7 Mar 2024 23:25:54 +0900 Subject: [PATCH 2/4] wip --- src/controllers/client/search.ctl.ts | 4 +- src/controllers/client/star.ctl.ts | 4 +- src/controllers/geek/geek.ctl.ts | 4 +- src/modules/client/client.module.ts | 3 +- src/providers/client/client-prisma.pvd.ts | 2 +- src/providers/client/client.pvd.ts | 244 +--------------------- src/providers/client/search.pvd.ts | 105 ++++++++++ src/providers/client/star.pvd.ts | 163 +++++++++++++++ src/providers/news/geek/geek.pvd.ts | 4 +- src/types/geek.type.ts | 6 +- src/validators/geek.validator.ts | 4 +- 11 files changed, 287 insertions(+), 256 deletions(-) create mode 100644 src/providers/client/search.pvd.ts create mode 100644 src/providers/client/star.pvd.ts diff --git a/src/controllers/client/search.ctl.ts b/src/controllers/client/search.ctl.ts index 971f088..40860c6 100644 --- a/src/controllers/client/search.ctl.ts +++ b/src/controllers/client/search.ctl.ts @@ -5,12 +5,12 @@ import { validatePasswordTempKeyRequestValidator, } from '@validators/client/search.validator'; import { SetErrorResponse, SetResponse } from 'dto/response.dto'; -import { ClientProvider } from 'providers/client/client.pvd'; +import { ClientSearchProvider } from 'providers/client/search.pvd'; import { SearchEmailRequest, SearchPasswordRequest, ValidatePasswordKeyRequest } from 'types/password.type'; @Controller('users/search') export class ClientSearchController { - constructor(private readonly client: ClientProvider) {} + constructor(private readonly client: ClientSearchProvider) {} @Post('email') async searchEmailController(@Body() request: SearchEmailRequest) { diff --git a/src/controllers/client/star.ctl.ts b/src/controllers/client/star.ctl.ts index 1e6988b..d1e3b77 100644 --- a/src/controllers/client/star.ctl.ts +++ b/src/controllers/client/star.ctl.ts @@ -1,12 +1,12 @@ import { Body, Controller, Post } from '@nestjs/common'; import { clientMyPageStarNewsValidator } from '@validators/client/mypage.validator'; import { SetErrorResponse, SetResponse } from 'dto/response.dto'; -import { ClientProvider } from 'providers/client/client.pvd'; +import { ClientStarProvider } from 'providers/client/star.pvd'; import { ClientMyPageStarNewsRequest } from 'types/client.type'; @Controller('users/star') export class ClientStarController { - constructor(private readonly client: ClientProvider) {} + constructor(private readonly client: ClientStarProvider) {} @Post('star/hacker') async getHackerStarNewsController(@Body() request: ClientMyPageStarNewsRequest) { diff --git a/src/controllers/geek/geek.ctl.ts b/src/controllers/geek/geek.ctl.ts index 68bcc8a..747edb1 100755 --- a/src/controllers/geek/geek.ctl.ts +++ b/src/controllers/geek/geek.ctl.ts @@ -2,7 +2,7 @@ import { Body, Controller, Post, Query } from '@nestjs/common'; import { geekNewsStarValidator, geekNewsUnStarValidator, geekNewsValidator } from '@validators/geek.validator'; import { SetErrorResponse, SetResponse } from 'dto/response.dto'; import { GeekProvider } from 'providers/news/geek/geek.pvd'; -import { DailyHadaNewsRequest } from 'types/geek.type'; +import { DailyGeekNewsRequest } from 'types/geek.type'; import { StarRequest } from 'types/request.type'; @Controller('geek') @@ -11,7 +11,7 @@ export class GeekController { @Post('news') async geekGetLatestNewsController( - @Body() request: DailyHadaNewsRequest, + @Body() request: DailyGeekNewsRequest, @Query('page') page: number, @Query('size') size: number, ) { diff --git a/src/modules/client/client.module.ts b/src/modules/client/client.module.ts index b7269e9..327f460 100644 --- a/src/modules/client/client.module.ts +++ b/src/modules/client/client.module.ts @@ -4,11 +4,12 @@ import { ClientStarController } from '@controllers/client/star.ctl'; import { MailerModule } from '@modules/mailer.module'; import { Module } from '@nestjs/common'; import { ClientProvider } from 'providers/client/client.pvd'; +import { ClientSearchProvider } from 'providers/client/search.pvd'; import { AccountManagerModule } from './account.module'; import { ClientPrismaModule } from './client-prisma.module'; @Module({ - providers: [ClientProvider], + providers: [ClientProvider, ClientSearchProvider], imports: [AccountManagerModule, ClientPrismaModule, MailerModule], controllers: [ClientController, ClientSearchController, ClientStarController], }) diff --git a/src/providers/client/client-prisma.pvd.ts b/src/providers/client/client-prisma.pvd.ts index 1ce1189..9e528df 100644 --- a/src/providers/client/client-prisma.pvd.ts +++ b/src/providers/client/client-prisma.pvd.ts @@ -114,7 +114,7 @@ export class ClientPrismaLibrary extends PrismaClient { } } - async updateClientLoginStatus(email: string, clientUuid: string, isLogined: number) { + async updateClientLoginStatus(email: string, clientUuid: string, isLogined: boolean) { try { await this.client.update({ data: { diff --git a/src/providers/client/client.pvd.ts b/src/providers/client/client.pvd.ts index 14d6681..244cb80 100644 --- a/src/providers/client/client.pvd.ts +++ b/src/providers/client/client.pvd.ts @@ -1,14 +1,11 @@ import { ClientError, NoUserError } from '@errors/client.error'; -import { NoValidateKeyError, PasswordError } from '@errors/password.error'; +import { PasswordError } from '@errors/password.error'; import { comparePassword, decrypt } from '@libraries/client/decrypt.lib'; import { cryptData } from '@libraries/client/encrypt.lib'; import { Injectable } from '@nestjs/common'; import { ClientLogger } from '@utils/logger.util'; -import { createSearchPasswordMailcontent } from '@utils/mail.utils'; -import { randomBytes } from 'crypto'; import { MailerProvider } from 'providers/mailer.pvd'; import { clearIntervalAsync, setIntervalAsync } from 'set-interval-async'; -import { HadaNewsReturn } from 'types/geek.type'; import { AccountManager } from '../auth/account-manager.pvd'; import { ClientPrismaLibrary } from './client-prisma.pvd'; @@ -118,7 +115,7 @@ export class ClientProvider { } }, interval); - await this.prisma.updateClientLoginStatus(email, uuid, 1); + await this.prisma.updateClientLoginStatus(email, uuid, true); return encodedEmail; } catch (error) { @@ -150,7 +147,7 @@ export class ClientProvider { const email = decrypt(encodedEmail, token); - await this.prisma.updateClientLoginStatus(email, uuid, 0); + await this.prisma.updateClientLoginStatus(email, uuid, false); const deleteItem = await this.accountManager.deleteItem(encodedEmail); @@ -210,241 +207,6 @@ export class ClientProvider { } } - async myStarredMlNews(clientUuid: string, page: number) { - try { - const foundKey = await this.accountManager.getItem(clientUuid); - - if (foundKey === null) { - ClientLogger.debug('[MYPAGE] No Matching User Found: %o', { - clientUuid, - }); - - throw new ClientError('[MYPAGE] Finding Matching User Info', 'No Matching User Found'); - } - - ClientLogger.debug('[MYPAGE] Found Key Item: %o', { - clientUuid, - foundKey, - }); - - const { totalPosts, mlStarredNews } = await this.prisma.getStarredMlNewsPagination(page, 10, clientUuid); - - const mlNews = mlStarredNews.map((item) => item.ml_news); - - return { - totalPosts, - mlNews, - }; - } catch (error) { - ClientLogger.error('[MYPAGE] Get My Page Error: %o', { - error, - }); - - throw new ClientError( - '[MYPAGE] Get My Page', - 'Get My Page Error. Please try again.', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } - - async myStarredHackerNews(clientUuid: string, page: number) { - try { - const foundKey = await this.accountManager.getItem(clientUuid); - - if (foundKey === null) { - ClientLogger.debug('[MYPAGE] No Matching User Found: %o', { - clientUuid, - }); - - throw new ClientError('[MYPAGE] Finding Matching User Info', 'No Matching User Found'); - } - - ClientLogger.debug('[MYPAGE] Found Key Item: %o', { - clientUuid, - foundKey, - }); - - const { totalPosts, hackerStarredNews } = await this.prisma.getStarredHackerNewsPagination(page, 10, clientUuid); - - const hackerNews = hackerStarredNews.map((item) => item.hacker_news); - - return { - totalPosts, - hackerNews, - }; - } catch (error) { - ClientLogger.error('[MYPAGE] Get My Page Error: %o', { - error, - }); - - throw new ClientError( - '[MYPAGE] Get My Page', - 'Get My Page Error. Please try again.', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } - - async myStarredGeekNews(clientUuid: string, page: number) { - try { - const foundKey = await this.accountManager.getItem(clientUuid); - const resultNewsArray: Array = []; - - if (foundKey === null) { - ClientLogger.debug('[MYPAGE] No Matching User Found: %o', { - clientUuid, - }); - - throw new ClientError('[MYPAGE] Finding Matching User Info', 'No Matching User Found'); - } - - ClientLogger.debug('[MYPAGE] Found Key Item: %o', { - clientUuid, - foundKey, - }); - - const { totalPosts, geekStarredNews } = await this.prisma.getStarredGeekNewsPagination(page, 10, clientUuid); - - for (let i = 0; i <= geekStarredNews.length - 1; i += 1) { - const { post, descLink, uuid, link, founded } = geekStarredNews[i].geek_news; - - const isUrlUndefined = descLink.split('.io/')[1]; - - if (isUrlUndefined === 'undefined') { - ClientLogger.debug('[GEEK] Found Undefiend Desc Card URL: %o', { - title: post, - descUrl: descLink, - uuid, - isUrlUndefined, - }); - - ClientLogger.debug('[GEEK] Put Original Link into return array: %o', { - post, - uuid, - desc: descLink, - originalLink: link, - }); - - resultNewsArray.push({ - post, - uuid, - descLink: link, - founded, - }); - } else { - resultNewsArray.push({ - post, - uuid, - descLink, - founded, - }); - } - } - - return { - totalPosts, - resultNewsArray, - }; - } catch (error) { - ClientLogger.error('[MYPAGE] Get My Page Error: %o', { - error, - }); - - throw new ClientError( - '[MYPAGE] Get My Page', - 'Get My Page Error. Please try again.', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } - - async searchPassword(email: string, name: string) { - try { - // 찾기 - const result = await this.prisma.selectUserInfo(email, name); - - if (result === null) throw new NoUserError('[SEARCH_PASS] Search Password', 'No User Found'); - - const randomKey = randomBytes(8).toString('hex'); - // const { encodedData: encodedPassword, dataToken: passwordToken } = cryptData(randomPassword); - - const mailContent = createSearchPasswordMailcontent(randomKey); - - const { password, password_token: token } = result; - - await this.accountManager.setTempData(randomKey, email, password, token); - - await this.mailer.sendMail(email, 'Search Password', mailContent); - - ClientLogger.debug('[SEARCH_PASS] Sent New Password Complete'); - - return 'Sent'; - } catch (error) { - ClientLogger.error('[SEARCH_PASS] Search Password Error: %o', { - error, - }); - - throw new ClientError( - '[SEARCH_PASS] Search Password', - 'Search Password Error', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } - - async validateSearchingPasswordKey(tempKey: string) { - try { - // 찾기 - const tempItem = await this.accountManager.getTempData(tempKey); - - if (tempItem === null) - throw new NoValidateKeyError('[VALIDATE_KEY] Validate Password Searching Key', 'No Matching Key Found'); - - const { password, token } = tempItem; - - const rawPassword = decrypt(password, token); - - ClientLogger.debug('[VALIDATE_KEY] Validate Password Searching Key Complete'); - - return rawPassword; - } catch (error) { - ClientLogger.error('[VALIDATE_KEY] Validate Password Searching Key Error: %o', { - error, - }); - - throw new ClientError( - '[VALIDATE_KEY] Validate Password Searching Key', - 'Validate Password Searching Key Error', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } - - async searchEmail(name: string) { - try { - const result = await this.prisma.findEmail(name); - - if (result === null) throw new NoUserError('[SEARCH_EMAIL] Find Email', 'No Matching Data Found'); - - const { email } = result; - - ClientLogger.debug('[SEARCH_EMAIL] Finding Email Complete'); - - return email; - } catch (error) { - ClientLogger.error('[SEARCH_EMAIL] Finding Email Error: %o', { - error, - }); - - throw new ClientError( - '[SEARCH_EMAIL] Finding Email', - 'Finding Email Error', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } - async changePassword(encodedEmail: string, password: string, newPassword: string) { try { const loginInfo = await this.accountManager.getItem(encodedEmail); diff --git a/src/providers/client/search.pvd.ts b/src/providers/client/search.pvd.ts new file mode 100644 index 0000000..c124620 --- /dev/null +++ b/src/providers/client/search.pvd.ts @@ -0,0 +1,105 @@ +import { ClientError, NoUserError } from '@errors/client.error'; +import { NoValidateKeyError } from '@errors/password.error'; +import { decrypt } from '@libraries/client/decrypt.lib'; +import { Injectable } from '@nestjs/common'; +import { ClientLogger } from '@utils/logger.util'; +import { createSearchPasswordMailcontent } from '@utils/mail.utils'; +import { randomBytes } from 'crypto'; +import { AccountManager } from 'providers/auth/account-manager.pvd'; +import { MailerProvider } from 'providers/mailer.pvd'; +import { ClientPrismaLibrary } from './client-prisma.pvd'; + +@Injectable() +export class ClientSearchProvider { + constructor( + private readonly prisma: ClientPrismaLibrary, + private readonly accountManager: AccountManager, + private readonly mailer: MailerProvider, + ) {} + + async searchPassword(email: string, name: string) { + try { + // 찾기 + const result = await this.prisma.selectUserInfo(email, name); + + if (result === null) throw new NoUserError('[SEARCH_PASS] Search Password', 'No User Found'); + + const randomKey = randomBytes(8).toString('hex'); + // const { encodedData: encodedPassword, dataToken: passwordToken } = cryptData(randomPassword); + + const mailContent = createSearchPasswordMailcontent(randomKey); + + const { password, password_token: token } = result; + + await this.accountManager.setTempData(randomKey, email, password, token); + + await this.mailer.sendMail(email, 'Search Password', mailContent); + + ClientLogger.debug('[SEARCH_PASS] Sent New Password Complete'); + + return 'Sent'; + } catch (error) { + ClientLogger.error('[SEARCH_PASS] Search Password Error: %o', { + error, + }); + + throw new ClientError( + '[SEARCH_PASS] Search Password', + 'Search Password Error', + error instanceof Error ? error : new Error(JSON.stringify(error)), + ); + } + } + + async validateSearchingPasswordKey(tempKey: string) { + try { + // 찾기 + const tempItem = await this.accountManager.getTempData(tempKey); + + if (tempItem === null) + throw new NoValidateKeyError('[VALIDATE_KEY] Validate Password Searching Key', 'No Matching Key Found'); + + const { password, token } = tempItem; + + const rawPassword = decrypt(password, token); + + ClientLogger.debug('[VALIDATE_KEY] Validate Password Searching Key Complete'); + + return rawPassword; + } catch (error) { + ClientLogger.error('[VALIDATE_KEY] Validate Password Searching Key Error: %o', { + error, + }); + + throw new ClientError( + '[VALIDATE_KEY] Validate Password Searching Key', + 'Validate Password Searching Key Error', + error instanceof Error ? error : new Error(JSON.stringify(error)), + ); + } + } + + async searchEmail(name: string) { + try { + const result = await this.prisma.findEmail(name); + + if (result === null) throw new NoUserError('[SEARCH_EMAIL] Find Email', 'No Matching Data Found'); + + const { email } = result; + + ClientLogger.debug('[SEARCH_EMAIL] Finding Email Complete'); + + return email; + } catch (error) { + ClientLogger.error('[SEARCH_EMAIL] Finding Email Error: %o', { + error, + }); + + throw new ClientError( + '[SEARCH_EMAIL] Finding Email', + 'Finding Email Error', + error instanceof Error ? error : new Error(JSON.stringify(error)), + ); + } + } +} diff --git a/src/providers/client/star.pvd.ts b/src/providers/client/star.pvd.ts new file mode 100644 index 0000000..039727c --- /dev/null +++ b/src/providers/client/star.pvd.ts @@ -0,0 +1,163 @@ +import { ClientError } from '@errors/client.error'; +import { Injectable } from '@nestjs/common'; +import { ClientLogger } from '@utils/logger.util'; +import { AccountManager } from 'providers/auth/account-manager.pvd'; +import { GeekNewsReturn } from 'types/geek.type'; +import { ClientPrismaLibrary } from './client-prisma.pvd'; + +@Injectable() +export class ClientStarProvider { + constructor( + private readonly accountManager: AccountManager, + private readonly prisma: ClientPrismaLibrary, + ) {} + + async myStarredMlNews(clientUuid: string, page: number) { + try { + const foundKey = await this.accountManager.getItem(clientUuid); + + if (foundKey === null) { + ClientLogger.debug('[MYPAGE] No Matching User Found: %o', { + clientUuid, + }); + + throw new ClientError('[MYPAGE] Finding Matching User Info', 'No Matching User Found'); + } + + ClientLogger.debug('[MYPAGE] Found Key Item: %o', { + clientUuid, + foundKey, + }); + + const { totalPosts, mlStarredNews } = await this.prisma.getStarredMlNewsPagination(page, 10, clientUuid); + + const mlNews = mlStarredNews.map((item) => item.ml_news); + + return { + totalPosts, + mlNews, + }; + } catch (error) { + ClientLogger.error('[MYPAGE] Get My Page Error: %o', { + error, + }); + + throw new ClientError( + '[MYPAGE] Get My Page', + 'Get My Page Error. Please try again.', + error instanceof Error ? error : new Error(JSON.stringify(error)), + ); + } + } + + async myStarredHackerNews(clientUuid: string, page: number) { + try { + const foundKey = await this.accountManager.getItem(clientUuid); + + if (foundKey === null) { + ClientLogger.debug('[MYPAGE] No Matching User Found: %o', { + clientUuid, + }); + + throw new ClientError('[MYPAGE] Finding Matching User Info', 'No Matching User Found'); + } + + ClientLogger.debug('[MYPAGE] Found Key Item: %o', { + clientUuid, + foundKey, + }); + + const { totalPosts, hackerStarredNews } = await this.prisma.getStarredHackerNewsPagination(page, 10, clientUuid); + + const hackerNews = hackerStarredNews.map((item) => item.hacker_news); + + return { + totalPosts, + hackerNews, + }; + } catch (error) { + ClientLogger.error('[MYPAGE] Get My Page Error: %o', { + error, + }); + + throw new ClientError( + '[MYPAGE] Get My Page', + 'Get My Page Error. Please try again.', + error instanceof Error ? error : new Error(JSON.stringify(error)), + ); + } + } + + async myStarredGeekNews(clientUuid: string, page: number) { + try { + const foundKey = await this.accountManager.getItem(clientUuid); + const resultNewsArray: Array = []; + + if (foundKey === null) { + ClientLogger.debug('[MYPAGE] No Matching User Found: %o', { + clientUuid, + }); + + throw new ClientError('[MYPAGE] Finding Matching User Info', 'No Matching User Found'); + } + + ClientLogger.debug('[MYPAGE] Found Key Item: %o', { + clientUuid, + foundKey, + }); + + const { totalPosts, geekStarredNews } = await this.prisma.getStarredGeekNewsPagination(page, 10, clientUuid); + + for (let i = 0; i <= geekStarredNews.length - 1; i += 1) { + const { post, descLink, uuid, link, founded } = geekStarredNews[i].geek_news; + + const isUrlUndefined = descLink.split('.io/')[1]; + + if (isUrlUndefined === 'undefined') { + ClientLogger.debug('[GEEK] Found Undefiend Desc Card URL: %o', { + title: post, + descUrl: descLink, + uuid, + isUrlUndefined, + }); + + ClientLogger.debug('[GEEK] Put Original Link into return array: %o', { + post, + uuid, + desc: descLink, + originalLink: link, + }); + + resultNewsArray.push({ + post, + uuid, + descLink: link, + founded, + }); + } else { + resultNewsArray.push({ + post, + uuid, + descLink, + founded, + }); + } + } + + return { + totalPosts, + resultNewsArray, + }; + } catch (error) { + ClientLogger.error('[MYPAGE] Get My Page Error: %o', { + error, + }); + + throw new ClientError( + '[MYPAGE] Get My Page', + 'Get My Page Error. Please try again.', + error instanceof Error ? error : new Error(JSON.stringify(error)), + ); + } + } +} diff --git a/src/providers/news/geek/geek.pvd.ts b/src/providers/news/geek/geek.pvd.ts index 9f31548..68a7748 100644 --- a/src/providers/news/geek/geek.pvd.ts +++ b/src/providers/news/geek/geek.pvd.ts @@ -4,12 +4,12 @@ import { NewsLogger } from '@utils/logger.util'; import { endOfDay, startOfDay } from 'date-fns'; import moment from 'moment-timezone'; import { AccountManager } from 'providers/auth/account-manager.pvd'; -import { HadaNewsReturn } from 'types/geek.type'; +import { GeekNewsReturn } from 'types/geek.type'; import { GeekPrismaLibrary } from './geek-prisma.lib'; @Injectable() export class GeekProvider { - private resultNewsArray: Array; + private resultNewsArray: Array; constructor( private readonly prisma: GeekPrismaLibrary, diff --git a/src/types/geek.type.ts b/src/types/geek.type.ts index 17a54b0..d203416 100644 --- a/src/types/geek.type.ts +++ b/src/types/geek.type.ts @@ -1,4 +1,4 @@ -export interface HadaNewsReturn { +export interface GeekNewsReturn { uuid: string; post: string; descLink: string; @@ -6,7 +6,7 @@ export interface HadaNewsReturn { originalLink?: string; } -export interface DailyHadaNewsReturn { +export interface DailyGeekNewsReturn { uuid: string; post: string; descLink: string; @@ -14,6 +14,6 @@ export interface DailyHadaNewsReturn { liked: number; } -export interface DailyHadaNewsRequest { +export interface DailyGeekNewsRequest { today: string; } diff --git a/src/validators/geek.validator.ts b/src/validators/geek.validator.ts index 318c419..cad0c2a 100644 --- a/src/validators/geek.validator.ts +++ b/src/validators/geek.validator.ts @@ -1,10 +1,10 @@ import { ValidatorError } from '@errors/validator.error'; import { Logger } from '@utils/logger.util'; -import { DailyHadaNewsRequest } from 'types/geek.type'; +import { DailyGeekNewsRequest } from 'types/geek.type'; import { StarRequest } from 'types/request.type'; import { z } from 'zod'; -export const geekNewsValidator = async (request: DailyHadaNewsRequest) => { +export const geekNewsValidator = async (request: DailyGeekNewsRequest) => { try { const scheme = z.object({ today: z.string() }); From 0eae7b317651d0403013a8be7cb3ea2e934106f8 Mon Sep 17 00:00:00 2001 From: donghquinn Date: Thu, 7 Mar 2024 23:26:10 +0900 Subject: [PATCH 3/4] wip: seperate client providers --- src/modules/client/client.module.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/client/client.module.ts b/src/modules/client/client.module.ts index 327f460..18fff33 100644 --- a/src/modules/client/client.module.ts +++ b/src/modules/client/client.module.ts @@ -5,11 +5,12 @@ import { MailerModule } from '@modules/mailer.module'; import { Module } from '@nestjs/common'; import { ClientProvider } from 'providers/client/client.pvd'; import { ClientSearchProvider } from 'providers/client/search.pvd'; +import { ClientStarProvider } from 'providers/client/star.pvd'; import { AccountManagerModule } from './account.module'; import { ClientPrismaModule } from './client-prisma.module'; @Module({ - providers: [ClientProvider, ClientSearchProvider], + providers: [ClientProvider, ClientSearchProvider, ClientStarProvider], imports: [AccountManagerModule, ClientPrismaModule, MailerModule], controllers: [ClientController, ClientSearchController, ClientStarController], }) From 356a901da663670f18328278e72348c7f68c8eed Mon Sep 17 00:00:00 2001 From: donghquinn Date: Thu, 7 Mar 2024 23:27:21 +0900 Subject: [PATCH 4/4] wip: client modules --- src/modules/client/client.module.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/client/client.module.ts b/src/modules/client/client.module.ts index 18fff33..14c6db4 100644 --- a/src/modules/client/client.module.ts +++ b/src/modules/client/client.module.ts @@ -9,9 +9,9 @@ import { ClientStarProvider } from 'providers/client/star.pvd'; import { AccountManagerModule } from './account.module'; import { ClientPrismaModule } from './client-prisma.module'; -@Module({ +@Module( { + controllers: [ClientController, ClientSearchController, ClientStarController], providers: [ClientProvider, ClientSearchProvider, ClientStarProvider], imports: [AccountManagerModule, ClientPrismaModule, MailerModule], - controllers: [ClientController, ClientSearchController, ClientStarController], }) export class ClientModule {}