diff --git a/.yarn/cache/@nestjs-common-npm-10.3.0-56be202040-bedb3437e6.zip b/.yarn/cache/@nestjs-common-npm-10.3.1-de3e4ee620-39b004b2cd.zip similarity index 86% rename from .yarn/cache/@nestjs-common-npm-10.3.0-56be202040-bedb3437e6.zip rename to .yarn/cache/@nestjs-common-npm-10.3.1-de3e4ee620-39b004b2cd.zip index 704f8ad..9deb8a2 100644 Binary files a/.yarn/cache/@nestjs-common-npm-10.3.0-56be202040-bedb3437e6.zip and b/.yarn/cache/@nestjs-common-npm-10.3.1-de3e4ee620-39b004b2cd.zip differ diff --git a/.yarn/cache/@nestjs-core-npm-10.3.0-a7ea43c011-4bdeed0f20.zip b/.yarn/cache/@nestjs-core-npm-10.3.1-60ec0a24f1-397580c200.zip similarity index 91% rename from .yarn/cache/@nestjs-core-npm-10.3.0-a7ea43c011-4bdeed0f20.zip rename to .yarn/cache/@nestjs-core-npm-10.3.1-60ec0a24f1-397580c200.zip index cc22515..abba58e 100644 Binary files a/.yarn/cache/@nestjs-core-npm-10.3.0-a7ea43c011-4bdeed0f20.zip and b/.yarn/cache/@nestjs-core-npm-10.3.1-60ec0a24f1-397580c200.zip differ diff --git a/.yarn/cache/@nestjs-platform-express-npm-10.3.0-f9f204578a-5e802d18f7.zip b/.yarn/cache/@nestjs-platform-express-npm-10.3.1-a128c4678c-cfcffc6ac3.zip similarity index 89% rename from .yarn/cache/@nestjs-platform-express-npm-10.3.0-f9f204578a-5e802d18f7.zip rename to .yarn/cache/@nestjs-platform-express-npm-10.3.1-a128c4678c-cfcffc6ac3.zip index 1209f3d..12a4823 100644 Binary files a/.yarn/cache/@nestjs-platform-express-npm-10.3.0-f9f204578a-5e802d18f7.zip and b/.yarn/cache/@nestjs-platform-express-npm-10.3.1-a128c4678c-cfcffc6ac3.zip differ diff --git a/.yarn/cache/@prisma-client-npm-5.8.1-b5b60f0390-8af50ff949.zip b/.yarn/cache/@prisma-client-npm-5.8.1-b5b60f0390-8af50ff949.zip deleted file mode 100644 index a1b7c9c..0000000 Binary files a/.yarn/cache/@prisma-client-npm-5.8.1-b5b60f0390-8af50ff949.zip and /dev/null differ diff --git a/.yarn/cache/@prisma-client-npm-5.9.1-764ac1601e-2a661cec8f.zip b/.yarn/cache/@prisma-client-npm-5.9.1-764ac1601e-2a661cec8f.zip new file mode 100644 index 0000000..217756d Binary files /dev/null and b/.yarn/cache/@prisma-client-npm-5.9.1-764ac1601e-2a661cec8f.zip differ diff --git a/.yarn/cache/@prisma-debug-npm-5.8.1-19c7438d01-a36c3cb11c.zip b/.yarn/cache/@prisma-debug-npm-5.9.1-5ead12191a-ef9daf19c0.zip similarity index 90% rename from .yarn/cache/@prisma-debug-npm-5.8.1-19c7438d01-a36c3cb11c.zip rename to .yarn/cache/@prisma-debug-npm-5.9.1-5ead12191a-ef9daf19c0.zip index bc7c136..fb9acaf 100644 Binary files a/.yarn/cache/@prisma-debug-npm-5.8.1-19c7438d01-a36c3cb11c.zip and b/.yarn/cache/@prisma-debug-npm-5.9.1-5ead12191a-ef9daf19c0.zip differ diff --git a/.yarn/cache/@prisma-engines-npm-5.8.1-0c5500341e-3edc786fee.zip b/.yarn/cache/@prisma-engines-npm-5.9.1-4d1998d255-383d224741.zip similarity index 91% rename from .yarn/cache/@prisma-engines-npm-5.8.1-0c5500341e-3edc786fee.zip rename to .yarn/cache/@prisma-engines-npm-5.9.1-4d1998d255-383d224741.zip index 714aa47..f40eb02 100644 Binary files a/.yarn/cache/@prisma-engines-npm-5.8.1-0c5500341e-3edc786fee.zip and b/.yarn/cache/@prisma-engines-npm-5.9.1-4d1998d255-383d224741.zip differ diff --git a/.yarn/cache/@prisma-engines-version-npm-5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2-0c53e7214b-cd326d3a0f.zip b/.yarn/cache/@prisma-engines-version-npm-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64-c7d3f36404-7ed88a87f6.zip similarity index 79% rename from .yarn/cache/@prisma-engines-version-npm-5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2-0c53e7214b-cd326d3a0f.zip rename to .yarn/cache/@prisma-engines-version-npm-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64-c7d3f36404-7ed88a87f6.zip index 859470a..10f6e0f 100644 Binary files a/.yarn/cache/@prisma-engines-version-npm-5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2-0c53e7214b-cd326d3a0f.zip and b/.yarn/cache/@prisma-engines-version-npm-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64-c7d3f36404-7ed88a87f6.zip differ diff --git a/.yarn/cache/@prisma-fetch-engine-npm-5.8.1-0aa40119fb-e2845e5528.zip b/.yarn/cache/@prisma-fetch-engine-npm-5.9.1-ecdef657e6-6a48b323b4.zip similarity index 90% rename from .yarn/cache/@prisma-fetch-engine-npm-5.8.1-0aa40119fb-e2845e5528.zip rename to .yarn/cache/@prisma-fetch-engine-npm-5.9.1-ecdef657e6-6a48b323b4.zip index 9a7bab3..0e8684e 100644 Binary files a/.yarn/cache/@prisma-fetch-engine-npm-5.8.1-0aa40119fb-e2845e5528.zip and b/.yarn/cache/@prisma-fetch-engine-npm-5.9.1-ecdef657e6-6a48b323b4.zip differ diff --git a/.yarn/cache/@prisma-get-platform-npm-5.8.1-c5a47f1dea-eb57023cdb.zip b/.yarn/cache/@prisma-get-platform-npm-5.9.1-9b99c820ee-14e2ba7fcb.zip similarity index 96% rename from .yarn/cache/@prisma-get-platform-npm-5.8.1-c5a47f1dea-eb57023cdb.zip rename to .yarn/cache/@prisma-get-platform-npm-5.9.1-9b99c820ee-14e2ba7fcb.zip index 1dad816..c1335b1 100644 Binary files a/.yarn/cache/@prisma-get-platform-npm-5.8.1-c5a47f1dea-eb57023cdb.zip and b/.yarn/cache/@prisma-get-platform-npm-5.9.1-9b99c820ee-14e2ba7fcb.zip differ diff --git a/.yarn/cache/@types-node-npm-20.11.2-767862562e-029d603b56.zip b/.yarn/cache/@types-node-npm-20.11.16-d9bc65d4bc-751f50ec5c.zip similarity index 73% rename from .yarn/cache/@types-node-npm-20.11.2-767862562e-029d603b56.zip rename to .yarn/cache/@types-node-npm-20.11.16-d9bc65d4bc-751f50ec5c.zip index 8671777..08f4d46 100644 Binary files a/.yarn/cache/@types-node-npm-20.11.2-767862562e-029d603b56.zip and b/.yarn/cache/@types-node-npm-20.11.16-d9bc65d4bc-751f50ec5c.zip differ diff --git a/.yarn/cache/prisma-npm-5.8.1-705e7f19a8-66f7b85a4b.zip b/.yarn/cache/prisma-npm-5.8.1-705e7f19a8-66f7b85a4b.zip deleted file mode 100644 index 5ce6ed4..0000000 Binary files a/.yarn/cache/prisma-npm-5.8.1-705e7f19a8-66f7b85a4b.zip and /dev/null differ diff --git a/.yarn/cache/prisma-npm-5.9.1-ab453feee9-4dd4e09493.zip b/.yarn/cache/prisma-npm-5.9.1-ab453feee9-4dd4e09493.zip new file mode 100644 index 0000000..f8f3265 Binary files /dev/null and b/.yarn/cache/prisma-npm-5.9.1-ab453feee9-4dd4e09493.zip differ diff --git a/package-deploy.json b/package-deploy.json index 88997c8..4ada73a 100755 --- a/package-deploy.json +++ b/package-deploy.json @@ -10,12 +10,12 @@ "schema": "prisma generate" }, "dependencies": { - "@nestjs/common": "^10.3.0", - "@nestjs/core": "^10.3.0", + "@nestjs/common": "^10.3.1", + "@nestjs/core": "^10.3.1", "@nestjs/jwt": "^10.2.0", "@nestjs/passport": "^10.0.3", - "@nestjs/platform-express": "^10.3.0", - "@prisma/client": "^5.8.1", + "@nestjs/platform-express": "^10.3.1", + "@prisma/client": "^5.9.1", "cookie-parser": "^1.4.6", "date-fns": "^2.30.0", "express": "^4.18.2", @@ -24,7 +24,7 @@ "node-fetch": "^3.3.2", "passport": "^0.7.0", "passport-jwt": "^4.0.1", - "prisma": "^5.8.1", + "prisma": "^5.9.1", "reflect-metadata": "^0.2.1", "rxjs": "^7.8.1", "winston": "^3.11.0", @@ -34,7 +34,7 @@ "devDependencies": { "@types/cookie-parser": "^1", "@types/express": "^4.17.21", - "@types/node": "^20.11.2", + "@types/node": "^20.11.16", "@types/passport": "^0", "@types/passport-jwt": "^4", "@typescript-eslint/eslint-plugin": "^6.19.0", diff --git a/package.json b/package.json index b74218f..9dffb6a 100755 --- a/package.json +++ b/package.json @@ -15,12 +15,12 @@ "db:update": "prisma db push" }, "dependencies": { - "@nestjs/common": "^10.3.0", - "@nestjs/core": "^10.3.0", + "@nestjs/common": "^10.3.1", + "@nestjs/core": "^10.3.1", "@nestjs/jwt": "^10.2.0", "@nestjs/passport": "^10.0.3", - "@nestjs/platform-express": "^10.3.0", - "@prisma/client": "^5.8.1", + "@nestjs/platform-express": "^10.3.1", + "@prisma/client": "^5.9.1", "cookie-parser": "^1.4.6", "date-fns": "^2.30.0", "express": "^4.18.2", @@ -29,7 +29,7 @@ "node-fetch": "^3.3.2", "passport": "^0.7.0", "passport-jwt": "^4.0.1", - "prisma": "^5.8.1", + "prisma": "^5.9.1", "reflect-metadata": "^0.2.1", "rxjs": "^7.8.1", "winston": "^3.11.0", @@ -39,7 +39,7 @@ "devDependencies": { "@types/cookie-parser": "^1", "@types/express": "^4.17.21", - "@types/node": "^20.11.2", + "@types/node": "^20.11.16", "@types/passport": "^0", "@types/passport-jwt": "^4", "@typescript-eslint/eslint-plugin": "^6.19.0", diff --git a/src/controllers/geek/geek.ctl.ts b/src/controllers/geek/geek.ctl.ts index b8bd1d3..b1b3eb8 100755 --- a/src/controllers/geek/geek.ctl.ts +++ b/src/controllers/geek/geek.ctl.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Post, Query } from '@nestjs/common'; +import { Body, Controller, Get, Headers, Post, Query } from '@nestjs/common'; import { hadaNewsStarValidator, hadaNewsValidator } from '@validators/hada.validator'; import { SetErrorResponse, SetResponse } from 'dto/response.dto'; import { GeekProvider } from 'providers/news/geek/geek.pvd'; @@ -23,11 +23,11 @@ export class GeekController { } @Post('/star') - async giveStarNews(@Body() request: StarRequest) { + async giveStarNews(@Body() request: StarRequest, @Headers('Authorization') clientUuid: string) { try { - const { uuid } = await hadaNewsStarValidator(request); + const { uuid: postUuid } = await hadaNewsStarValidator(request); - const result = await this.geek.giveStar(uuid); + const result = await this.geek.giveStar(postUuid, clientUuid); return new SetResponse(200, { result }); } catch (error) { diff --git a/src/controllers/hacker/hacker.ctl.ts b/src/controllers/hacker/hacker.ctl.ts index 10fe3bc..b272d51 100755 --- a/src/controllers/hacker/hacker.ctl.ts +++ b/src/controllers/hacker/hacker.ctl.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Post, Query } from '@nestjs/common'; +import { Body, Controller, Get, Post, Headers, Query } from '@nestjs/common'; import { hackerNewsStarValidator, hackerNewsValidator } from '@validators/hacker.validator'; import { SetErrorResponse, SetResponse } from 'dto/response.dto'; import { HackersNewsProvider } from 'providers/news/hacker/hacker.pvd'; @@ -34,11 +34,11 @@ export class HackerController { } @Post('/star') - async giveStarNews(@Body() request: StarRequest) { + async giveStarNews(@Body() request: StarRequest, @Headers('Authorization') clientUuid: string) { try { - const { uuid } = await hackerNewsStarValidator(request); + const { uuid: PostUuid } = await hackerNewsStarValidator(request); - const result = await this.hacker.giveStar(uuid); + const result = await this.hacker.giveStar(PostUuid, clientUuid); return new SetResponse(200, { result }); } catch (error) { diff --git a/src/controllers/machine/machine.ctl.ts b/src/controllers/machine/machine.ctl.ts index 5f67084..a78030b 100644 --- a/src/controllers/machine/machine.ctl.ts +++ b/src/controllers/machine/machine.ctl.ts @@ -1,5 +1,5 @@ import { MachineLearningProvider } from 'providers/news/ml/machine.pvd'; -import { Body, Controller, Get, Post, Query } from '@nestjs/common'; +import { Body, Controller, Get, Post, Headers, Query } from '@nestjs/common'; import { machineLearningValidator, mlNewsStarValidator } from '@validators/ml.validator'; import { SetErrorResponse, SetResponse } from 'dto/response.dto'; import { StarRequest } from 'types/request.type'; @@ -23,11 +23,11 @@ export class MachineLearningController { } @Post('/star') - async giveStarNews(@Body() request: StarRequest) { + async giveStarNews(@Body() request: StarRequest, @Headers('Authorization') clientUuid: string) { try { - const { uuid } = await mlNewsStarValidator(request); + const { uuid: postUuid } = await mlNewsStarValidator(request); - const result = await this.mlNews.giveStar(uuid); + const result = await this.mlNews.giveStar(postUuid, clientUuid); return new SetResponse(200, { result }); } catch (error) { diff --git a/src/errors/manager.error.ts b/src/errors/manager.error.ts index cb15ec9..45b2e1e 100755 --- a/src/errors/manager.error.ts +++ b/src/errors/manager.error.ts @@ -1,4 +1,4 @@ -export class StarError extends Error { +export class AccountError extends Error { type: string; constructor(type: string, message: string, cause?: Error) { @@ -6,7 +6,7 @@ export class StarError extends Error { this.type = type; - this.name = '[Star Error]'; + this.name = '[Account Error]'; this.cause = cause; } diff --git a/src/modules/client/account.module.ts b/src/modules/client/account.module.ts index aa4e625..e3b15b9 100644 --- a/src/modules/client/account.module.ts +++ b/src/modules/client/account.module.ts @@ -1,5 +1,5 @@ import { Module } from '@nestjs/common'; -import { AccountManager } from 'providers/client/account-manager.pvd'; +import { AccountManager } from 'providers/auth/account-manager.pvd'; @Module({ providers: [AccountManager], diff --git a/src/modules/geek/geek.module.ts b/src/modules/geek/geek.module.ts index 61ae80a..46452e4 100755 --- a/src/modules/geek/geek.module.ts +++ b/src/modules/geek/geek.module.ts @@ -1,11 +1,12 @@ import { GeekController } from '@controllers/geek/geek.ctl'; +import { AccountManagerModule } from '@modules/client/account.module'; import { Module } from '@nestjs/common'; import { GeekProvider } from 'providers/news/geek/geek.pvd'; import { GeekPrismaModule } from './geek-prisma.module'; @Module({ controllers: [GeekController], - imports: [GeekPrismaModule], + imports: [GeekPrismaModule, AccountManagerModule], providers: [GeekProvider], }) export class GeekModule {} diff --git a/src/modules/hacker/hacker.module.ts b/src/modules/hacker/hacker.module.ts index 2752eda..f1eaa1e 100755 --- a/src/modules/hacker/hacker.module.ts +++ b/src/modules/hacker/hacker.module.ts @@ -1,11 +1,12 @@ import { HackerController } from '@controllers/hacker/hacker.ctl'; +import { AccountManagerModule } from '@modules/client/account.module'; import { Module } from '@nestjs/common'; import { HackersNewsProvider } from 'providers/news/hacker/hacker.pvd'; import { HackerPrismaModule } from './hacker-prisma.module'; @Module({ controllers: [HackerController], - imports: [HackerPrismaModule], + imports: [HackerPrismaModule, AccountManagerModule], providers: [HackersNewsProvider], }) export class HackerModule {} diff --git a/src/modules/ml/machine.module.ts b/src/modules/ml/machine.module.ts index cf6f03f..acfb54b 100644 --- a/src/modules/ml/machine.module.ts +++ b/src/modules/ml/machine.module.ts @@ -1,11 +1,12 @@ import { MachineLearningController } from '@controllers/machine/machine.ctl'; +import { AccountManagerModule } from '@modules/client/account.module'; import { Module } from '@nestjs/common'; import { MachineLearningProvider } from 'providers/news/ml/machine.pvd'; import { MlPrismaModule } from './ml-prisma.module'; @Module({ controllers: [MachineLearningController], - imports: [MlPrismaModule], + imports: [MlPrismaModule, AccountManagerModule], providers: [MachineLearningProvider], }) export class MachineLearningNewsModule {} diff --git a/src/providers/auth/account-manager.pvd.ts b/src/providers/auth/account-manager.pvd.ts new file mode 100644 index 0000000..67915eb --- /dev/null +++ b/src/providers/auth/account-manager.pvd.ts @@ -0,0 +1,157 @@ +import { Injectable } from '@nestjs/common'; +import { ClientLogger, ManagerLogger } from '@utils/logger.util'; +import { ClientLoginMapItem, ClientLoginMapKey } from 'types/client.type'; + +@Injectable() +export class AccountManager { + private userMap: WeakMap; + + private userKeys: Array; + + constructor() { + this.userKeys = []; + this.userMap = new WeakMap(); + } + + public setLoginUser(clientUuid: string, email: string, password?: string) { + const isLogined = this.getItem(clientUuid); + + ManagerLogger.debug('[ACCOUNT] Searching User Info: %o', { + isLogined, + map: this.userMap, + clientUuid, + }); + + if (!isLogined) { + const clientKey = { uuid: clientUuid }; + + this.userKeys.push(clientKey); + this.setItem(email, clientKey, password); + + if (this.userKeys.length >= 5000) { + ClientLogger.debug('[AccountManager] keyList maximum reached. shift()'); + this.userKeys.shift(); + } + + ClientLogger.info('[ACCOUNT] Set Finished'); + + return clientUuid; + } + + ManagerLogger.debug('[ACCOUNT] Found User Key: %o', { + clientUuid, + map: this.userMap, + }); + + const interval = 1000 * 60 * 10; + + const timer = setInterval(() => { + const isExsit = this.getItem(clientUuid); + + if (!isExsit) { + ManagerLogger.info('[ACCOUNT] It is not existing user. Clear Interval.'); + + ManagerLogger.debug('[ACCOUNT] Client Map Inspection: %o', { + isExsit, + clientUuid, + map: this.userMap, + }); + + clearInterval(timer); + } else { + ManagerLogger.info('[ACCOUNT] Expiration time. Delete user.'); + + ManagerLogger.debug('[ACCOUNT] Client Map Inspection: %o', { + clientUuid, + map: this.userMap, + }); + + this.deleteItem(clientUuid); + } + }, interval); + + return clientUuid; + } + + public deleteLogoutUser(clientUuid: string) { + ManagerLogger.debug('[ACCOUNT] Client Data: %o', { + clientUuid, + map: this.userMap, + }); + + const isExist = this.getItem(clientUuid); + + if (!isExist) { + ManagerLogger.info('[ACCOUNT] Not Matchin Data found. Ignore.'); + + return false; + } + + this.deleteItem(clientUuid); + + ManagerLogger.debug('[ACCOUNT] Client Map Delete Inspection: %o', { + clientUuid, + map: this.userMap, + }); + + return true; + } + + public deleteItem(clientUuid: string) { + const index = this.userKeys.findIndex((item) => item.uuid === clientUuid); + + if (index > -1) this.userKeys.splice(index, 1); + + ClientLogger.debug('[ACCOUNT] Delete Finished: %o', { + clientUuid, + index, + keyList: this.userKeys, + map: this.userMap, + }); + } + + public setItem(email: string, clientKey: ClientLoginMapKey, password?: string) { + return this.userMap.set(clientKey, { email, password }); + } + + public getItem(clientUuid: string) { + const key = this.userKeys.find((item) => item.uuid === clientUuid); + + if (!key) return null; + + return this.userMap.get(key) as ClientLoginMapItem; + } + + // public stop() { + // if (this.isListening) { + // this.isListening = false; + + // // Account lock 이 전부 풀릴 때까지 대기 + // for (;;) { + // // 등록된 주소와 mutex 조회 + // const items = this.keyList + // .map((item) => ({ address: item.address, ...this.getItem(item.address) })) + // .filter((item) => item.mutex !== null); + + // // 등록된 주소가 없을 경우 안전하게 끝낼 수 있음 + // if (!items.length) break; + + // // 그렇지 않을 경우 락 여부를 확인해야 함 + // for (let i = 0; i < items.length; i += 1) { + // const item = items[i]; + + // if (item?.mutex?.isLocked()) { + // Logger.info('[AccountManager] Waiting for address in use(locked): %o', item.address); + + // // 1초 대기 + // // SIGTERM 핸들러는 비동기 코드 resolve 가 되지 않으므로 then() 으로 기다림 + // setTimeout(1000).then(() => + // Logger.info ('[AccountManager] Waited 1 second for address: %o', item.address )); + // } + // } + // } + + // TxLogger.info('[AccountManager] Address lock cleared, safe to shutdown.'); + // } + // } +} diff --git a/src/providers/auth/jwt.pvd.ts b/src/providers/auth/jwt.pvd.ts index 872f823..a4e370c 100644 --- a/src/providers/auth/jwt.pvd.ts +++ b/src/providers/auth/jwt.pvd.ts @@ -1,55 +1,73 @@ -import { AuthError } from '@errors/auth.error'; -import { Injectable, Logger } from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { Response } from 'express'; - -@Injectable() -export class JwtProvider { - constructor(private readonly jwt: JwtService) {} - - async getAccessToken(email: string, userUuid: string): Promise { - try { - return await this.jwt.signAsync( - { email, userUuid }, - { secret: process.env.JWT_ACCESS_TOKEN_SECRET, expiresIn: '5m' }, - ); - } catch (error) { - Logger.error('[JWT] Issue Access Token Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), - }); - - throw new AuthError( - '[JWT] Issue Access Token', - 'Issue Access Token Error. Please Try Again.', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } - - async setRefreshToken(email: string, userUuid: string, response: Response) { - try { - const refreshToken = await this.jwt.signAsync( - { - email, - userUuid, - }, - { - secret: process.env.JWT_REFRESH_TOKEN_SECRET, - expiresIn: '2w', - }, - ); - - response.setHeader('Set-Cookie', `refreshToken=${refreshToken}`); - } catch (error) { - Logger.error('[JWT] Issue Refresh Token Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), - }); - - throw new AuthError( - '[JWT] Issue Refresh Token', - 'Issue Refresh Token Error. Please Try Again.', - error instanceof Error ? error : new Error(JSON.stringify(error)), - ); - } - } -} +// import { AuthError } from '@errors/auth.error'; +// import { Injectable, Logger, UnauthorizedException } from '@nestjs/common'; +// import { JwtService } from '@nestjs/jwt'; +// import { Response } from 'express'; +// import { AccountManager } from './account-manager.pvd'; + +// @Injectable() +// export class JwtProvider { +// constructor( +// private readonly jwt: JwtService, +// private readonly account: AccountManager, +// ) {} + +// async getAccessToken(email: string, userUuid: string): Promise { +// try { +// return await this.jwt.signAsync( +// { email, userUuid }, +// { secret: process.env.JWT_ACCESS_TOKEN_SECRET, expiresIn: '5m' }, +// ); +// } catch (error) { +// Logger.error('[JWT] Issue Access Token Error: %o', { +// error: error instanceof Error ? error : new Error(JSON.stringify(error)), +// }); + +// throw new AuthError( +// '[JWT] Issue Access Token', +// 'Issue Access Token Error. Please Try Again.', +// error instanceof Error ? error : new Error(JSON.stringify(error)), +// ); +// } +// } + +// async signIn(email: string, pass: string): Promise<{ access_token: string }> { +// const userInfo = this.account.getItem(email); + +// if (!userInfo) throw new UnauthorizedException(); + +// if (userInfo.password !== pass) { +// throw new UnauthorizedException(); +// } +// const payload = { uuid: userInfo.uuid, email }; +// return { +// access_token: await this.jwt.signAsync(payload), +// }; +// } + +// async setRefreshToken(email: string, userUuid: string, response: Response) { +// try { +// const refreshToken = await this.jwt.signAsync( +// { +// email, +// userUuid, +// }, +// { +// secret: process.env.JWT_REFRESH_TOKEN_SECRET, +// expiresIn: '2w', +// }, +// ); + +// response.setHeader('Set-Cookie', `refreshToken=${refreshToken}`); +// } catch (error) { +// Logger.error('[JWT] Issue Refresh Token Error: %o', { +// error: error instanceof Error ? error : new Error(JSON.stringify(error)), +// }); + +// throw new AuthError( +// '[JWT] Issue Refresh Token', +// 'Issue Refresh Token Error. Please Try Again.', +// error instanceof Error ? error : new Error(JSON.stringify(error)), +// ); +// } +// } +// } diff --git a/src/providers/client/account-manager.pvd.ts b/src/providers/client/account-manager.pvd.ts deleted file mode 100644 index 549e89d..0000000 --- a/src/providers/client/account-manager.pvd.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ManagerLogger } from '@utils/logger.util'; -import { ClientLoginMapItem, ClientLoginMapKey } from 'types/client.type'; - -@Injectable() -export class AccountManager { - private userMap: WeakMap; - - constructor() { - this.userMap = new WeakMap(); - } - - public setLoginUser(uuid: string, email: string) { - const isLogined = this.searchItem(uuid); - - if (isLogined) { - ManagerLogger.info('[ACCOUNT] Found Already Logined User Info. Ignore'); - - return; - } - - this.setItem(uuid, email); - - const interval = 1000 * 60 * 10; - - const timer = setInterval(() => { - const isExsit = this.searchItem(uuid); - - if (!isExsit) { - ManagerLogger.info('[ACCOUNT] It is not existing user. Clear Interval.'); - - clearInterval(timer); - } else { - ManagerLogger.info('[ACCOUNT] Expiration time. Delete user.'); - this.deleteItem(uuid); - } - }, interval); - } - - public searchItem(uuid: string) { - const isExist = this.userMap.has({ uuid }); - - ManagerLogger.info('[ACCOUNT] Found Existing user info'); - - return isExist; - } - - public deleteItem(uuid: string) { - const isExist = this.searchItem(uuid); - - if (!isExist) { - ManagerLogger.info('[ACCOUNT] Not Matchin Data found. Ignore.'); - - return; - } - - ManagerLogger.info('[ACCOUNT] Found Existing user info. Delete it'); - this.userMap.delete({ uuid }); - } - - public setItem(uuid: string, email: string) { - this.userMap.set({ uuid }, { email }); - } - - // public stop() { - // if (this.isListening) { - // this.isListening = false; - - // // Account lock 이 전부 풀릴 때까지 대기 - // for (;;) { - // // 등록된 주소와 mutex 조회 - // const items = this.keyList - // .map((item) => ({ address: item.address, ...this.getItem(item.address) })) - // .filter((item) => item.mutex !== null); - - // // 등록된 주소가 없을 경우 안전하게 끝낼 수 있음 - // if (!items.length) break; - - // // 그렇지 않을 경우 락 여부를 확인해야 함 - // for (let i = 0; i < items.length; i += 1) { - // const item = items[i]; - - // if (item?.mutex?.isLocked()) { - // Logger.info('[AccountManager] Waiting for address in use(locked): %o', item.address); - - // // 1초 대기 - // // SIGTERM 핸들러는 비동기 코드 resolve 가 되지 않으므로 then() 으로 기다림 - // setTimeout(1000).then(() => - // Logger.info ('[AccountManager] Waited 1 second for address: %o', item.address )); - // } - // } - // } - - // TxLogger.info('[AccountManager] Address lock cleared, safe to shutdown.'); - // } - // } -} diff --git a/src/providers/client/client-prisma.pvd.ts b/src/providers/client/client-prisma.pvd.ts index 72100c8..c97a1ae 100644 --- a/src/providers/client/client-prisma.pvd.ts +++ b/src/providers/client/client-prisma.pvd.ts @@ -48,7 +48,7 @@ export class ClientPrismaLibrary extends PrismaClient { return uuid; } catch (error) { ClientLogger.error('[Signup] Check is existing email: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new ClientError( @@ -59,7 +59,7 @@ export class ClientPrismaLibrary extends PrismaClient { } } - async selectUserInfoByMail(email: string, isLogined: number) { + async selectUserInfoByMail(email: string) { try { const userInfo = await this.client.findFirst({ select: { @@ -69,13 +69,13 @@ export class ClientPrismaLibrary extends PrismaClient { }, where: { email, - is_logined: isLogined, }, }); + return userInfo; } catch (error) { ClientLogger.error('[Signup] Check is existing email: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new ClientError( @@ -114,7 +114,7 @@ export class ClientPrismaLibrary extends PrismaClient { async updateClientLoginStatus(clientUuid: string, isLogined: number) { try { - const userInfo = await this.client.update({ + await this.client.update({ data: { is_logined: isLogined, }, @@ -122,7 +122,6 @@ export class ClientPrismaLibrary extends PrismaClient { uuid: clientUuid, }, }); - return userInfo; } catch (error) { ClientLogger.error('[STATUS] User Status Update: %o', { error, @@ -196,7 +195,7 @@ export class ClientPrismaLibrary extends PrismaClient { skip: (page - 1) * size, }); - ClientLogger.info('[STARRED] Founded Starred News: %o', { + ClientLogger.debug('[STARRED] Founded Starred News: %o', { totalPosts, hackerNewsSize: hackerStarredNews.length, geekNewsSize: geekStarredNews.length, diff --git a/src/providers/client/client.pvd.ts b/src/providers/client/client.pvd.ts index 8c726e2..95b217f 100644 --- a/src/providers/client/client.pvd.ts +++ b/src/providers/client/client.pvd.ts @@ -3,7 +3,7 @@ import { comparePassword } from '@libraries/client/decrypt.lib'; import { cryptPassword } from '@libraries/client/encrypt.lib'; import { Injectable } from '@nestjs/common'; import { ClientLogger } from '@utils/logger.util'; -import { AccountManager } from './account-manager.pvd'; +import { AccountManager } from '../auth/account-manager.pvd'; import { ClientPrismaLibrary } from './client-prisma.pvd'; @Injectable() @@ -32,7 +32,7 @@ export class ClientProvider { return uuid; } catch (error) { ClientLogger.error('[Signup] Singup New User Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new ClientError( @@ -45,10 +45,10 @@ export class ClientProvider { async login(email: string, password: string) { try { - const userInfo = await this.prisma.selectUserInfoByMail(email, 0); + const userInfo = await this.prisma.selectUserInfoByMail(email); if (userInfo === null) { - ClientLogger.info('[LOGIN] No Matching User Found: %o', { + ClientLogger.debug('[LOGIN] No Matching User Found: %o', { email, }); @@ -65,7 +65,7 @@ export class ClientProvider { throw new ClientError('[LOGIN] Password Matching ', ' Password Matching is Not Match. Reject.'); } - this.accountManager.setLoginUser(uuid, email); + this.accountManager.setLoginUser(uuid, email, foundPassword); await this.prisma.updateClientLoginStatus(uuid, 1); @@ -85,7 +85,7 @@ export class ClientProvider { async logout(clientUuid: string) { try { - const foundKey = this.accountManager.searchItem(clientUuid); + const foundKey = this.accountManager.getItem(clientUuid); if (foundKey === null) { ClientLogger.debug('[LOGIN] No Matching User Found: %o', { @@ -95,14 +95,11 @@ export class ClientProvider { throw new ClientError('[LOGIN] Finding Matching User Info', 'No Matching User Found'); } - ClientLogger.debug('[LOGOUT] Found Key Item: %o', { - clientUuid, - foundKey, - }); - await this.prisma.updateClientLoginStatus(clientUuid, 0); - this.accountManager.deleteItem(clientUuid); + const deleteItem = this.accountManager.deleteLogoutUser(clientUuid); + + if (!deleteItem) throw new ClientError('[LOGOUT] Logout', 'No Data Found. Ignore.'); return 'Logout Success'; } catch (error) { @@ -111,8 +108,8 @@ export class ClientProvider { }); throw new ClientError( - '[LOGIN] Login', - 'Login Error. Please try again.', + '[LOGIN] Logout', + 'Logout Error. Please try again.', error instanceof Error ? error : new Error(JSON.stringify(error)), ); } @@ -120,17 +117,17 @@ export class ClientProvider { async myPage(clientUuid: string, page: number) { try { - const foundKey = this.accountManager.searchItem(clientUuid); + const foundKey = this.accountManager.getItem(clientUuid); if (foundKey === null) { - ClientLogger.debug('[LOGIN] No Matching User Found: %o', { + ClientLogger.debug('[MYPAGE] No Matching User Found: %o', { clientUuid, }); - throw new ClientError('[LOGIN] Finding Matching User Info', 'No Matching User Found'); + throw new ClientError('[MYPAGE] Finding Matching User Info', 'No Matching User Found'); } - ClientLogger.debug('[LOGOUT] Found Key Item: %o', { + ClientLogger.debug('[MYPAGE] Found Key Item: %o', { clientUuid, foundKey, }); @@ -145,13 +142,13 @@ export class ClientProvider { mlStarredNews, }; } catch (error) { - ClientLogger.error('[LOGIN] Login Error: %o', { + ClientLogger.error('[MYPAGE] Get My Page Error: %o', { error, }); throw new ClientError( - '[LOGIN] Login', - 'Login Error. Please try again.', + '[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-prisma.lib.ts b/src/providers/news/geek/geek-prisma.lib.ts index 9ad3277..aa4968e 100644 --- a/src/providers/news/geek/geek-prisma.lib.ts +++ b/src/providers/news/geek/geek-prisma.lib.ts @@ -22,7 +22,7 @@ export class GeekPrismaLibrary extends PrismaClient { return result; } catch (error) { NewsLogger.error('[HADA] Bring Geek News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new PrismaError( @@ -33,27 +33,33 @@ export class GeekPrismaLibrary extends PrismaClient { } } - async checkHadaNewsIsLiked(uuid: string) { + async checkHadaNewsIsLiked(postUuid: string, clientUuid: string) { try { - const isStarred = await this.geek.findFirst({ + const isStarred = await this.geek_Liked.findFirst({ select: { - liked: true, + uuid: true, + geek_news: { + select: { + liked: true, + }, + }, }, where: { - uuid, + userUuid: clientUuid, + postUuid, }, }); if (isStarred === null) throw new HadaError('[Hada] Get Star Info', 'No Star Info Found.'); - NewsLogger.info('[Hada] Found Is Starred Info: %o', { - isLiked: isStarred?.liked, + NewsLogger.debug('[Hada] Found Is Starred Info: %o', { + isLiked: isStarred.geek_news.liked, }); - return isStarred.liked; + return { uuid: isStarred.uuid, liked: isStarred.geek_news.liked }; } catch (error) { NewsLogger.error('[Hada] Check Hada News Liked Info Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new HadaError( @@ -64,18 +70,26 @@ export class GeekPrismaLibrary extends PrismaClient { } } - async updateHadaNewsLikedtoUnliked(uuid: string) { + async updateHadaNewsLikedtoUnliked(likedUuid: string, postUuid: string, clientUuid: string) { try { - NewsLogger.info('[HADA] Give Hada News unStar Request: %o', { - uuid, + NewsLogger.debug('[HADA] Give Hada News unStar Request: %o', { + likedUuid, + postUuid, + clientUuid, }); - await this.geek.update({ + await this.geek_Liked.update({ data: { - liked: 0, + geek_news: { + update: { + liked: 0, + }, + }, }, where: { - uuid, + uuid: likedUuid, + postUuid, + userUuid: clientUuid, }, }); @@ -84,7 +98,7 @@ export class GeekPrismaLibrary extends PrismaClient { return 0; } catch (error) { NewsLogger.error('[Hada] Update Liked to UnLiked Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new HadaError( @@ -95,18 +109,26 @@ export class GeekPrismaLibrary extends PrismaClient { } } - async updateHadaNewsLiked(uuid: string) { + async updateHadaNewsLiked(likedUuid: string, postUuid: string, clientUuid: string) { try { - NewsLogger.info('[HADA] Give Hacker News Star Request: %o', { - uuid, + NewsLogger.debug('[HADA] Give Hacker News Star Request: %o', { + likedUuid, + postUuid, + clientUuid, }); - await this.geek.update({ + await this.geek_Liked.update({ data: { - liked: 1, + geek_news: { + update: { + liked: 1, + }, + }, }, where: { - uuid, + uuid: likedUuid, + postUuid, + userUuid: clientUuid, }, }); @@ -115,7 +137,7 @@ export class GeekPrismaLibrary extends PrismaClient { return 0; } catch (error) { NewsLogger.error('[Hada] Update News Liked Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new HadaError( @@ -147,7 +169,7 @@ export class GeekPrismaLibrary extends PrismaClient { skip: (page - 1) * size, }); - NewsLogger.info('[Hada] Founded Starred News: %o', { + NewsLogger.debug('[Hada] Founded Starred News: %o', { totalPosts, newsSize: starredNews.length, }); @@ -158,7 +180,7 @@ export class GeekPrismaLibrary extends PrismaClient { }; } catch (error) { NewsLogger.info('[Hada] Get Starred News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new HadaError( diff --git a/src/providers/news/geek/geek.pvd.ts b/src/providers/news/geek/geek.pvd.ts index db9fac2..6cd8724 100644 --- a/src/providers/news/geek/geek.pvd.ts +++ b/src/providers/news/geek/geek.pvd.ts @@ -3,6 +3,7 @@ import { Injectable } from '@nestjs/common'; 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 { GeekPrismaLibrary } from './geek-prisma.lib'; @@ -10,7 +11,10 @@ import { GeekPrismaLibrary } from './geek-prisma.lib'; export class GeekProvider { private resultNewsArray: Array; - constructor(private readonly prisma: GeekPrismaLibrary) { + constructor( + private readonly prisma: GeekPrismaLibrary, + private readonly account: AccountManager, + ) { this.resultNewsArray = []; } @@ -32,7 +36,7 @@ export class GeekProvider { const isUrlUndefined = result[i].descLink.split('.io/')[1]; if (isUrlUndefined === 'undefined') { - NewsLogger.info('[GEEK] Found Undefiend Desc Card URL: %o', { + NewsLogger.debug('[GEEK] Found Undefiend Desc Card URL: %o', { title: result[i].post, descUrl: result[i].descLink, uuid: result[i].uuid, @@ -65,7 +69,7 @@ export class GeekProvider { return result; } catch (error) { NewsLogger.error('[GEEK] Bring Hada News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new HadaError( @@ -76,22 +80,26 @@ export class GeekProvider { } } - async giveStar(uuid: string) { + async giveStar(postUuid: string, clientUuid: string) { try { - const isLiked = await this.prisma.checkHadaNewsIsLiked(uuid); + const isLogined = this.account.getItem(clientUuid); - if (isLiked) { - await this.prisma.updateHadaNewsLikedtoUnliked(uuid); + if (!isLogined) throw new HadaError('[GEEK] Give Star on the Stars', 'No Logined User Found.'); + + const { uuid: likedUuid, liked } = await this.prisma.checkHadaNewsIsLiked(postUuid, clientUuid); + + if (liked) { + await this.prisma.updateHadaNewsLikedtoUnliked(likedUuid, postUuid, clientUuid); } - if (!isLiked) { - await this.prisma.updateHadaNewsLiked(uuid); + if (!liked) { + await this.prisma.updateHadaNewsLiked(likedUuid, postUuid, clientUuid); } return true; } catch (error) { NewsLogger.error('[GEEK] Star Update Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new HadaError( @@ -116,7 +124,7 @@ export class GeekProvider { return starredNews; } catch (error) { NewsLogger.error('[GEEK] Get Starred Update Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new HadaError( diff --git a/src/providers/news/hacker/hacker-prisma.lib.ts b/src/providers/news/hacker/hacker-prisma.lib.ts index 307b0bf..0fcdec9 100644 --- a/src/providers/news/hacker/hacker-prisma.lib.ts +++ b/src/providers/news/hacker/hacker-prisma.lib.ts @@ -33,24 +33,30 @@ export class HackerPrismaLibrary extends PrismaClient { } } - async checkHackerNewsIsLiked(uuid: string) { + async checkHackerNewsIsLiked(postUuid: string, clientUuid: string) { try { - const isStarred = await this.hackers.findFirst({ + const isStarred = await this.hacker_Liked.findFirst({ select: { - liked: true, + uuid: true, + hacker_news: { + select: { + liked: true, + }, + }, }, where: { - uuid, + userUuid: clientUuid, + postUuid, }, }); if (isStarred === null) throw new HackerError('[Hacker] Get Star Info', 'No Star Info Found.'); - NewsLogger.info('[Hacker] Found Is Starred Info: %o', { - isLiked: isStarred?.liked, + NewsLogger.debug('[Hacker] Found Is Starred Info: %o', { + isLiked: isStarred.hacker_news.liked, }); - return isStarred.liked; + return { uuid: isStarred.uuid, isLiked: isStarred.hacker_news.liked }; } catch (error) { NewsLogger.error('[Hacker] Check Hada News Liked Info Error: %o', { error, @@ -64,24 +70,29 @@ export class HackerPrismaLibrary extends PrismaClient { } } - async updateHackerNewsLikedtoUnliked(uuid: string) { + async updateHackerNewsLikedtoUnliked(likedUuid: string, postUuid: string, clientUuid: string): Promise { try { - NewsLogger.info('[Hacker] Give Hada News unStar Request: %o', { - uuid, + NewsLogger.debug('[Hacker] Give Hada News unStar Request: %o', { + likedUuid, + postUuid, + clientUuid, }); - await this.hackers.update({ + await this.hacker_Liked.update({ data: { - liked: 0, + hacker_news: { + update: { + liked: 0, + }, + }, }, where: { - uuid, + uuid: likedUuid, + postUuid, + userUuid: clientUuid, }, }); - NewsLogger.info('[Hacker] Unstarred Updated'); - - return 0; } catch (error) { NewsLogger.error('[Hacker] Update Liked to UnLiked Error: %o', { error, @@ -95,24 +106,30 @@ export class HackerPrismaLibrary extends PrismaClient { } } - async updateHackerNewsLiked(uuid: string) { + async updateHackerNewsLiked(likedUuid: string, postUuid: string, clientUuid: string): Promise { try { - NewsLogger.info('[Hacker] Give Hacker News Star Request: %o', { - uuid, + NewsLogger.debug('[Hacker] Give Hacker News Star Request: %o', { + likedUuid, + postUuid, + clientUuid, }); - await this.hackers.update({ + await this.hacker_Liked.update({ data: { - liked: 1, + hacker_news: { + update: { + liked: 1, + }, + }, }, where: { - uuid, + uuid: likedUuid, + postUuid, + userUuid: clientUuid, }, }); NewsLogger.info('[Hacker] Starred Updated'); - - return 0; } catch (error) { NewsLogger.error('[Hacker] Update News Liked Error: %o', { error, @@ -164,7 +181,7 @@ export class HackerPrismaLibrary extends PrismaClient { // skip: (page - 1) * size, // }); - NewsLogger.info('[Hacker] Founded Starred News: %o', { + NewsLogger.debug('[Hacker] Founded Starred News: %o', { totalPosts, newsSize: starredNews.length, }); @@ -174,7 +191,7 @@ export class HackerPrismaLibrary extends PrismaClient { starredNews, }; } catch (error) { - NewsLogger.info('[Hacker] Get Starred News Error: %o', { + NewsLogger.error('[Hacker] Get Starred News Error: %o', { error, }); diff --git a/src/providers/news/hacker/hacker.pvd.ts b/src/providers/news/hacker/hacker.pvd.ts index 4ca263b..35a1e86 100755 --- a/src/providers/news/hacker/hacker.pvd.ts +++ b/src/providers/news/hacker/hacker.pvd.ts @@ -3,11 +3,15 @@ import { Injectable } from '@nestjs/common'; 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 { HackerPrismaLibrary } from './hacker-prisma.lib'; @Injectable() export class HackersNewsProvider { - constructor(private prisma: HackerPrismaLibrary) {} + constructor( + private readonly prisma: HackerPrismaLibrary, + private readonly account: AccountManager, + ) {} async getHackerNewsCount() { try { @@ -57,16 +61,20 @@ export class HackersNewsProvider { } } - async giveStar(uuid: string) { + async giveStar(postUuid: string, clientUuid: string) { try { - const isLiked = await this.prisma.checkHackerNewsIsLiked(uuid); + const isLogined = this.account.getItem(clientUuid); + + if (!isLogined) throw new HackerError('[Hackers] Give Star on the Stars', 'No Logined User Found.'); + + const { uuid: likedUuid, isLiked } = await this.prisma.checkHackerNewsIsLiked(postUuid, clientUuid); if (isLiked) { - await this.prisma.updateHackerNewsLikedtoUnliked(uuid); + await this.prisma.updateHackerNewsLikedtoUnliked(likedUuid, postUuid, clientUuid); } if (!isLiked) { - await this.prisma.updateHackerNewsLiked(uuid); + await this.prisma.updateHackerNewsLiked(likedUuid, postUuid, clientUuid); } return true; diff --git a/src/providers/news/ml/machine.pvd.ts b/src/providers/news/ml/machine.pvd.ts index e54268b..b85cd69 100644 --- a/src/providers/news/ml/machine.pvd.ts +++ b/src/providers/news/ml/machine.pvd.ts @@ -3,11 +3,15 @@ import { Injectable } from '@nestjs/common'; 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 { MlPrismaLibrary } from './ml-prisma.lib'; @Injectable() export class MachineLearningProvider { - constructor(private readonly prisma: MlPrismaLibrary) {} + constructor( + private readonly prisma: MlPrismaLibrary, + private readonly account: AccountManager, + ) {} async bringLatestMachineLearningNews(today: string) { try { @@ -25,7 +29,7 @@ export class MachineLearningProvider { return result; } catch (error) { NewsLogger.error('[ML] Get Latest Machine Learning News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -36,22 +40,26 @@ export class MachineLearningProvider { } } - async giveStar(uuid: string) { + async giveStar(postUuid: string, clientUuid: string) { try { - const isLiked = await this.prisma.checkIsMlNewsLiked(uuid); + const isLogined = this.account.getItem(clientUuid); + + if (!isLogined) throw new MachineLearningError('[ML] Give Star on the Stars', 'No Logined User Found.'); + + const { uuid: likedUuid, isLiked } = await this.prisma.checkIsMlNewsLiked(postUuid, clientUuid); if (!isLiked) { - await this.prisma.updateMlNewsLiked(uuid); + await this.prisma.updateMlNewsLiked(likedUuid, postUuid, clientUuid); } if (isLiked) { - await this.prisma.updateMlNewsLikedtoUnliked(uuid); + await this.prisma.updateMlNewsLikedtoUnliked(likedUuid, postUuid, clientUuid); } return true; } catch (error) { NewsLogger.error('[ML] Give Star on the ML News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -76,7 +84,7 @@ export class MachineLearningProvider { return starredNews; } catch (error) { NewsLogger.error('[ML] Bring Starred ML News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( diff --git a/src/providers/news/ml/ml-prisma.lib.ts b/src/providers/news/ml/ml-prisma.lib.ts index 73267fe..3feaf56 100644 --- a/src/providers/news/ml/ml-prisma.lib.ts +++ b/src/providers/news/ml/ml-prisma.lib.ts @@ -27,7 +27,7 @@ export class MlPrismaLibrary extends PrismaClient { return result; } catch (error) { NewsLogger.error('[ML] Bring Geek News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new PrismaError( @@ -38,27 +38,33 @@ export class MlPrismaLibrary extends PrismaClient { } } - async checkIsMlNewsLiked(uuid: string) { + async checkIsMlNewsLiked(postUuid: string, clientUuid: string) { try { - const isStarred = await this.machineNews.findFirst({ + const isStarred = await this.ml_Liked.findFirst({ select: { - liked: true, + uuid: true, + ml_news: { + select: { + liked: true, + }, + }, }, where: { - uuid, + userUuid: clientUuid, + postUuid, }, }); if (isStarred === null) throw new MachineLearningError('[ML] Get Star Info', 'No Star Info Found.'); - NewsLogger.info('[ML] Found Is Starred Info: %o', { - isLiked: isStarred.liked, + NewsLogger.debug('[ML] Found Is Starred Info: %o', { + isLiked: isStarred.ml_news.liked, }); - return isStarred.liked; + return { uuid: isStarred.uuid, isLiked: isStarred.ml_news.liked }; } catch (error) { NewsLogger.error('[ML] Check Hada News Liked Info Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -69,27 +75,32 @@ export class MlPrismaLibrary extends PrismaClient { } } - async updateMlNewsLikedtoUnliked(uuid: string) { + async updateMlNewsLikedtoUnliked(likedUuid: string, postUuid: string, clientUuid: string): Promise { try { - NewsLogger.info('[ML] Give Hada News unStar Request: %o', { - uuid, + NewsLogger.debug('[ML] Give Hada News unStar Request: %o', { + likedUuid, + postUuid, + clientUuid, }); - await this.machineNews.update({ + await this.ml_Liked.update({ data: { - liked: 0, + ml_news: { + update: { + liked: 0, + }, + }, }, where: { - uuid, + uuid: likedUuid, + postUuid, + userUuid: clientUuid, }, }); - NewsLogger.info('[ML] Unstarred Updated'); - - return 0; } catch (error) { NewsLogger.error('[ML] Update Liked to UnLiked Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -100,27 +111,33 @@ export class MlPrismaLibrary extends PrismaClient { } } - async updateMlNewsLiked(uuid: string) { + async updateMlNewsLiked(likedUuid: string, postUuid: string, clientUuid: string): Promise { try { - NewsLogger.info('[ML] Give Hacker News Star Request: %o', { - uuid, + NewsLogger.debug('[ML] Give Hacker News Star Request: %o', { + likedUuid, + postUuid, + clientUuid, }); - await this.machineNews.update({ + await this.ml_Liked.update({ data: { - liked: 1, + ml_news: { + update: { + liked: 1, + }, + }, }, where: { - uuid, + uuid: likedUuid, + postUuid, + userUuid: clientUuid, }, }); NewsLogger.info('[ML] Starred Updated'); - - return 0; } catch (error) { NewsLogger.error('[ML] Update News Liked Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -152,7 +169,7 @@ export class MlPrismaLibrary extends PrismaClient { skip: (page - 1) * size, }); - NewsLogger.info('[ML] Founded Starred News: %o', { + NewsLogger.debug('[ML] Founded Starred News: %o', { totalPosts, newsSize: starredNews.length, }); @@ -163,7 +180,7 @@ export class MlPrismaLibrary extends PrismaClient { }; } catch (error) { NewsLogger.info('[ML] Get Starred News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( diff --git a/src/providers/news/news-prisma.lib.ts b/src/providers/news/news-prisma.lib.ts index 3aeb0a6..262a433 100644 --- a/src/providers/news/news-prisma.lib.ts +++ b/src/providers/news/news-prisma.lib.ts @@ -22,7 +22,7 @@ export class NewsPrismaLibrary extends PrismaClient { return result; } catch (error) { NewsLogger.error('[HADA] Bring Geek News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new PrismaError( @@ -54,7 +54,7 @@ export class NewsPrismaLibrary extends PrismaClient { return result; } catch (error) { NewsLogger.error('[ML] Bring Geek News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new PrismaError( @@ -78,14 +78,14 @@ export class NewsPrismaLibrary extends PrismaClient { if (isStarred === null) throw new MachineLearningError('[ML] Get Star Info', 'No Star Info Found.'); - NewsLogger.info('[ML] Found Is Starred Info: %o', { + NewsLogger.debug('[ML] Found Is Starred Info: %o', { isLiked: isStarred.liked, }); return isStarred.liked; } catch (error) { NewsLogger.error('[ML] Check Hada News Liked Info Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -98,7 +98,7 @@ export class NewsPrismaLibrary extends PrismaClient { async updateMlNewsLikedtoUnliked(uuid: string) { try { - NewsLogger.info('[ML] Give Hada News unStar Request: %o', { + NewsLogger.debug('[ML] Give Hada News unStar Request: %o', { uuid, }); @@ -116,7 +116,7 @@ export class NewsPrismaLibrary extends PrismaClient { return 0; } catch (error) { NewsLogger.error('[ML] Update Liked to UnLiked Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -129,7 +129,7 @@ export class NewsPrismaLibrary extends PrismaClient { async updateMlNewsLiked(uuid: string) { try { - NewsLogger.info('[ML] Give Hacker News Star Request: %o', { + NewsLogger.debug('[ML] Give Hacker News Star Request: %o', { uuid, }); @@ -147,7 +147,7 @@ export class NewsPrismaLibrary extends PrismaClient { return 0; } catch (error) { NewsLogger.error('[ML] Update News Liked Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -179,7 +179,7 @@ export class NewsPrismaLibrary extends PrismaClient { skip: (page - 1) * size, }); - NewsLogger.info('[ML] Founded Starred News: %o', { + NewsLogger.debug('[ML] Founded Starred News: %o', { totalPosts, newsSize: starredNews.length, }); @@ -190,7 +190,7 @@ export class NewsPrismaLibrary extends PrismaClient { }; } catch (error) { NewsLogger.info('[ML] Get Starred News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new MachineLearningError( @@ -217,7 +217,7 @@ export class NewsPrismaLibrary extends PrismaClient { return result; } catch (error) { NewsLogger.error('[ML] Bring Geek News Error: %o', { - error: error instanceof Error ? error : new Error(JSON.stringify(error)), + error, }); throw new PrismaError( diff --git a/src/types/client.type.ts b/src/types/client.type.ts index dccfa96..db285eb 100644 --- a/src/types/client.type.ts +++ b/src/types/client.type.ts @@ -18,6 +18,7 @@ export interface ClientLoginMapKey { export interface ClientLoginMapItem { email: string; + password?: string; } export interface ClientMyPageRequest { diff --git a/yarn.lock b/yarn.lock index 31e0e1d..7889e15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -160,9 +160,9 @@ __metadata: languageName: node linkType: hard -"@nestjs/common@npm:^10.3.0": - version: 10.3.0 - resolution: "@nestjs/common@npm:10.3.0" +"@nestjs/common@npm:^10.3.1": + version: 10.3.1 + resolution: "@nestjs/common@npm:10.3.1" dependencies: iterare: "npm:1.2.1" tslib: "npm:2.6.2" @@ -177,13 +177,13 @@ __metadata: optional: true class-validator: optional: true - checksum: bedb3437e6517df423526409b5a70cc33c52b557d17bd74ca12ab09a37ad5ff4ecdece44db625e3d702e21d308bc49d5419afe1752181af6aafdee3a27c9d394 + checksum: 39b004b2cd7e2399ef9e6e3afda67a34abe1bea93360ed065423ffe2b278cf5f3a29b4bc70586de0d6051c3bb8d6b7e556fce40ba372c2bb15a01e84feaece29 languageName: node linkType: hard -"@nestjs/core@npm:^10.3.0": - version: 10.3.0 - resolution: "@nestjs/core@npm:10.3.0" +"@nestjs/core@npm:^10.3.1": + version: 10.3.1 + resolution: "@nestjs/core@npm:10.3.1" dependencies: "@nuxtjs/opencollective": "npm:0.3.2" fast-safe-stringify: "npm:2.1.1" @@ -205,7 +205,7 @@ __metadata: optional: true "@nestjs/websockets": optional: true - checksum: 4bdeed0f203e55b4a1edf0031df55b6bf059c1f9faf6f86ac70e08a6e279c2d494df858ea251cbef915aa0df27b6534d1baace2847a3be7853bf07c1ad3a196f + checksum: 397580c2009301e30a5f353862920fb3498e91aa41655ddb0474f63de2d99aff4bf9e3446322692760dff9a3b7d4453e6bcedd2db689518d3e56c6acf31fce16 languageName: node linkType: hard @@ -231,9 +231,9 @@ __metadata: languageName: node linkType: hard -"@nestjs/platform-express@npm:^10.3.0": - version: 10.3.0 - resolution: "@nestjs/platform-express@npm:10.3.0" +"@nestjs/platform-express@npm:^10.3.1": + version: 10.3.1 + resolution: "@nestjs/platform-express@npm:10.3.1" dependencies: body-parser: "npm:1.20.2" cors: "npm:2.8.5" @@ -243,7 +243,7 @@ __metadata: peerDependencies: "@nestjs/common": ^10.0.0 "@nestjs/core": ^10.0.0 - checksum: 5e802d18f779246ac5dac69df7fb293f60b3802d31f50637b08dc9055ef1b4ee2ee18b2ff1c8545894a7ca1dd570033de6fa05764365ca74cb5734ab7a923b3e + checksum: cfcffc6ac3f7e59f1cabcd344ef52d509378561bc3ab763bd860db3afdf0a66bede59246a9bae0ef9bbf6ec2c875fff871ebd8cade38d55ac3d70610bc83f436 languageName: node linkType: hard @@ -287,61 +287,61 @@ __metadata: languageName: node linkType: hard -"@prisma/client@npm:^5.8.1": - version: 5.8.1 - resolution: "@prisma/client@npm:5.8.1" +"@prisma/client@npm:^5.9.1": + version: 5.9.1 + resolution: "@prisma/client@npm:5.9.1" peerDependencies: prisma: "*" peerDependenciesMeta: prisma: optional: true - checksum: 8af50ff949195022ae8521bb805375cc45e795a26478b3c4f9ce4565730cc9f294b8b1e80c760887b99a5973b10c173d1a87f9fb63e5cc7c29b38624cc22a491 + checksum: 2a661cec8fa94697ee5346e4cc793a7f3ae563ef2427cb15b6b9f712af9368010ede3f854bf75b39b5601db131d4c49cb175449f2f9a281c968685a3507ae183 languageName: node linkType: hard -"@prisma/debug@npm:5.8.1": - version: 5.8.1 - resolution: "@prisma/debug@npm:5.8.1" - checksum: a36c3cb11c0d0135038760c9ea3a4c169d99336b6f7b9943c280b699cdbe04ccd2d0d9d21aa7a44e5391bb1de1f3748ee9bf6667f2940703ecb13450efc3c44d +"@prisma/debug@npm:5.9.1": + version: 5.9.1 + resolution: "@prisma/debug@npm:5.9.1" + checksum: ef9daf19c083e6a7c7470417aee4d4a3a12446c18285cc76f65ce2d133650c28d7a2f0fa5efe9ed7b2d0968ea91d1884e16d377908cc853f20a458270612aa44 languageName: node linkType: hard -"@prisma/engines-version@npm:5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2": - version: 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2 - resolution: "@prisma/engines-version@npm:5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2" - checksum: cd326d3a0f977ca8fe488f0f32193c358a39f6f2eb06dc75edc532e3682e8fde2573638d74766c534012daae250bc07fda1d9eb53ec1540b63183c927d54ffb6 +"@prisma/engines-version@npm:5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64": + version: 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64 + resolution: "@prisma/engines-version@npm:5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64" + checksum: 7ed88a87f64b1cd55fe5ade37020dafb47e8b2f0735cd0e1941953012c3097a6c10800fd7e6d683e8f74bffa66c3b5442e343cada383b3ec2e15c6d4c4b4074f languageName: node linkType: hard -"@prisma/engines@npm:5.8.1": - version: 5.8.1 - resolution: "@prisma/engines@npm:5.8.1" +"@prisma/engines@npm:5.9.1": + version: 5.9.1 + resolution: "@prisma/engines@npm:5.9.1" dependencies: - "@prisma/debug": "npm:5.8.1" - "@prisma/engines-version": "npm:5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2" - "@prisma/fetch-engine": "npm:5.8.1" - "@prisma/get-platform": "npm:5.8.1" - checksum: 3edc786fee06a10c6e2e17b488d047cccae226bd0cb5537ec417e64d70b1793d5abd2397aa5dadebad435da1bf46eb9d1731d56bd0eb955f65bf6118990b52bb + "@prisma/debug": "npm:5.9.1" + "@prisma/engines-version": "npm:5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64" + "@prisma/fetch-engine": "npm:5.9.1" + "@prisma/get-platform": "npm:5.9.1" + checksum: 383d2247416d8f0df577c9fcacf0662d4f30f297f135b9bd8f832f9768ed2a835a3380a1062685c0e36fe4d6b91d2f17de72d2d28b0e7afe2e055f9fc5213af2 languageName: node linkType: hard -"@prisma/fetch-engine@npm:5.8.1": - version: 5.8.1 - resolution: "@prisma/fetch-engine@npm:5.8.1" +"@prisma/fetch-engine@npm:5.9.1": + version: 5.9.1 + resolution: "@prisma/fetch-engine@npm:5.9.1" dependencies: - "@prisma/debug": "npm:5.8.1" - "@prisma/engines-version": "npm:5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2" - "@prisma/get-platform": "npm:5.8.1" - checksum: e2845e55283ed5a9f51a414d4093d95e9a05196e15cd94f2be1ea2849c39bbe0b0d91bb20443b380dac9f6ae4fdbff5cbbd869b4bff85a6a5919198307c5b9dc + "@prisma/debug": "npm:5.9.1" + "@prisma/engines-version": "npm:5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64" + "@prisma/get-platform": "npm:5.9.1" + checksum: 6a48b323b4929bdcea92c2fde61fbe78c655ebf075589bd4968c4122fa14360be023f41840d43a7964f86c104da68d850ad1bcd6a5894714c3d8adf526fca95b languageName: node linkType: hard -"@prisma/get-platform@npm:5.8.1": - version: 5.8.1 - resolution: "@prisma/get-platform@npm:5.8.1" +"@prisma/get-platform@npm:5.9.1": + version: 5.9.1 + resolution: "@prisma/get-platform@npm:5.9.1" dependencies: - "@prisma/debug": "npm:5.8.1" - checksum: eb57023cdb21ed6b6c76486aa0ff84632b094bd1b297bc0592f4d99643159ccaad199f1fccad5e89f7d83ba733855e74eb480046568f89f7de4265cb5d35ddf9 + "@prisma/debug": "npm:5.9.1" + checksum: 14e2ba7fcb43d285cd8b1780b9abe709891cf3681eb515b5a237e543906b3b9e9e8cd0606cfb86ed5096ff690b19df1803f1b80cf02c3df9c994e77c30974113 languageName: node linkType: hard @@ -469,12 +469,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^20.11.2": - version: 20.11.2 - resolution: "@types/node@npm:20.11.2" +"@types/node@npm:^20.11.16": + version: 20.11.16 + resolution: "@types/node@npm:20.11.16" dependencies: undici-types: "npm:~5.26.4" - checksum: 029d603b56f7277b109a14e29e97d8e7269960cedafd8761cd0e65a0bcd9e7a554c192708becf3248a22f42681f476320af6a06c64a692a52414d1c167d9f50a + checksum: 751f50ec5c9332b11515e82fe37c71479ac4449b711280aa3c7910edf67b1e3f5ac00041512add543f9a892096a68356406998bf02a2c809a73d176c44c28414 languageName: node linkType: hard @@ -3075,14 +3075,14 @@ __metadata: languageName: node linkType: hard -"prisma@npm:^5.8.1": - version: 5.8.1 - resolution: "prisma@npm:5.8.1" +"prisma@npm:^5.9.1": + version: 5.9.1 + resolution: "prisma@npm:5.9.1" dependencies: - "@prisma/engines": "npm:5.8.1" + "@prisma/engines": "npm:5.9.1" bin: prisma: build/index.js - checksum: 66f7b85a4b606f5a51413e41cdd569144e6ab4b503b6fcc18bd983fad4bf2951a846a3d1010b6dd853ef15838e7e8deefaf98501fca63624a1fda50a5d5cecf8 + checksum: 4dd4e094939b5dd7b317a821544e777a6d8804bf106546edf3ff0d6ea8203299fca09d852c6d10694a55d088fece1e5f8d86eac5706614609860b1fee7c4769d languageName: node linkType: hard @@ -3546,15 +3546,15 @@ __metadata: version: 0.0.0-use.local resolution: "tech_news_scrape_back@workspace:." dependencies: - "@nestjs/common": "npm:^10.3.0" - "@nestjs/core": "npm:^10.3.0" + "@nestjs/common": "npm:^10.3.1" + "@nestjs/core": "npm:^10.3.1" "@nestjs/jwt": "npm:^10.2.0" "@nestjs/passport": "npm:^10.0.3" - "@nestjs/platform-express": "npm:^10.3.0" - "@prisma/client": "npm:^5.8.1" + "@nestjs/platform-express": "npm:^10.3.1" + "@prisma/client": "npm:^5.9.1" "@types/cookie-parser": "npm:^1" "@types/express": "npm:^4.17.21" - "@types/node": "npm:^20.11.2" + "@types/node": "npm:^20.11.16" "@types/passport": "npm:^0" "@types/passport-jwt": "npm:^4" "@typescript-eslint/eslint-plugin": "npm:^6.19.0" @@ -3573,7 +3573,7 @@ __metadata: passport: "npm:^0.7.0" passport-jwt: "npm:^4.0.1" prettier: "npm:^3.2.2" - prisma: "npm:^5.8.1" + prisma: "npm:^5.9.1" reflect-metadata: "npm:^0.2.1" rxjs: "npm:^7.8.1" ts-node: "npm:^10.9.2"