From ecc2b817e6c454dffd61d28f542bfefdc587a88b Mon Sep 17 00:00:00 2001 From: Cesxhin Date: Sun, 28 Jul 2024 17:34:03 +0200 Subject: [PATCH 01/21] Create basic api rest, custom log and create empty first controller --- .gitignore | 6 ++ .vscode/launch.json | 15 +++++ src_refactory/applications/logger.ts | 56 +++++++++++++++++ src_refactory/applications/serverFastify.ts | 50 +++++++++++++++ src_refactory/controllers/AnimeController.ts | 16 +++++ src_refactory/index.ts | 65 ++++++++++++++++++++ src_refactory/package.json | 27 ++++++++ src_refactory/tsconfig.json | 7 +++ 8 files changed, 242 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 src_refactory/applications/logger.ts create mode 100644 src_refactory/applications/serverFastify.ts create mode 100644 src_refactory/controllers/AnimeController.ts create mode 100644 src_refactory/index.ts create mode 100644 src_refactory/package.json create mode 100644 src_refactory/tsconfig.json diff --git a/.gitignore b/.gitignore index 8bfb316..0d35a1f 100644 --- a/.gitignore +++ b/.gitignore @@ -405,3 +405,9 @@ Properties schemas.json Cesxhin.AnimeManga.Api.csproj + + +# node +node_modules +package-lock.json +.env \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9bd3aae --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node-terminal", + "request": "launch", + "name": "Launch Program", + "cwd": "${workspaceFolder}\\src_refactory", + "command": "npm run start" + } + ] +} \ No newline at end of file diff --git a/src_refactory/applications/logger.ts b/src_refactory/applications/logger.ts new file mode 100644 index 0000000..edb0d6b --- /dev/null +++ b/src_refactory/applications/logger.ts @@ -0,0 +1,56 @@ +import chalk from "chalk"; +import {DateTime} from "luxon"; + +class Logger { + nameService: string | null = null; + + constructor(nameService: string){ + this.nameService = nameService.toUpperCase(); + } + + debug(...args: Array){ + this.#baseLog("debug", ...args); + } + + info(...args: Array){ + this.#baseLog("info", ...args); + } + + warn(...args: Array){ + this.#baseLog("warning", ...args); + } + + error(...args: Array){ + this.#baseLog("error", ...args); + } + + fatal(...args: Array){ + this.#baseLog("fatal", ...args); + } + + #baseLog(type: "debug" | "info" | "warning" | "error" | "fatal", ...args: Array){ + let message = `[${DateTime.now().toFormat("dd-MM-yyyy hh:mm:ssZZ")}] [${type.toUpperCase()}] [${this.nameService}]` + + switch(type){ + case "debug": + message = chalk.gray(message, ...args); + break; + case "info": + message = chalk.blue(message, ...args); + break; + case "warning": + message = chalk.yellow(message, ...args); + break; + case "error": + message = chalk.red(message, ...args); + break; + case "fatal": + message = chalk.redBright(message, ...args); + break; + } + + console.log(message); + } +} + +export default Logger; \ No newline at end of file diff --git a/src_refactory/applications/serverFastify.ts b/src_refactory/applications/serverFastify.ts new file mode 100644 index 0000000..46b2fc8 --- /dev/null +++ b/src_refactory/applications/serverFastify.ts @@ -0,0 +1,50 @@ +import Fastify from 'fastify'; +import { DateTime } from 'luxon'; +import { env } from 'process'; +import _ from "lodash"; + +import Logger from './logger'; +const logger = new Logger("api"); + +//settings +const fastify = Fastify(); + +fastify.addHook("onRequest", (req, replay, next) => { + //@ts-ignores + replay.startTime = DateTime.now().toISO(); + + next(); +}) + +fastify.addHook("onResponse", (req, replay, next) => { + //@ts-ignore + const time = DateTime.fromISO(replay.startTime); + + let bodyJson = {}; + + if(env.LOG_LEVEL === "debug"){ + const body = req.body; + + if(!_.isObject(body)){ + try{ + bodyJson = JSON.parse(body as string); + }catch{ + //ignore + } + }else{ + bodyJson = body; + } + } + + const message = [req.raw.method, req.url.split('?')[0], JSON.stringify(req.query), JSON.stringify(bodyJson), replay.statusCode, `(${DateTime.now().diff(time).toMillis()} ms)`]; + + if(replay.statusCode === 500){ + logger.error(...message); + }else{ + logger.info(...message); + } + + next(); +}) + +export default fastify; \ No newline at end of file diff --git a/src_refactory/controllers/AnimeController.ts b/src_refactory/controllers/AnimeController.ts new file mode 100644 index 0000000..d82b240 --- /dev/null +++ b/src_refactory/controllers/AnimeController.ts @@ -0,0 +1,16 @@ +import Logger from "../applications/logger"; +import fastify from "../applications/serverFastify"; + +const logger = new Logger("anime-controller"); + +logger.debug("Loaded controller!") + +fastify.get('/', async function handler (request, reply) { + return { hello: 'world' } +}) + +fastify.post('/', async function handler (request, reply) { + return { hello: 'world' } +}) + +export default fastify; \ No newline at end of file diff --git a/src_refactory/index.ts b/src_refactory/index.ts new file mode 100644 index 0000000..8625e52 --- /dev/null +++ b/src_refactory/index.ts @@ -0,0 +1,65 @@ +import { env, exit, platform } from "process"; +import fs from "fs"; +import path from "path"; +import _ from "lodash"; +import {config} from "dotenv"; + +//load env +config(); + +import fastifyServer from "./applications/serverFastify" +import Logger from "./applications/logger"; + +const logger = new Logger("server"); +const __dirname = path.resolve(); + +async function init(){ + logger.info("Starting service api..."); + + //routes + logger.debug("Starting load routes"); + await loadRoutes(); + logger.debug("Finish load all routes"); + + //server + let connection = ""; + try{ + connection = await fastifyServer.listen({ + port: _.isNil(env.SERVER_PORT)? 3001 : parseInt(env.SERVER_PORT), + host: env.SERVER_PORT || "127.0.0.1", + }) + }catch(err){ + logger.fatal(`Stop service api reason:`, err); + exit(1); + } + + logger.info(`Connection established ${connection}`); +} + +async function loadRoutes(){ + const listFileRoutes: Array = []; + + try{ + listFileRoutes.push(...(fs.readdirSync(path.join(__dirname, "controllers"))).filter((file) => file.indexOf('.') !== -1)); + }catch(err){ + logger.error("Failed load routes reason:", err); + } + + logger.debug("List routes available:", listFileRoutes.join(', ')) + + let success = 0; + for (const route of listFileRoutes) { + try{ + await import(path.join(platform === "win32"? 'file://' : '', __dirname, 'controllers', route)); + }catch(err){ + logger.error("Failed load", route); + continue; + } + + success++; + } + + logger.debug('Total routes loaded', success); +} + +init(); \ No newline at end of file diff --git a/src_refactory/package.json b/src_refactory/package.json new file mode 100644 index 0000000..e265278 --- /dev/null +++ b/src_refactory/package.json @@ -0,0 +1,27 @@ +{ + "name": "api_service", + "version": "1.0.0", + "main": "index.js", + "type": "module", + "scripts": { + "start": "npx tsx index.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@types/lodash": "^4.17.7", + "@types/luxon": "^3.4.2", + "chalk": "^5.3.0", + "dotenv": "^16.4.5", + "fastify": "^4.28.1", + "lodash": "^4.17.21", + "luxon": "^3.4.4", + "typescript": "^5.5.4" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "tsx": "^4.16.2" + } +} diff --git a/src_refactory/tsconfig.json b/src_refactory/tsconfig.json new file mode 100644 index 0000000..6d41c9f --- /dev/null +++ b/src_refactory/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "moduleResolution": "Bundler", + "module": "ESNext", + "target": "ESNext" + } +} \ No newline at end of file From 67bcd8f525e5cc30752874f883699ed42cd9b4a8 Mon Sep 17 00:00:00 2001 From: Cesxhin Date: Sun, 28 Jul 2024 18:17:09 +0200 Subject: [PATCH 02/21] Add submodule references --- .gitmodules | 3 +++ references | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 references diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..aea52df --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "references"] + path = references + url = https://github.com/Anime-Manga/references.git diff --git a/references b/references new file mode 160000 index 0000000..418ae3c --- /dev/null +++ b/references @@ -0,0 +1 @@ +Subproject commit 418ae3c300805b14f38da549899440e6299fa815 From d33436c650dee5cf670a424e90ae410ad74421d8 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 3 Aug 2024 09:09:53 +0200 Subject: [PATCH 03/21] Move main function to server fastify --- src_refactory/applications/serverFastify.ts | 66 ++++++++++++++++++++- src_refactory/index.ts | 61 +------------------ 2 files changed, 65 insertions(+), 62 deletions(-) diff --git a/src_refactory/applications/serverFastify.ts b/src_refactory/applications/serverFastify.ts index 46b2fc8..5532c98 100644 --- a/src_refactory/applications/serverFastify.ts +++ b/src_refactory/applications/serverFastify.ts @@ -1,14 +1,70 @@ +import { env, exit, platform } from "process"; +import fs from "fs"; import Fastify from 'fastify'; import { DateTime } from 'luxon'; -import { env } from 'process'; +import path from "path"; import _ from "lodash"; import Logger from './logger'; -const logger = new Logger("api"); + +const logger = new Logger("server-fastify"); +const __dirname = path.resolve(); //settings const fastify = Fastify(); +//init +async function init(address: string = "127.0.0.1", port: number = 3001, path_controllers = "controllers"){ + logger.info("Starting service fastify..."); + + //routes + logger.debug("Starting load routes"); + await loadRouters(path_controllers); + logger.debug("Finish load all routes"); + + //server + let connection = ""; + try{ + connection = await fastify.listen({ + port: _.isNil(env.SERVER_PORT)? 3001 : parseInt(env.SERVER_PORT), + host: env.SERVER_PORT || "127.0.0.1", + }) + }catch(err){ + logger.fatal(`Stop service fastify reason:`, err); + exit(1); + } + + logger.info(`Connection established ${connection}`); +} + +//load routers +async function loadRouters(path_controllers: string){ + const listFileRoutes: Array = []; + + try{ + listFileRoutes.push(...(fs.readdirSync(path.join(__dirname, path_controllers))).filter((file) => file.indexOf('.') !== -1)); + }catch(err){ + logger.error("Failed load routes reason:", err); + } + + logger.debug("List routes available:", listFileRoutes.join(', ')) + + let success = 0; + for (const route of listFileRoutes) { + try{ + await import(path.join(platform === "win32"? 'file://' : '', __dirname, 'controllers', route)); + }catch(err){ + logger.error("Failed load", route); + continue; + } + + success++; + } + + logger.debug('Total routes loaded', success); +} + +//logging fastify.addHook("onRequest", (req, replay, next) => { //@ts-ignores replay.startTime = DateTime.now().toISO(); @@ -47,4 +103,8 @@ fastify.addHook("onResponse", (req, replay, next) => { next(); }) -export default fastify; \ No newline at end of file +export default fastify; + +export { + init +} \ No newline at end of file diff --git a/src_refactory/index.ts b/src_refactory/index.ts index 8625e52..2a27f32 100644 --- a/src_refactory/index.ts +++ b/src_refactory/index.ts @@ -1,65 +1,8 @@ -import { env, exit, platform } from "process"; -import fs from "fs"; -import path from "path"; -import _ from "lodash"; import {config} from "dotenv"; +import {init} from "./applications/serverFastify" + //load env config(); -import fastifyServer from "./applications/serverFastify" -import Logger from "./applications/logger"; - -const logger = new Logger("server"); -const __dirname = path.resolve(); - -async function init(){ - logger.info("Starting service api..."); - - //routes - logger.debug("Starting load routes"); - await loadRoutes(); - logger.debug("Finish load all routes"); - - //server - let connection = ""; - try{ - connection = await fastifyServer.listen({ - port: _.isNil(env.SERVER_PORT)? 3001 : parseInt(env.SERVER_PORT), - host: env.SERVER_PORT || "127.0.0.1", - }) - }catch(err){ - logger.fatal(`Stop service api reason:`, err); - exit(1); - } - - logger.info(`Connection established ${connection}`); -} - -async function loadRoutes(){ - const listFileRoutes: Array = []; - - try{ - listFileRoutes.push(...(fs.readdirSync(path.join(__dirname, "controllers"))).filter((file) => file.indexOf('.') !== -1)); - }catch(err){ - logger.error("Failed load routes reason:", err); - } - - logger.debug("List routes available:", listFileRoutes.join(', ')) - - let success = 0; - for (const route of listFileRoutes) { - try{ - await import(path.join(platform === "win32"? 'file://' : '', __dirname, 'controllers', route)); - }catch(err){ - logger.error("Failed load", route); - continue; - } - - success++; - } - - logger.debug('Total routes loaded', success); -} - init(); \ No newline at end of file From 957c0209ddef5c164de0bc6b1c9ee1266a18642b Mon Sep 17 00:00:00 2001 From: cesxhin Date: Thu, 22 Aug 2024 21:12:43 +0200 Subject: [PATCH 04/21] Add postgres and references --- .gitmodules | 1 + references | 2 +- src_refactory/applications/logger.ts | 57 +---------------- src_refactory/applications/postgres.ts | 68 +++++++++++++++++++++ src_refactory/applications/serverFastify.ts | 4 +- src_refactory/index.ts | 7 ++- src_refactory/package.json | 11 +++- 7 files changed, 86 insertions(+), 64 deletions(-) mode change 100644 => 120000 src_refactory/applications/logger.ts create mode 100644 src_refactory/applications/postgres.ts diff --git a/.gitmodules b/.gitmodules index aea52df..d0a8a20 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "references"] path = references url = https://github.com/Anime-Manga/references.git + branch = refactory diff --git a/references b/references index 418ae3c..0968f3f 160000 --- a/references +++ b/references @@ -1 +1 @@ -Subproject commit 418ae3c300805b14f38da549899440e6299fa815 +Subproject commit 0968f3f57b805713ed523125eb97bf129c8add82 diff --git a/src_refactory/applications/logger.ts b/src_refactory/applications/logger.ts deleted file mode 100644 index edb0d6b..0000000 --- a/src_refactory/applications/logger.ts +++ /dev/null @@ -1,56 +0,0 @@ -import chalk from "chalk"; -import {DateTime} from "luxon"; - -class Logger { - nameService: string | null = null; - - constructor(nameService: string){ - this.nameService = nameService.toUpperCase(); - } - - debug(...args: Array){ - this.#baseLog("debug", ...args); - } - - info(...args: Array){ - this.#baseLog("info", ...args); - } - - warn(...args: Array){ - this.#baseLog("warning", ...args); - } - - error(...args: Array){ - this.#baseLog("error", ...args); - } - - fatal(...args: Array){ - this.#baseLog("fatal", ...args); - } - - #baseLog(type: "debug" | "info" | "warning" | "error" | "fatal", ...args: Array){ - let message = `[${DateTime.now().toFormat("dd-MM-yyyy hh:mm:ssZZ")}] [${type.toUpperCase()}] [${this.nameService}]` - - switch(type){ - case "debug": - message = chalk.gray(message, ...args); - break; - case "info": - message = chalk.blue(message, ...args); - break; - case "warning": - message = chalk.yellow(message, ...args); - break; - case "error": - message = chalk.red(message, ...args); - break; - case "fatal": - message = chalk.redBright(message, ...args); - break; - } - - console.log(message); - } -} - -export default Logger; \ No newline at end of file diff --git a/src_refactory/applications/logger.ts b/src_refactory/applications/logger.ts new file mode 120000 index 0000000..df766bd --- /dev/null +++ b/src_refactory/applications/logger.ts @@ -0,0 +1 @@ +../../references/src_refactory/applications/logger.ts \ No newline at end of file diff --git a/src_refactory/applications/postgres.ts b/src_refactory/applications/postgres.ts new file mode 100644 index 0000000..04bcd4a --- /dev/null +++ b/src_refactory/applications/postgres.ts @@ -0,0 +1,68 @@ +import pg from "pg"; +const {Pool} = pg; + +import Logger from "./logger"; +const logger = new Logger("pg"); + +let pool: pg.Pool; + +let inRestartingPool = false; + +//settings +let address: string, port: number, username: string, password: string, nameDatabase: string; + +async function init(newAddress: string = "localhost", newPort: number = 5432, newUsername: string = null, newPassword: string = null, newNameDatabase: string = "anime&manga"){ + address = newAddress; + port = newPort; + username = newUsername; + password = newPassword; + nameDatabase = newNameDatabase; + + await retryPool(); + + pool.on('error', async (err) => { + logger.error("[POOL] Disconnected to progresql, details:", err); + + if(!inRestartingPool){ + await retryPool(); + } + }) +} + +function createPool(){ + logger.debug("Creating Pool..."); + + //setup configuration + pool = new Pool({ + database: nameDatabase, + host: address, + port, + user: username, + password, + connectionTimeoutMillis: 5000 + }); + + logger.debug("Created Pool"); +} + +async function retryPool(){ + inRestartingPool = true; + + do{ + try{ + createPool(); + break; + }catch(err){ + logger.error('Failed connect to postgres, details:', err); + } + }while(true); + + inRestartingPool = false; + logger.info("Connected to postgres!") +} + +export default pool; + +export { + init +} \ No newline at end of file diff --git a/src_refactory/applications/serverFastify.ts b/src_refactory/applications/serverFastify.ts index 5532c98..55b9ca0 100644 --- a/src_refactory/applications/serverFastify.ts +++ b/src_refactory/applications/serverFastify.ts @@ -6,15 +6,15 @@ import path from "path"; import _ from "lodash"; import Logger from './logger'; - const logger = new Logger("server-fastify"); + const __dirname = path.resolve(); //settings const fastify = Fastify(); //init -async function init(address: string = "127.0.0.1", port: number = 3001, path_controllers = "controllers"){ +async function init(path_controllers = "controllers"){ logger.info("Starting service fastify..."); //routes diff --git a/src_refactory/index.ts b/src_refactory/index.ts index 2a27f32..8fd4aa2 100644 --- a/src_refactory/index.ts +++ b/src_refactory/index.ts @@ -1,8 +1,11 @@ import {config} from "dotenv"; -import {init} from "./applications/serverFastify" +import {init as initServerFastify} from "./applications/serverFastify" +import {init as initPostgres} from "./applications/postgres" //load env config(); -init(); \ No newline at end of file +await initPostgres(null, null, process.env.POSTGRES_USERNAME, process.env.POSTGRES_PASSWORD); + +await initServerFastify(); \ No newline at end of file diff --git a/src_refactory/package.json b/src_refactory/package.json index e265278..b25592b 100644 --- a/src_refactory/package.json +++ b/src_refactory/package.json @@ -4,24 +4,29 @@ "main": "index.js", "type": "module", "scripts": { - "start": "npx tsx index.ts" + "start": "npx tsx index.ts", + "clear": "rm -rf node_modules package-lock.json", + "create_link_references": "cd ../references/src_refactory && ln -s ../../src_refactory/node_modules && ln -s ../../src_refactory/package.json" }, "keywords": [], "author": "", "license": "ISC", "description": "", "dependencies": { - "@types/lodash": "^4.17.7", - "@types/luxon": "^3.4.2", "chalk": "^5.3.0", "dotenv": "^16.4.5", "fastify": "^4.28.1", "lodash": "^4.17.21", "luxon": "^3.4.4", + "pg": "^8.12.0", "typescript": "^5.5.4" }, "devDependencies": { + "@types/lodash": "^4.17.7", + "@types/luxon": "^3.4.2", + "@types/pg": "^8.11.6", "@types/node": "^22.0.0", + "@types/pg-pool": "^2.0.6", "tsx": "^4.16.2" } } From e036643942176183c0ddf7dc283f236f1eeaf5af Mon Sep 17 00:00:00 2001 From: cesxhin Date: Thu, 29 Aug 2024 22:59:47 +0200 Subject: [PATCH 05/21] First controller created --- .vscode/launch.json | 4 +- .../repositories/IAccountRepository.ts | 17 ++ .../interfaces/services/IAccountService.ts | 14 ++ src_refactory/applications/logger.ts | 1 - src_refactory/applications/postgres.ts | 68 ------- .../repositories/AccountRepository.ts | 51 +++++ src_refactory/applications/serverFastify.ts | 110 ----------- .../applications/services/AccountService.ts | 64 ++++++ src_refactory/controllers/AnimeController.ts | 16 -- src_refactory/controllers/account/index.ts | 12 ++ .../controllers/account/routes/createRoute.ts | 27 +++ .../controllers/account/routes/findRoute.ts | 25 +++ .../controllers/account/routes/index.ts | 2 + .../domain/interfaces/DTOs/IAccountDTO.ts | 15 ++ .../domain/interfaces/models/IAccount.ts | 15 ++ src_refactory/domain/models/Account.ts | 21 ++ src_refactory/index.ts | 10 +- src_refactory/modules/api.ts | 31 +++ src_refactory/modules/logger.ts | 1 + src_refactory/package.json | 11 +- src_refactory/server/fastify/index.ts | 187 ++++++++++++++++++ .../server/fastify/interfaces/IController.ts | 6 + .../server/fastify/interfaces/IRoute.ts | 8 + src_refactory/server/postgres/index.ts | 44 +++++ .../postgres/interfaces/IConfigPostgres.ts | 7 + src_refactory/tsconfig.json | 5 +- src_refactory/utils/AccountUtils.ts | 9 + src_refactory/utils/utils.ts | 16 ++ 28 files changed, 593 insertions(+), 204 deletions(-) create mode 100644 src_refactory/applications/interfaces/repositories/IAccountRepository.ts create mode 100644 src_refactory/applications/interfaces/services/IAccountService.ts delete mode 120000 src_refactory/applications/logger.ts delete mode 100644 src_refactory/applications/postgres.ts create mode 100644 src_refactory/applications/repositories/AccountRepository.ts delete mode 100644 src_refactory/applications/serverFastify.ts create mode 100644 src_refactory/applications/services/AccountService.ts delete mode 100644 src_refactory/controllers/AnimeController.ts create mode 100644 src_refactory/controllers/account/index.ts create mode 100644 src_refactory/controllers/account/routes/createRoute.ts create mode 100644 src_refactory/controllers/account/routes/findRoute.ts create mode 100644 src_refactory/controllers/account/routes/index.ts create mode 100644 src_refactory/domain/interfaces/DTOs/IAccountDTO.ts create mode 100644 src_refactory/domain/interfaces/models/IAccount.ts create mode 100644 src_refactory/domain/models/Account.ts create mode 100644 src_refactory/modules/api.ts create mode 120000 src_refactory/modules/logger.ts create mode 100644 src_refactory/server/fastify/index.ts create mode 100644 src_refactory/server/fastify/interfaces/IController.ts create mode 100644 src_refactory/server/fastify/interfaces/IRoute.ts create mode 100644 src_refactory/server/postgres/index.ts create mode 100644 src_refactory/server/postgres/interfaces/IConfigPostgres.ts create mode 100644 src_refactory/utils/AccountUtils.ts create mode 100644 src_refactory/utils/utils.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 9bd3aae..0a67b54 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,8 +7,8 @@ { "type": "node-terminal", "request": "launch", - "name": "Launch Program", - "cwd": "${workspaceFolder}\\src_refactory", + "name": "Start", + "cwd": "${workspaceFolder}/src_refactory", "command": "npm run start" } ] diff --git a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts new file mode 100644 index 0000000..7e9c589 --- /dev/null +++ b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts @@ -0,0 +1,17 @@ +import { Repository } from "typeorm"; + +import { Account } from "../../../domain/models/Account"; +import { IAccount } from "../../../domain/interfaces/models/IAccount"; + +export default interface IAccountRepository { + connectionRepository: Repository; + + //get + findFromUsername(username: string): Promise; + //put + createAccount(data: IAccount): Promise; + //post + updateAccount(data: IAccount): Promise; + //delete + deleteAccount(username: string): void; +} \ No newline at end of file diff --git a/src_refactory/applications/interfaces/services/IAccountService.ts b/src_refactory/applications/interfaces/services/IAccountService.ts new file mode 100644 index 0000000..4afb655 --- /dev/null +++ b/src_refactory/applications/interfaces/services/IAccountService.ts @@ -0,0 +1,14 @@ +import {IAccountDTO} from "../../../domain/interfaces/DTOs/IAccountDTO" +import {IAccount} from "../../../domain/interfaces/models/IAccount" + +export default interface IAccountService { + //get + findFromUsername(username: string): Promise; + login(username: string, password: string): Promise; + //put + createAccount(data: IAccount): Promise; + //post + updateAccount(data: IAccount): Promise; + //delete + deleteAccount(username: string): void; +} \ No newline at end of file diff --git a/src_refactory/applications/logger.ts b/src_refactory/applications/logger.ts deleted file mode 120000 index df766bd..0000000 --- a/src_refactory/applications/logger.ts +++ /dev/null @@ -1 +0,0 @@ -../../references/src_refactory/applications/logger.ts \ No newline at end of file diff --git a/src_refactory/applications/postgres.ts b/src_refactory/applications/postgres.ts deleted file mode 100644 index 04bcd4a..0000000 --- a/src_refactory/applications/postgres.ts +++ /dev/null @@ -1,68 +0,0 @@ -import pg from "pg"; -const {Pool} = pg; - -import Logger from "./logger"; -const logger = new Logger("pg"); - -let pool: pg.Pool; - -let inRestartingPool = false; - -//settings -let address: string, port: number, username: string, password: string, nameDatabase: string; - -async function init(newAddress: string = "localhost", newPort: number = 5432, newUsername: string = null, newPassword: string = null, newNameDatabase: string = "anime&manga"){ - address = newAddress; - port = newPort; - username = newUsername; - password = newPassword; - nameDatabase = newNameDatabase; - - await retryPool(); - - pool.on('error', async (err) => { - logger.error("[POOL] Disconnected to progresql, details:", err); - - if(!inRestartingPool){ - await retryPool(); - } - }) -} - -function createPool(){ - logger.debug("Creating Pool..."); - - //setup configuration - pool = new Pool({ - database: nameDatabase, - host: address, - port, - user: username, - password, - connectionTimeoutMillis: 5000 - }); - - logger.debug("Created Pool"); -} - -async function retryPool(){ - inRestartingPool = true; - - do{ - try{ - createPool(); - break; - }catch(err){ - logger.error('Failed connect to postgres, details:', err); - } - }while(true); - - inRestartingPool = false; - logger.info("Connected to postgres!") -} - -export default pool; - -export { - init -} \ No newline at end of file diff --git a/src_refactory/applications/repositories/AccountRepository.ts b/src_refactory/applications/repositories/AccountRepository.ts new file mode 100644 index 0000000..8c83591 --- /dev/null +++ b/src_refactory/applications/repositories/AccountRepository.ts @@ -0,0 +1,51 @@ +import { Like } from "typeorm"; + +import {pg} from "../../server/postgres"; +import { ApiErrorGeneric, ApiNotFound } from "../../modules/api"; + +import IAccountRepository from "../interfaces/repositories/IAccountRepository"; +import { IAccount, IAccountEnv } from "../../domain/interfaces/models/IAccount"; + +import { Account } from "../../domain/models/Account"; + +import Logger from "../../modules/logger"; +const logger = new Logger("account-db"); + +export default class AccountRepository implements IAccountRepository { + connectionRepository = pg.getRepository(Account); + + async findFromUsername(username: string): Promise { + let rs: Account | null = null; + + try{ + rs = await this.connectionRepository.findOneBy({ [IAccountEnv.USERNAME]: Like(username) }); + }catch(err){ + logger.error("Failed exec query findFromUsername, details:", err); + throw new ApiErrorGeneric(err); + } + + if(rs === null){ + throw new ApiNotFound(`Not found this username '${username}'`); + } + + return rs; + } + + async createAccount(data: IAccount): Promise { + try{ + await this.connectionRepository.insert(data) + }catch(err){ + logger.error("Failed exec query createAccount, details:", err); + throw new ApiErrorGeneric(err); + } + + return data; + } + updateAccount(data: IAccount): Promise { + throw new Error("Method not implemented."); + } + deleteAccount(username: string): void { + throw new Error("Method not implemented."); + } + +} \ No newline at end of file diff --git a/src_refactory/applications/serverFastify.ts b/src_refactory/applications/serverFastify.ts deleted file mode 100644 index 55b9ca0..0000000 --- a/src_refactory/applications/serverFastify.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { env, exit, platform } from "process"; -import fs from "fs"; -import Fastify from 'fastify'; -import { DateTime } from 'luxon'; -import path from "path"; -import _ from "lodash"; - -import Logger from './logger'; -const logger = new Logger("server-fastify"); - -const __dirname = path.resolve(); - -//settings -const fastify = Fastify(); - -//init -async function init(path_controllers = "controllers"){ - logger.info("Starting service fastify..."); - - //routes - logger.debug("Starting load routes"); - await loadRouters(path_controllers); - logger.debug("Finish load all routes"); - - //server - let connection = ""; - try{ - connection = await fastify.listen({ - port: _.isNil(env.SERVER_PORT)? 3001 : parseInt(env.SERVER_PORT), - host: env.SERVER_PORT || "127.0.0.1", - }) - }catch(err){ - logger.fatal(`Stop service fastify reason:`, err); - exit(1); - } - - logger.info(`Connection established ${connection}`); -} - -//load routers -async function loadRouters(path_controllers: string){ - const listFileRoutes: Array = []; - - try{ - listFileRoutes.push(...(fs.readdirSync(path.join(__dirname, path_controllers))).filter((file) => file.indexOf('.') !== -1)); - }catch(err){ - logger.error("Failed load routes reason:", err); - } - - logger.debug("List routes available:", listFileRoutes.join(', ')) - - let success = 0; - for (const route of listFileRoutes) { - try{ - await import(path.join(platform === "win32"? 'file://' : '', __dirname, 'controllers', route)); - }catch(err){ - logger.error("Failed load", route); - continue; - } - - success++; - } - - logger.debug('Total routes loaded', success); -} - -//logging -fastify.addHook("onRequest", (req, replay, next) => { - //@ts-ignores - replay.startTime = DateTime.now().toISO(); - - next(); -}) - -fastify.addHook("onResponse", (req, replay, next) => { - //@ts-ignore - const time = DateTime.fromISO(replay.startTime); - - let bodyJson = {}; - - if(env.LOG_LEVEL === "debug"){ - const body = req.body; - - if(!_.isObject(body)){ - try{ - bodyJson = JSON.parse(body as string); - }catch{ - //ignore - } - }else{ - bodyJson = body; - } - } - - const message = [req.raw.method, req.url.split('?')[0], JSON.stringify(req.query), JSON.stringify(bodyJson), replay.statusCode, `(${DateTime.now().diff(time).toMillis()} ms)`]; - - if(replay.statusCode === 500){ - logger.error(...message); - }else{ - logger.info(...message); - } - - next(); -}) - -export default fastify; - -export { - init -} \ No newline at end of file diff --git a/src_refactory/applications/services/AccountService.ts b/src_refactory/applications/services/AccountService.ts new file mode 100644 index 0000000..61c9176 --- /dev/null +++ b/src_refactory/applications/services/AccountService.ts @@ -0,0 +1,64 @@ +import IAccountService from "../interfaces/services/IAccountService"; +import { IAccountDTO, IAccountDTOEnv } from "../../domain/interfaces/DTOs/IAccountDTO"; +import { IAccount, IAccountEnv } from "../../domain/interfaces/models/IAccount"; + +import AccountRepository from "../repositories/AccountRepository"; + +import {hashPassword} from "../../utils/AccountUtils"; +import { ApiConflict, ApiNotFound, ApiUnauthorized } from "../../modules/api"; + +import { objectAssign } from "../../utils/utils"; +import { Account } from "../../domain/models/Account"; + +export class AccountService implements IAccountService { + accountRepository = new AccountRepository(); + + async login(username: string, password: string): Promise { + let user: Account; + + try{ + user = await this.accountRepository.findFromUsername(username); + }catch(e){ + if(e instanceof ApiNotFound){ + throw new ApiUnauthorized("Username/Password wrong"); + }else{ + throw new e; + } + } + + if(hashPassword(password) !== user[IAccountEnv.PASSWORD]){ + throw new ApiUnauthorized("Username/Password wrong"); + } + + return objectAssign(user, IAccountDTOEnv); + } + async findFromUsername(username: string): Promise { + const user = await this.accountRepository.findFromUsername(username); + + return objectAssign(user, IAccountDTOEnv); + } + async createAccount(data: IAccount): Promise { + const username = data[IAccountEnv.USERNAME]; + + try{ + await this.accountRepository.findFromUsername(username); + }catch(e){ + if(e instanceof ApiNotFound){ + data[IAccountEnv.PASSWORD] = hashPassword(data[IAccountEnv.PASSWORD]); + const createdAccount = await this.accountRepository.createAccount(data); + + return objectAssign(createdAccount, IAccountDTOEnv); + }else{ + throw new e; + } + } + + throw new ApiConflict(`This username already used ${username}`); + } + updateAccount(data: IAccount): Promise { + throw new Error("Method not implemented."); + } + deleteAccount(username: string): void { + throw new Error("Method not implemented."); + } +} \ No newline at end of file diff --git a/src_refactory/controllers/AnimeController.ts b/src_refactory/controllers/AnimeController.ts deleted file mode 100644 index d82b240..0000000 --- a/src_refactory/controllers/AnimeController.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Logger from "../applications/logger"; -import fastify from "../applications/serverFastify"; - -const logger = new Logger("anime-controller"); - -logger.debug("Loaded controller!") - -fastify.get('/', async function handler (request, reply) { - return { hello: 'world' } -}) - -fastify.post('/', async function handler (request, reply) { - return { hello: 'world' } -}) - -export default fastify; \ No newline at end of file diff --git a/src_refactory/controllers/account/index.ts b/src_refactory/controllers/account/index.ts new file mode 100644 index 0000000..6d4aacd --- /dev/null +++ b/src_refactory/controllers/account/index.ts @@ -0,0 +1,12 @@ +import Logger from "../../modules/logger"; +const logger = new Logger("account-controller"); + +logger.debug("Loaded controller!") + +import * as routes from "./routes"; +import { IController } from "../../server/fastify/interfaces/IController"; + +export default { + routes, + pathBaseController: "/account" +} as IController; \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/createRoute.ts b/src_refactory/controllers/account/routes/createRoute.ts new file mode 100644 index 0000000..58c9cdb --- /dev/null +++ b/src_refactory/controllers/account/routes/createRoute.ts @@ -0,0 +1,27 @@ +import Joi from "joi"; + +import { AccountService } from "../../../applications/services/AccountService"; + +import { IRoute } from "../../../server/fastify/interfaces/IRoute"; +import { IAccount, IAccountEnv } from "../../../domain/interfaces/models/IAccount"; + +const accountService = new AccountService(); + +export default { + method: "POST", + url: "/create", + hander: async function (request, replay){ + const account = request.body as IAccount; + + return accountService.createAccount(account); + }, + options: { + schema: { + body: Joi.object({ + [IAccountEnv.USERNAME]: Joi.string().max(250).required(), + [IAccountEnv.PASSWORD]: Joi.string().max(500).required(), + [IAccountEnv.CHANGE_PASSWORD]: Joi.boolean().required() + }) + } + } +} as IRoute \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/findRoute.ts b/src_refactory/controllers/account/routes/findRoute.ts new file mode 100644 index 0000000..a54197c --- /dev/null +++ b/src_refactory/controllers/account/routes/findRoute.ts @@ -0,0 +1,25 @@ +import Joi from "joi"; + +import { AccountService } from "../../../applications/services/AccountService"; + +import { IRoute } from "../../../server/fastify/interfaces/IRoute"; +import { IAccount, IAccountEnv } from "../../../domain/interfaces/models/IAccount"; + +const accountService = new AccountService(); + +export default { + method: "GET", + url: "/find", + hander: async function (request, replay){ + const {username} = request.query as {username: string}; + + return accountService.findFromUsername(username); + }, + options: { + schema: { + querystring: Joi.object({ + [IAccountEnv.USERNAME]: Joi.string().max(250).required() + }) + } + } +} as IRoute \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/index.ts b/src_refactory/controllers/account/routes/index.ts new file mode 100644 index 0000000..7dc277a --- /dev/null +++ b/src_refactory/controllers/account/routes/index.ts @@ -0,0 +1,2 @@ +export {default as createRoute} from "./createRoute"; +export {default as findRoute} from "./findRoute"; \ No newline at end of file diff --git a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts new file mode 100644 index 0000000..2c11bc6 --- /dev/null +++ b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts @@ -0,0 +1,15 @@ +export enum IAccountDTOEnv { + USERNAME = "username", + LAST_ACCESS = "last_access", + CHANGE_PASSWORD = "change_password", + EXPIRE_PASSWORD = "expire_password", + AVATAR = "avatr" +} + +export interface IAccountDTO { + [IAccountDTOEnv.USERNAME]: string, + [IAccountDTOEnv.LAST_ACCESS]: Date, + [IAccountDTOEnv.CHANGE_PASSWORD]: Date, + [IAccountDTOEnv.EXPIRE_PASSWORD]: Date, + [IAccountDTOEnv.AVATAR]: string +} \ No newline at end of file diff --git a/src_refactory/domain/interfaces/models/IAccount.ts b/src_refactory/domain/interfaces/models/IAccount.ts new file mode 100644 index 0000000..11e70a4 --- /dev/null +++ b/src_refactory/domain/interfaces/models/IAccount.ts @@ -0,0 +1,15 @@ +export enum IAccountEnv { + USERNAME = "username", + PASSWORD = "password", + LAST_ACCESS = "last_access", + CHANGE_PASSWORD = "change_password", + EXPIRE_PASSWORD = "expire_password" +} + +export interface IAccount { + [IAccountEnv.USERNAME]: string, + [IAccountEnv.PASSWORD]: string, + [IAccountEnv.LAST_ACCESS]: Date, + [IAccountEnv.CHANGE_PASSWORD]: boolean, + [IAccountEnv.EXPIRE_PASSWORD]: Date +} \ No newline at end of file diff --git a/src_refactory/domain/models/Account.ts b/src_refactory/domain/models/Account.ts new file mode 100644 index 0000000..5c740b1 --- /dev/null +++ b/src_refactory/domain/models/Account.ts @@ -0,0 +1,21 @@ +import { Entity, PrimaryColumn, Column } from "typeorm"; +import { DateTime } from "luxon"; +import { IAccount, IAccountEnv } from "../interfaces/models/IAccount"; + +@Entity("account") +export class Account implements IAccount{ + @PrimaryColumn({type: "varchar", length: 250}) + [IAccountEnv.USERNAME]: string; + + @Column({type: "varchar", length: 500}) + [IAccountEnv.PASSWORD]: string; + + @Column({type: "timestamptz", nullable: true, default: null}) + [IAccountEnv.LAST_ACCESS]: Date; + + @Column({type: "boolean", default: false}) + [IAccountEnv.CHANGE_PASSWORD]: boolean; + + @Column({type: "timestamptz", default: DateTime.now().plus({month: 1})}) + [IAccountEnv.EXPIRE_PASSWORD]: Date; +} \ No newline at end of file diff --git a/src_refactory/index.ts b/src_refactory/index.ts index 8fd4aa2..028bb3f 100644 --- a/src_refactory/index.ts +++ b/src_refactory/index.ts @@ -1,11 +1,15 @@ import {config} from "dotenv"; -import {init as initServerFastify} from "./applications/serverFastify" -import {init as initPostgres} from "./applications/postgres" +import {init as initServerFastify} from "./server/fastify" +import {init as initPostgres} from "./server/postgres" //load env config(); -await initPostgres(null, null, process.env.POSTGRES_USERNAME, process.env.POSTGRES_PASSWORD); +await initPostgres({ + username: process.env.POSTGRES_USERNAME, + password: process.env.POSTGRES_PASSWORD, + database: process.env.POSTGRES_DB +}); await initServerFastify(); \ No newline at end of file diff --git a/src_refactory/modules/api.ts b/src_refactory/modules/api.ts new file mode 100644 index 0000000..9a37e43 --- /dev/null +++ b/src_refactory/modules/api.ts @@ -0,0 +1,31 @@ +class ApiNotFound extends Error { + constructor(message: string) { + super(message); + this.name = "ApiNotFound"; + } +} +class ApiErrorGeneric extends Error { + constructor(message: string) { + super(message); + this.name = "ApiErrorGeneric"; + } +} +class ApiConflict extends Error { + constructor(message: string) { + super(message); + this.name = "ApiConflict"; + } +} +class ApiUnauthorized extends Error { + constructor(message: string) { + super(message); + this.name = "ApiUnauthorized"; + } +} + +export { + ApiNotFound, + ApiErrorGeneric, + ApiConflict, + ApiUnauthorized +} \ No newline at end of file diff --git a/src_refactory/modules/logger.ts b/src_refactory/modules/logger.ts new file mode 120000 index 0000000..8a88647 --- /dev/null +++ b/src_refactory/modules/logger.ts @@ -0,0 +1 @@ +../../references/src_refactory/modules/logger.ts \ No newline at end of file diff --git a/src_refactory/package.json b/src_refactory/package.json index b25592b..309f4de 100644 --- a/src_refactory/package.json +++ b/src_refactory/package.json @@ -6,26 +6,31 @@ "scripts": { "start": "npx tsx index.ts", "clear": "rm -rf node_modules package-lock.json", - "create_link_references": "cd ../references/src_refactory && ln -s ../../src_refactory/node_modules && ln -s ../../src_refactory/package.json" + "create_link_references": "cd ../references/src_refactory && ln -s ../../src_refactory/node_modules && ln -s ../../src_refactory/package.json && ln -s ../../src_refactory/tsconfig.json" }, "keywords": [], "author": "", "license": "ISC", "description": "", "dependencies": { + "@types/crypto-js": "^4.2.2", "chalk": "^5.3.0", + "crypto-js": "^4.2.0", "dotenv": "^16.4.5", "fastify": "^4.28.1", + "joi": "^17.13.3", "lodash": "^4.17.21", - "luxon": "^3.4.4", + "luxon": "^3.5.0", "pg": "^8.12.0", + "reflect-metadata": "^0.2.2", + "typeorm": "^0.3.20", "typescript": "^5.5.4" }, "devDependencies": { "@types/lodash": "^4.17.7", "@types/luxon": "^3.4.2", + "@types/node": "^22.5.0", "@types/pg": "^8.11.6", - "@types/node": "^22.0.0", "@types/pg-pool": "^2.0.6", "tsx": "^4.16.2" } diff --git a/src_refactory/server/fastify/index.ts b/src_refactory/server/fastify/index.ts new file mode 100644 index 0000000..723cd56 --- /dev/null +++ b/src_refactory/server/fastify/index.ts @@ -0,0 +1,187 @@ +import { env, exit, platform } from "process"; +import fs from "fs"; +import Fastify from 'fastify'; +import { DateTime } from 'luxon'; +import path from "path"; +import _ from "lodash"; + +import { ApiConflict, ApiErrorGeneric, ApiNotFound, ApiUnauthorized } from "../../modules/api"; + +import { IController } from "./interfaces/IController"; + +import Logger from '../../modules/logger'; +const logger = new Logger("server-fastify"); + +const __dirname = path.resolve(); + +//settings +const fastify = Fastify(); + +//init +async function init(pathControllers = "controllers"){ + logger.info("Starting service fastify..."); + + //controllers + logger.debug("Starting load controllers"); + await loadControllers(pathControllers); + logger.debug("Finish load all controllers"); + + //server + let connection = ""; + try{ + connection = await fastify.listen({ + port: _.isNil(env.SERVER_PORT)? 3001 : parseInt(env.SERVER_PORT), + host: env.SERVER_PORT || "127.0.0.1", + }) + }catch(err){ + logger.fatal(`Stop service fastify reason:`, err); + exit(1); + } + + logger.info(`Connection established ${connection}`); +} + +//load routers +async function loadControllers(path_controllers: string){ + const listFileControllers: Array = []; + const basePathController = path.join(__dirname, path_controllers); + + //get list folder inside controllers + const listControllers = fs.readdirSync(basePathController).map((singlePath) => path.join(path_controllers, singlePath)); + + //get index every controller + for (const controller of listControllers) { + try{ + listFileControllers.push(...(fs.readdirSync(controller)).filter((file) => file === "index.ts").map((singlePath) => path.join(controller, singlePath))); + }catch(err){ + logger.error("Failed load controllers reason:", err); + } + } + + logger.debug("List controllers available:", listFileControllers.join(', ')) + + let success = 0; + for (const fileController of listFileControllers) { + let controller: IController; + + try{ + controller = (await import(path.join(platform === "win32"? 'file://' : '', __dirname, fileController))).default; + }catch(err){ + logger.error("Failed load", `"${fileController}", details:`, err); + continue; + } + + loadRoutes(controller, fileController); + + success++; + } + + logger.debug('Total controllers loaded', success); +} + +function loadRoutes(controller: IController, nameController: string){ + logger.debug("Routes", `(${Object.keys(controller.routes).length})`, "available"); + + let success = 0; + for (const route in controller.routes) { + const pathRoute = path.join(controller.pathBaseController, controller.routes[route].url); + try{ + fastify.route({ + url: pathRoute, + method: controller.routes[route].method, + handler: controller.routes[route].hander, + validatorCompiler: ({ schema }) => { + //@ts-ignore + return data => schema.validate(data) + }, + ...controller.routes[route].options + }) + }catch(err){ + logger.error("Failed load route", `"${pathRoute}" details:`, err); + continue; + } + + success++; + } + + logger.debug('Loaded', `(${success}) routes from`, nameController); +} + +//logging +fastify.addHook("onRequest", (req, replay, next) => { + //@ts-ignores + replay.startTime = DateTime.now().toISO(); + + next(); +}) + +fastify.addHook("onResponse", (req, replay, next) => { + //@ts-ignore + const time = DateTime.fromISO(replay.startTime); + + let bodyJson = {}; + + if(env.LOG_LEVEL === "debug"){ + const body = req.body; + + if(!_.isObject(body)){ + try{ + bodyJson = JSON.parse(body as string); + }catch{ + //ignore + } + }else{ + bodyJson = body; + } + } + + const message = [req.raw.method, req.url.split('?')[0], JSON.stringify(req.query), JSON.stringify(bodyJson), replay.statusCode, `(${DateTime.now().diff(time).toMillis()} ms)`]; + + if(replay.statusCode === 500){ + logger.error(...message); + }else if(replay.statusCode !== 200){ + logger.warn(...message); + }else{ + logger.info(...message); + } + + next(); +}) + +fastify.setErrorHandler((error, request, replay) => { + const message = { + error: error.name, + message: error.message + } + + if(error instanceof ApiConflict){ + return replay.status(409).send({ + ...message, + statusCode: 409 + }) + }else if(error instanceof ApiNotFound){ + return replay.status(404).send({ + ...message, + statusCode: 404 + }); + }else if(error instanceof ApiUnauthorized){ + return replay.status(401).send({ + ...message, + statusCode: 401 + }); + }else if(error instanceof ApiErrorGeneric){ + return replay.status(500).send({ + ...message, + statusCode: 500 + }); + }else{ + logger.error(error); + return error; + } +}) + +export default fastify; + +export { + init +} \ No newline at end of file diff --git a/src_refactory/server/fastify/interfaces/IController.ts b/src_refactory/server/fastify/interfaces/IController.ts new file mode 100644 index 0000000..e3ecb32 --- /dev/null +++ b/src_refactory/server/fastify/interfaces/IController.ts @@ -0,0 +1,6 @@ +import { IRoute } from "./IRoute"; + +export interface IController { + routes: {[key: string]: IRoute}, + pathBaseController: string +} \ No newline at end of file diff --git a/src_refactory/server/fastify/interfaces/IRoute.ts b/src_refactory/server/fastify/interfaces/IRoute.ts new file mode 100644 index 0000000..fea8345 --- /dev/null +++ b/src_refactory/server/fastify/interfaces/IRoute.ts @@ -0,0 +1,8 @@ +import { RouteHandlerMethod, RouteShorthandOptions, HTTPMethods } from "fastify"; + +export interface IRoute { + url: string, + method: HTTPMethods, + options?: RouteShorthandOptions, + hander: RouteHandlerMethod +} \ No newline at end of file diff --git a/src_refactory/server/postgres/index.ts b/src_refactory/server/postgres/index.ts new file mode 100644 index 0000000..37d6cc0 --- /dev/null +++ b/src_refactory/server/postgres/index.ts @@ -0,0 +1,44 @@ +import { DataSource } from "typeorm"; +import _ from "lodash"; + +import Logger from "../../modules/logger"; +const logger = new Logger("pg"); + +import { Account } from "../../domain/models/Account"; + +let pg: DataSource; + +async function init({ + address = "localhost", + port = "5432", + username = "root", + password = "root", + database = "animemanga" +}){ + pg = new DataSource({ + type: "postgres", + host: address, + port: parseInt(port), + username, + password, + database, + entities: [Account], + synchronize: process.env.NODE_ENV === 'dev', + connectTimeoutMS: 5000 + }); + + try{ + pg = await pg.initialize(); + }catch(err){ + logger.error('Error initialize postgres, reason:', err); + return; + } + + logger.debug("String connection:", `${address}:${port}`); + logger.info("Connected to pg!") +} + +export { + pg, + init +} \ No newline at end of file diff --git a/src_refactory/server/postgres/interfaces/IConfigPostgres.ts b/src_refactory/server/postgres/interfaces/IConfigPostgres.ts new file mode 100644 index 0000000..c268f78 --- /dev/null +++ b/src_refactory/server/postgres/interfaces/IConfigPostgres.ts @@ -0,0 +1,7 @@ +export interface IConfigPostgres { + address: string, + port: string + username: string, + password: string, + database: string +} \ No newline at end of file diff --git a/src_refactory/tsconfig.json b/src_refactory/tsconfig.json index 6d41c9f..aa4bae3 100644 --- a/src_refactory/tsconfig.json +++ b/src_refactory/tsconfig.json @@ -2,6 +2,9 @@ "compilerOptions": { "moduleResolution": "Bundler", "module": "ESNext", - "target": "ESNext" + "target": "ESNext", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true } } \ No newline at end of file diff --git a/src_refactory/utils/AccountUtils.ts b/src_refactory/utils/AccountUtils.ts new file mode 100644 index 0000000..5a6c411 --- /dev/null +++ b/src_refactory/utils/AccountUtils.ts @@ -0,0 +1,9 @@ +import CryptoJS from "crypto-js"; + +function hashPassword(password: string){ + return CryptoJS.SHA256(password).toString() +} + +export { + hashPassword +} \ No newline at end of file diff --git a/src_refactory/utils/utils.ts b/src_refactory/utils/utils.ts new file mode 100644 index 0000000..eb79693 --- /dev/null +++ b/src_refactory/utils/utils.ts @@ -0,0 +1,16 @@ +import _ from "lodash"; + +function objectAssign(data: any, Idata: any){ + let newData = {}; + for (const key in Idata) { + if(_.isObject(data)){ + newData[Idata[key]] = data[Idata[key]]; + } + } + + return newData as T; +} + +export { + objectAssign +} \ No newline at end of file From ff51beccebac6b15673198c2660ef13b5a075b9b Mon Sep 17 00:00:00 2001 From: cesxhin Date: Fri, 30 Aug 2024 21:39:02 +0200 Subject: [PATCH 06/21] complete basic controller account --- references | 2 +- .../repositories/IAccountRepository.ts | 2 +- .../interfaces/services/IAccountService.ts | 2 +- .../repositories/AccountRepository.ts | 42 +++++++++++++++---- .../applications/services/AccountService.ts | 34 +++++++++++---- .../controllers/account/routes/deleteRoute.ts | 24 +++++++++++ .../controllers/account/routes/index.ts | 4 +- .../controllers/account/routes/updateRoute.ts | 29 +++++++++++++ .../domain/interfaces/DTOs/IAccountDTO.ts | 4 +- .../domain/interfaces/models/IAccount.ts | 8 ++-- src_refactory/domain/models/Account.ts | 5 ++- 11 files changed, 130 insertions(+), 26 deletions(-) create mode 100644 src_refactory/controllers/account/routes/deleteRoute.ts create mode 100644 src_refactory/controllers/account/routes/updateRoute.ts diff --git a/references b/references index 0968f3f..2506e62 160000 --- a/references +++ b/references @@ -1 +1 @@ -Subproject commit 0968f3f57b805713ed523125eb97bf129c8add82 +Subproject commit 2506e62a45b3fc058b9eee925374a25a73a9bdce diff --git a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts index 7e9c589..e7c8bde 100644 --- a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts +++ b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts @@ -11,7 +11,7 @@ export default interface IAccountRepository { //put createAccount(data: IAccount): Promise; //post - updateAccount(data: IAccount): Promise; + updateAccount(username: string, data: Partial): Promise; //delete deleteAccount(username: string): void; } \ No newline at end of file diff --git a/src_refactory/applications/interfaces/services/IAccountService.ts b/src_refactory/applications/interfaces/services/IAccountService.ts index 4afb655..7de0589 100644 --- a/src_refactory/applications/interfaces/services/IAccountService.ts +++ b/src_refactory/applications/interfaces/services/IAccountService.ts @@ -8,7 +8,7 @@ export default interface IAccountService { //put createAccount(data: IAccount): Promise; //post - updateAccount(data: IAccount): Promise; + updateAccount(username: string, data: Partial): Promise; //delete deleteAccount(username: string): void; } \ No newline at end of file diff --git a/src_refactory/applications/repositories/AccountRepository.ts b/src_refactory/applications/repositories/AccountRepository.ts index 8c83591..0de4f6f 100644 --- a/src_refactory/applications/repositories/AccountRepository.ts +++ b/src_refactory/applications/repositories/AccountRepository.ts @@ -1,4 +1,4 @@ -import { Like } from "typeorm"; +import { DeleteResult, Like, UpdateResult } from "typeorm"; import {pg} from "../../server/postgres"; import { ApiErrorGeneric, ApiNotFound } from "../../modules/api"; @@ -14,11 +14,12 @@ const logger = new Logger("account-db"); export default class AccountRepository implements IAccountRepository { connectionRepository = pg.getRepository(Account); + //get async findFromUsername(username: string): Promise { let rs: Account | null = null; try{ - rs = await this.connectionRepository.findOneBy({ [IAccountEnv.USERNAME]: Like(username) }); + rs = await this.connectionRepository.findOneBy({ [IAccountEnv.USERNAME]: username }); }catch(err){ logger.error("Failed exec query findFromUsername, details:", err); throw new ApiErrorGeneric(err); @@ -30,8 +31,11 @@ export default class AccountRepository implements IAccountRepository { return rs; } - + + //post async createAccount(data: IAccount): Promise { + data[IAccountEnv.USERNAME] = data[IAccountEnv.USERNAME].toLowerCase(); + try{ await this.connectionRepository.insert(data) }catch(err){ @@ -41,11 +45,35 @@ export default class AccountRepository implements IAccountRepository { return data; } - updateAccount(data: IAccount): Promise { - throw new Error("Method not implemented."); + + //put + async updateAccount(username: string, data: IAccount): Promise { + let rs: UpdateResult; + try{ + rs = await this.connectionRepository.update({ [IAccountEnv.USERNAME]: username }, data); + }catch(err){ + logger.error("Failed exec query updateAccount, details:", err); + throw new ApiErrorGeneric(err); + } + + if(rs.affected <= 0){ + throw new ApiNotFound(`Cannot update information of ${username}`); + } } - deleteAccount(username: string): void { - throw new Error("Method not implemented."); + + //delete + async deleteAccount(username: string): Promise { + let rs: DeleteResult; + try{ + rs = await this.connectionRepository.delete({ [IAccountEnv.USERNAME]: username }); + }catch(err){ + logger.error("Failed exec query updateAccount, details:", err); + throw new ApiErrorGeneric(err); + } + + if(rs.affected <= 0){ + throw new ApiNotFound(`Cannot delete ${username}`); + } } } \ No newline at end of file diff --git a/src_refactory/applications/services/AccountService.ts b/src_refactory/applications/services/AccountService.ts index 61c9176..7a6f61f 100644 --- a/src_refactory/applications/services/AccountService.ts +++ b/src_refactory/applications/services/AccountService.ts @@ -1,3 +1,5 @@ +import _ from "lodash"; + import IAccountService from "../interfaces/services/IAccountService"; import { IAccountDTO, IAccountDTOEnv } from "../../domain/interfaces/DTOs/IAccountDTO"; import { IAccount, IAccountEnv } from "../../domain/interfaces/models/IAccount"; @@ -13,6 +15,14 @@ import { Account } from "../../domain/models/Account"; export class AccountService implements IAccountService { accountRepository = new AccountRepository(); + //get + async findFromUsername(username: string): Promise { + const user = await this.accountRepository.findFromUsername(username); + + return objectAssign(user, IAccountDTOEnv); + } + + //post async login(username: string, password: string): Promise { let user: Account; @@ -32,11 +42,6 @@ export class AccountService implements IAccountService { return objectAssign(user, IAccountDTOEnv); } - async findFromUsername(username: string): Promise { - const user = await this.accountRepository.findFromUsername(username); - - return objectAssign(user, IAccountDTOEnv); - } async createAccount(data: IAccount): Promise { const username = data[IAccountEnv.USERNAME]; @@ -55,10 +60,21 @@ export class AccountService implements IAccountService { throw new ApiConflict(`This username already used ${username}`); } - updateAccount(data: IAccount): Promise { - throw new Error("Method not implemented."); + + //update + async updateAccount(username: string, data: IAccount): Promise { + const user = await this.accountRepository.findFromUsername(username); + + await this.accountRepository.updateAccount(username, data); + + //update information + const newUser = _.merge(user, data); + + return objectAssign(newUser, IAccountDTOEnv); } - deleteAccount(username: string): void { - throw new Error("Method not implemented."); + + //delete + async deleteAccount(username: string): Promise { + await this.accountRepository.deleteAccount(username); } } \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/deleteRoute.ts b/src_refactory/controllers/account/routes/deleteRoute.ts new file mode 100644 index 0000000..e81d688 --- /dev/null +++ b/src_refactory/controllers/account/routes/deleteRoute.ts @@ -0,0 +1,24 @@ +import Joi from "joi"; + +import { IRoute } from "../../../server/fastify/interfaces/IRoute"; +import { IAccountEnv } from "../../../domain/interfaces/models/IAccount"; + +import { AccountService } from "../../../applications/services/AccountService"; +const accountService = new AccountService(); + +export default { + method: "DELETE", + url: "/delete", + hander: async function (request, replay){ + const {username} = request.query as {username: string}; + + return accountService.deleteAccount(username); + }, + options: { + schema: { + querystring: Joi.object({ + [IAccountEnv.USERNAME]: Joi.string().required() + }) + } + } +} as IRoute \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/index.ts b/src_refactory/controllers/account/routes/index.ts index 7dc277a..9a1e7e3 100644 --- a/src_refactory/controllers/account/routes/index.ts +++ b/src_refactory/controllers/account/routes/index.ts @@ -1,2 +1,4 @@ export {default as createRoute} from "./createRoute"; -export {default as findRoute} from "./findRoute"; \ No newline at end of file +export {default as findRoute} from "./findRoute"; +export {default as updateRoute} from "./updateRoute"; +export {default as deleteRoute} from "./deleteRoute"; \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/updateRoute.ts b/src_refactory/controllers/account/routes/updateRoute.ts new file mode 100644 index 0000000..643f04d --- /dev/null +++ b/src_refactory/controllers/account/routes/updateRoute.ts @@ -0,0 +1,29 @@ +import Joi from "joi"; + +import { IRoute } from "../../../server/fastify/interfaces/IRoute"; +import { IAccount, IAccountEnv } from "../../../domain/interfaces/models/IAccount"; + +import { AccountService } from "../../../applications/services/AccountService"; +const accountService = new AccountService(); + +export default { + method: "PUT", + url: "/update", + hander: async function (request, replay){ + const {username} = request.query as {username: string}; + const account = request.body as IAccount; + + return accountService.updateAccount(username, account); + }, + options: { + schema: { + querystring: Joi.object({ + [IAccountEnv.USERNAME]: Joi.string().required() + }), + body: Joi.object({ + [IAccountEnv.CHANGE_PASSWORD]: Joi.boolean().optional(), + [IAccountEnv.PROFILE]: Joi.string().optional(), + }) + } + } +} as IRoute \ No newline at end of file diff --git a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts index 2c11bc6..39e4fbb 100644 --- a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts +++ b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts @@ -3,7 +3,7 @@ export enum IAccountDTOEnv { LAST_ACCESS = "last_access", CHANGE_PASSWORD = "change_password", EXPIRE_PASSWORD = "expire_password", - AVATAR = "avatr" + PROFILE = "profile" } export interface IAccountDTO { @@ -11,5 +11,5 @@ export interface IAccountDTO { [IAccountDTOEnv.LAST_ACCESS]: Date, [IAccountDTOEnv.CHANGE_PASSWORD]: Date, [IAccountDTOEnv.EXPIRE_PASSWORD]: Date, - [IAccountDTOEnv.AVATAR]: string + [IAccountDTOEnv.PROFILE]: string } \ No newline at end of file diff --git a/src_refactory/domain/interfaces/models/IAccount.ts b/src_refactory/domain/interfaces/models/IAccount.ts index 11e70a4..3bf31a3 100644 --- a/src_refactory/domain/interfaces/models/IAccount.ts +++ b/src_refactory/domain/interfaces/models/IAccount.ts @@ -3,13 +3,15 @@ export enum IAccountEnv { PASSWORD = "password", LAST_ACCESS = "last_access", CHANGE_PASSWORD = "change_password", - EXPIRE_PASSWORD = "expire_password" + EXPIRE_PASSWORD = "expire_password", + PROFILE = "profile" } export interface IAccount { [IAccountEnv.USERNAME]: string, [IAccountEnv.PASSWORD]: string, - [IAccountEnv.LAST_ACCESS]: Date, + [IAccountEnv.LAST_ACCESS]: Date | null, [IAccountEnv.CHANGE_PASSWORD]: boolean, - [IAccountEnv.EXPIRE_PASSWORD]: Date + [IAccountEnv.EXPIRE_PASSWORD]: Date, + [IAccountEnv.PROFILE]: string } \ No newline at end of file diff --git a/src_refactory/domain/models/Account.ts b/src_refactory/domain/models/Account.ts index 5c740b1..a9fe4c4 100644 --- a/src_refactory/domain/models/Account.ts +++ b/src_refactory/domain/models/Account.ts @@ -11,11 +11,14 @@ export class Account implements IAccount{ [IAccountEnv.PASSWORD]: string; @Column({type: "timestamptz", nullable: true, default: null}) - [IAccountEnv.LAST_ACCESS]: Date; + [IAccountEnv.LAST_ACCESS]: Date | null; @Column({type: "boolean", default: false}) [IAccountEnv.CHANGE_PASSWORD]: boolean; @Column({type: "timestamptz", default: DateTime.now().plus({month: 1})}) [IAccountEnv.EXPIRE_PASSWORD]: Date; + + @Column({type: "text", default: null, nullable: true}) + [IAccountEnv.PROFILE]: string; } \ No newline at end of file From 4ceb0663ca5434cfa294f3115ac3ead956f9a551 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Mon, 16 Sep 2024 21:35:28 +0200 Subject: [PATCH 07/21] Implemetation validation schema and add controller request --- .../repositories/IAccountRepository.ts | 11 +- .../repositories/IRequestRepository.ts | 16 ++ .../generic/IConnectionRepository.ts | 5 + .../interfaces/services/IAccountService.ts | 2 +- .../interfaces/services/IRequestService.ts | 13 ++ .../repositories/AccountRepository.ts | 14 +- .../repositories/RequestRepository.ts | 72 +++++++ .../applications/services/AccountService.ts | 18 +- .../applications/services/RequestService.ts | 77 +++++++ src_refactory/controllers/account/create.ts | 25 +++ src_refactory/controllers/account/delete.ts | 29 +++ src_refactory/controllers/account/find.ts | 27 +++ src_refactory/controllers/account/index.ts | 12 -- .../controllers/account/routes/createRoute.ts | 27 --- .../controllers/account/routes/deleteRoute.ts | 24 --- .../controllers/account/routes/findRoute.ts | 25 --- .../controllers/account/routes/index.ts | 4 - .../controllers/account/routes/updateRoute.ts | 29 --- src_refactory/controllers/account/update.ts | 30 +++ src_refactory/controllers/request/action.ts | 26 +++ src_refactory/controllers/request/create.ts | 25 +++ src_refactory/controllers/request/list.ts | 24 +++ .../domain/interfaces/DTOs/IAccountDTO.ts | 18 +- .../domain/interfaces/DTOs/IRequestDTO.ts | 15 ++ .../domain/interfaces/models/IAccount.ts | 20 +- .../domain/interfaces/models/IRequest.ts | 15 ++ src_refactory/domain/models/Account.ts | 5 +- src_refactory/domain/models/Request.ts | 16 ++ src_refactory/modules/api.ts | 9 +- src_refactory/package.json | 5 + src_refactory/schemas/accountSchema.ts | 45 +++++ .../schemas/generic/genericSchema.ts | 25 +++ .../schemas/generic/paginationSchema.ts | 17 ++ src_refactory/schemas/requestSchema.ts | 48 +++++ src_refactory/server/fastify/index.ts | 188 ++++++++++++++---- src_refactory/server/postgres/index.ts | 4 +- src_refactory/utils/schemaUtils.ts | 11 + 37 files changed, 767 insertions(+), 209 deletions(-) create mode 100644 src_refactory/applications/interfaces/repositories/IRequestRepository.ts create mode 100644 src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts create mode 100644 src_refactory/applications/interfaces/services/IRequestService.ts create mode 100644 src_refactory/applications/repositories/RequestRepository.ts create mode 100644 src_refactory/applications/services/RequestService.ts create mode 100644 src_refactory/controllers/account/create.ts create mode 100644 src_refactory/controllers/account/delete.ts create mode 100644 src_refactory/controllers/account/find.ts delete mode 100644 src_refactory/controllers/account/index.ts delete mode 100644 src_refactory/controllers/account/routes/createRoute.ts delete mode 100644 src_refactory/controllers/account/routes/deleteRoute.ts delete mode 100644 src_refactory/controllers/account/routes/findRoute.ts delete mode 100644 src_refactory/controllers/account/routes/index.ts delete mode 100644 src_refactory/controllers/account/routes/updateRoute.ts create mode 100644 src_refactory/controllers/account/update.ts create mode 100644 src_refactory/controllers/request/action.ts create mode 100644 src_refactory/controllers/request/create.ts create mode 100644 src_refactory/controllers/request/list.ts create mode 100644 src_refactory/domain/interfaces/DTOs/IRequestDTO.ts create mode 100644 src_refactory/domain/interfaces/models/IRequest.ts create mode 100644 src_refactory/domain/models/Request.ts create mode 100644 src_refactory/schemas/accountSchema.ts create mode 100644 src_refactory/schemas/generic/genericSchema.ts create mode 100644 src_refactory/schemas/generic/paginationSchema.ts create mode 100644 src_refactory/schemas/requestSchema.ts create mode 100644 src_refactory/utils/schemaUtils.ts diff --git a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts index e7c8bde..9e242d9 100644 --- a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts +++ b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts @@ -1,15 +1,12 @@ -import { Repository } from "typeorm"; - import { Account } from "../../../domain/models/Account"; import { IAccount } from "../../../domain/interfaces/models/IAccount"; +import IConnectionRepository from "./generic/IConnectionRepository"; -export default interface IAccountRepository { - connectionRepository: Repository; - +export default interface IAccountRepository extends IConnectionRepository{ //get - findFromUsername(username: string): Promise; + findFromUsername(username: string): Promise; //put - createAccount(data: IAccount): Promise; + createAccount(data: IAccount): Promise; //post updateAccount(username: string, data: Partial): Promise; //delete diff --git a/src_refactory/applications/interfaces/repositories/IRequestRepository.ts b/src_refactory/applications/interfaces/repositories/IRequestRepository.ts new file mode 100644 index 0000000..ffbe6ef --- /dev/null +++ b/src_refactory/applications/interfaces/repositories/IRequestRepository.ts @@ -0,0 +1,16 @@ +import { IRequest } from "../../../domain/interfaces/models/IRequest" +import { Request } from "../../../domain/models/Request"; +import IConnectionRepository from "./generic/IConnectionRepository"; + +export default interface IRequestRepository extends IConnectionRepository { + //get + findByRequest(request_from: string, request_to: string): Promise + listPaginated(request_from: string, skip: number, length: number): Promise> + countTotalFromRequestFrom(request_from: string): Promise + + //put + create(data: IRequest): Promise + + //delete + delete(request_from: string, request_to: string): Promise +} \ No newline at end of file diff --git a/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts b/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts new file mode 100644 index 0000000..e61df93 --- /dev/null +++ b/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts @@ -0,0 +1,5 @@ +import { Repository } from "typeorm"; + +export default interface IConnectionRepository{ + connectionRepository: Repository; +} \ No newline at end of file diff --git a/src_refactory/applications/interfaces/services/IAccountService.ts b/src_refactory/applications/interfaces/services/IAccountService.ts index 7de0589..41e43f9 100644 --- a/src_refactory/applications/interfaces/services/IAccountService.ts +++ b/src_refactory/applications/interfaces/services/IAccountService.ts @@ -6,7 +6,7 @@ export default interface IAccountService { findFromUsername(username: string): Promise; login(username: string, password: string): Promise; //put - createAccount(data: IAccount): Promise; + createAccount(data: Partial): Promise; //post updateAccount(username: string, data: Partial): Promise; //delete diff --git a/src_refactory/applications/interfaces/services/IRequestService.ts b/src_refactory/applications/interfaces/services/IRequestService.ts new file mode 100644 index 0000000..a4eea74 --- /dev/null +++ b/src_refactory/applications/interfaces/services/IRequestService.ts @@ -0,0 +1,13 @@ +import { IRequest } from "../../../domain/interfaces/models/IRequest" +import { staticReturnPaginatedRequest } from "../../../schemas/requestSchema" + +export default interface IRequestService { + //get + listPaginated(request_from: string, skip: number, length: number): Promise + + //put + create(data: Partial): Promise + + //post + action(request_from: string, request_to: string, accept: boolean): Promise +} \ No newline at end of file diff --git a/src_refactory/applications/repositories/AccountRepository.ts b/src_refactory/applications/repositories/AccountRepository.ts index 0de4f6f..e5e5edf 100644 --- a/src_refactory/applications/repositories/AccountRepository.ts +++ b/src_refactory/applications/repositories/AccountRepository.ts @@ -1,4 +1,4 @@ -import { DeleteResult, Like, UpdateResult } from "typeorm"; +import { DeleteResult, UpdateResult } from "typeorm"; import {pg} from "../../server/postgres"; import { ApiErrorGeneric, ApiNotFound } from "../../modules/api"; @@ -12,11 +12,11 @@ import Logger from "../../modules/logger"; const logger = new Logger("account-db"); export default class AccountRepository implements IAccountRepository { - connectionRepository = pg.getRepository(Account); + connectionRepository = pg.getRepository(Account); //get - async findFromUsername(username: string): Promise { - let rs: Account | null = null; + async findFromUsername(username: string): Promise { + let rs: IAccount | null = null; try{ rs = await this.connectionRepository.findOneBy({ [IAccountEnv.USERNAME]: username }); @@ -33,7 +33,7 @@ export default class AccountRepository implements IAccountRepository { } //post - async createAccount(data: IAccount): Promise { + async createAccount(data: Partial): Promise { data[IAccountEnv.USERNAME] = data[IAccountEnv.USERNAME].toLowerCase(); try{ @@ -42,12 +42,10 @@ export default class AccountRepository implements IAccountRepository { logger.error("Failed exec query createAccount, details:", err); throw new ApiErrorGeneric(err); } - - return data; } //put - async updateAccount(username: string, data: IAccount): Promise { + async updateAccount(username: string, data: Partial): Promise { let rs: UpdateResult; try{ rs = await this.connectionRepository.update({ [IAccountEnv.USERNAME]: username }, data); diff --git a/src_refactory/applications/repositories/RequestRepository.ts b/src_refactory/applications/repositories/RequestRepository.ts new file mode 100644 index 0000000..cf80a64 --- /dev/null +++ b/src_refactory/applications/repositories/RequestRepository.ts @@ -0,0 +1,72 @@ +import { DeleteResult } from "typeorm"; + +import {pg} from "../../server/postgres"; +import { ApiErrorGeneric, ApiNotFound } from "../../modules/api"; + +import IRequestRepository from "../interfaces/repositories/IRequestRepository"; +import { IRequest, IRequestEnv } from "../../domain/interfaces/models/IRequest"; + +import { Request } from "../../domain/models/Request"; + +import Logger from "../../modules/logger"; +const logger = new Logger("request-db"); + +export default class RequestRepository implements IRequestRepository { + connectionRepository = pg.getRepository(Request); + + async findByRequest(request_from: string, request_to: string): Promise { + let request: IRequest; + try{ + request = await this.connectionRepository.findOneBy({ [IRequestEnv.REQUEST_FROM]: request_from, [IRequestEnv.REQUEST_TO]: request_to }); + }catch(err){ + logger.error("Failed exec query findByTarget, details:", err); + throw new ApiErrorGeneric(err); + } + + if(request === null){ + throw new ApiNotFound(`Not found request with request_from: "${request_from}" request_to: "${request_to}"`); + } + + return request; + } + async create(data: Partial): Promise { + try{ + await this.connectionRepository.insert(data); + }catch(err){ + logger.error("Failed exec query create, details:", err); + throw new ApiErrorGeneric(err); + } + } + async delete(request_from: string, request_to: string): Promise { + let rs: DeleteResult + try{ + rs = await this.connectionRepository.delete({[IRequestEnv.REQUEST_FROM]: request_from, [IRequestEnv.REQUEST_TO]: request_to}); + }catch(err){ + logger.error("Failed exec query delete, details:", err); + throw new ApiErrorGeneric(err); + } + + if(rs.affected <= 0){ + throw new ApiNotFound(`Cannot delete request with request_from: "${request_from}" request_to: "${request_to}"`) + } + } + async listPaginated(request_from: string, skip: number = 0, length: number = 10): Promise> { + let rs: Array = []; + try{ + rs = await this.connectionRepository.find({where: {[IRequestEnv.REQUEST_FROM]: request_from}, order: {[IRequestEnv.REQUEST_TIME]: "ASC"}, skip, take: length}); + }catch(err){ + logger.error("Failed exec query listPaginated, details:", err); + throw new ApiErrorGeneric(err); + } + + return rs; + } + async countTotalFromRequestFrom(request_from: string): Promise { + try{ + return await this.connectionRepository.count({where: {[IRequestEnv.REQUEST_FROM]: request_from}}); + }catch(err){ + logger.error("Failed exec query countTotal, details:", err); + throw new ApiErrorGeneric(err); + } + } +} \ No newline at end of file diff --git a/src_refactory/applications/services/AccountService.ts b/src_refactory/applications/services/AccountService.ts index 7a6f61f..ac0e46e 100644 --- a/src_refactory/applications/services/AccountService.ts +++ b/src_refactory/applications/services/AccountService.ts @@ -10,7 +10,6 @@ import {hashPassword} from "../../utils/AccountUtils"; import { ApiConflict, ApiNotFound, ApiUnauthorized } from "../../modules/api"; import { objectAssign } from "../../utils/utils"; -import { Account } from "../../domain/models/Account"; export class AccountService implements IAccountService { accountRepository = new AccountRepository(); @@ -19,12 +18,12 @@ export class AccountService implements IAccountService { async findFromUsername(username: string): Promise { const user = await this.accountRepository.findFromUsername(username); - return objectAssign(user, IAccountDTOEnv); + return objectAssign(user, IAccountDTOEnv); } //post async login(username: string, password: string): Promise { - let user: Account; + let user: IAccount; try{ user = await this.accountRepository.findFromUsername(username); @@ -40,9 +39,9 @@ export class AccountService implements IAccountService { throw new ApiUnauthorized("Username/Password wrong"); } - return objectAssign(user, IAccountDTOEnv); + return objectAssign(user, IAccountDTOEnv); } - async createAccount(data: IAccount): Promise { + async createAccount(data: Partial): Promise { const username = data[IAccountEnv.USERNAME]; try{ @@ -50,9 +49,10 @@ export class AccountService implements IAccountService { }catch(e){ if(e instanceof ApiNotFound){ data[IAccountEnv.PASSWORD] = hashPassword(data[IAccountEnv.PASSWORD]); - const createdAccount = await this.accountRepository.createAccount(data); + await this.accountRepository.createAccount(data); - return objectAssign(createdAccount, IAccountDTOEnv); + const user = await this.accountRepository.findFromUsername(data[IAccountEnv.USERNAME]); + return objectAssign(user, IAccountDTOEnv); }else{ throw new e; } @@ -62,7 +62,7 @@ export class AccountService implements IAccountService { } //update - async updateAccount(username: string, data: IAccount): Promise { + async updateAccount(username: string, data: Partial): Promise { const user = await this.accountRepository.findFromUsername(username); await this.accountRepository.updateAccount(username, data); @@ -70,7 +70,7 @@ export class AccountService implements IAccountService { //update information const newUser = _.merge(user, data); - return objectAssign(newUser, IAccountDTOEnv); + return objectAssign(newUser, IAccountDTOEnv); } //delete diff --git a/src_refactory/applications/services/RequestService.ts b/src_refactory/applications/services/RequestService.ts new file mode 100644 index 0000000..2e9b728 --- /dev/null +++ b/src_refactory/applications/services/RequestService.ts @@ -0,0 +1,77 @@ +import _ from "lodash"; + +import { ApiBadRequest, ApiConflict, ApiNotFound } from "../../modules/api"; + +import { objectAssign } from "../../utils/utils"; + +import { IRequestDTO, IRequestDTOEnv } from "../../domain/interfaces/DTOs/IRequestDTO"; +import { IRequest, IRequestEnv } from "../../domain/interfaces/models/IRequest"; + +import IRequestService from "../interfaces/services/IRequestService"; +import RequestRepository from "../repositories/RequestRepository"; +import async from "async"; +import { staticReturnPaginatedRequest } from "../../schemas/requestSchema"; +import AccountRepository from "../repositories/AccountRepository"; + +export class RequestService implements IRequestService { + requestRepository = new RequestRepository(); + accountRepository = new AccountRepository(); + + async create(data: Partial): Promise { + if(data[IRequestEnv.REQUEST_FROM].toLowerCase() === data[IRequestEnv.REQUEST_TO].toLowerCase()){ + throw new ApiBadRequest(`${IRequestEnv.REQUEST_FROM} cannot be same ${IRequestEnv.REQUEST_TO}`); + } + + const {findRequest, findRequestTO} = await async.parallel({ + findRequest: async () => { + try{ + await this.requestRepository.findByRequest(data[IRequestEnv.REQUEST_FROM], data[IRequestEnv.REQUEST_TO]); + }catch(err){ + if(err instanceof ApiNotFound){ + return false; + }else{ + throw new err; + } + } + + return true; + }, + findRequestTO: async () => { + try{ + await this.accountRepository.findFromUsername(data[IRequestEnv.REQUEST_TO]); + }catch(err){ + if(err instanceof ApiNotFound){ + return false; + }else{ + throw new err; + } + } + + return true; + } + }) + + if(!findRequest && findRequestTO){ + return await this.requestRepository.create(data); + }else if(!findRequestTO){ + throw new ApiNotFound(`The user "${data[IRequestEnv.REQUEST_TO]}" not exist!`); + }else{ + throw new ApiConflict("The request to become a friend has already been sent"); + } + } + action(request_from: string, request_to: string, accept: boolean): Promise { + //todo table friends + throw new Error("Method not implemented."); + } + async listPaginated(request_from: string, skip: number, length: number): Promise { + const {count, list} = await async.parallel, count: number}>({ + list: async () => (await this.requestRepository.listPaginated(request_from, skip, length)).map((reqeust) => objectAssign(reqeust, IRequestDTOEnv)), + count: async () => await this.requestRepository.countTotalFromRequestFrom(request_from) + }); + + return { + list, + max_count: count + } + } +} \ No newline at end of file diff --git a/src_refactory/controllers/account/create.ts b/src_refactory/controllers/account/create.ts new file mode 100644 index 0000000..cf90b17 --- /dev/null +++ b/src_refactory/controllers/account/create.ts @@ -0,0 +1,25 @@ +import { RouteShorthandOptions } from "fastify"; + +import { PATH_BASE_CONTROLLER, SCHEMA_CREATE_ACCOUNT, SCHEMA_RETURN_ACCOUNT, staticCreateAccount } from "../../schemas/accountSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import fastify from "../../server/fastify"; +import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; + +const accountService = new AccountService(); + +const options: RouteShorthandOptions = { + schema: { + body: { $ref: SCHEMA_CREATE_ACCOUNT }, + response: { + 200: { $ref: SCHEMA_RETURN_ACCOUNT }, + 500: { $ref: SCHEMA_ERROR }, + 401: { $ref: SCHEMA_ERROR }, + } + } +} + +fastify.post<{Querystring: staticCreateAccount}>(`${PATH_BASE_CONTROLLER}/create`, options, async (request) => { + return await accountService.createAccount(request.body); +}) \ No newline at end of file diff --git a/src_refactory/controllers/account/delete.ts b/src_refactory/controllers/account/delete.ts new file mode 100644 index 0000000..973eccc --- /dev/null +++ b/src_refactory/controllers/account/delete.ts @@ -0,0 +1,29 @@ +import { RouteShorthandOptions } from "fastify"; + +import { SCHEMA_ERROR, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; +import { PATH_BASE_CONTROLLER, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount } from "../../schemas/accountSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import fastify from "../../server/fastify"; + +const accountService = new AccountService(); + +const options: RouteShorthandOptions = { + schema: { + querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, + response: { + 200: { $ref: SCHEMA_RETURN_VOID }, + 500: { $ref: SCHEMA_ERROR }, + 404: { $ref: SCHEMA_ERROR }, + } + } +} + +fastify.delete<{Querystring: staticQueryUsernameAccount}>(`${PATH_BASE_CONTROLLER}/delete`, options, async (request) => { + const {username} = request.query; + + await accountService.deleteAccount(username); + + return { response: "ok" } +}) \ No newline at end of file diff --git a/src_refactory/controllers/account/find.ts b/src_refactory/controllers/account/find.ts new file mode 100644 index 0000000..2c4bdb8 --- /dev/null +++ b/src_refactory/controllers/account/find.ts @@ -0,0 +1,27 @@ +import { RouteShorthandOptions } from "fastify"; + +import { PATH_BASE_CONTROLLER, SCHEMA_RETURN_ACCOUNT, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount } from "../../schemas/accountSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import fastify from "../../server/fastify"; +import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; + +const accountService = new AccountService(); + +const options: RouteShorthandOptions = { + schema: { + querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, + response: { + 200: { $ref: SCHEMA_RETURN_ACCOUNT }, + 500: { $ref: SCHEMA_ERROR }, + 404: { $ref: SCHEMA_ERROR }, + } + } +} + +fastify.get<{Querystring: staticQueryUsernameAccount}>(`${PATH_BASE_CONTROLLER}/find`, options, async (request) => { + const {username} = request.query; + + return await accountService.findFromUsername(username); +}) \ No newline at end of file diff --git a/src_refactory/controllers/account/index.ts b/src_refactory/controllers/account/index.ts deleted file mode 100644 index 6d4aacd..0000000 --- a/src_refactory/controllers/account/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Logger from "../../modules/logger"; -const logger = new Logger("account-controller"); - -logger.debug("Loaded controller!") - -import * as routes from "./routes"; -import { IController } from "../../server/fastify/interfaces/IController"; - -export default { - routes, - pathBaseController: "/account" -} as IController; \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/createRoute.ts b/src_refactory/controllers/account/routes/createRoute.ts deleted file mode 100644 index 58c9cdb..0000000 --- a/src_refactory/controllers/account/routes/createRoute.ts +++ /dev/null @@ -1,27 +0,0 @@ -import Joi from "joi"; - -import { AccountService } from "../../../applications/services/AccountService"; - -import { IRoute } from "../../../server/fastify/interfaces/IRoute"; -import { IAccount, IAccountEnv } from "../../../domain/interfaces/models/IAccount"; - -const accountService = new AccountService(); - -export default { - method: "POST", - url: "/create", - hander: async function (request, replay){ - const account = request.body as IAccount; - - return accountService.createAccount(account); - }, - options: { - schema: { - body: Joi.object({ - [IAccountEnv.USERNAME]: Joi.string().max(250).required(), - [IAccountEnv.PASSWORD]: Joi.string().max(500).required(), - [IAccountEnv.CHANGE_PASSWORD]: Joi.boolean().required() - }) - } - } -} as IRoute \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/deleteRoute.ts b/src_refactory/controllers/account/routes/deleteRoute.ts deleted file mode 100644 index e81d688..0000000 --- a/src_refactory/controllers/account/routes/deleteRoute.ts +++ /dev/null @@ -1,24 +0,0 @@ -import Joi from "joi"; - -import { IRoute } from "../../../server/fastify/interfaces/IRoute"; -import { IAccountEnv } from "../../../domain/interfaces/models/IAccount"; - -import { AccountService } from "../../../applications/services/AccountService"; -const accountService = new AccountService(); - -export default { - method: "DELETE", - url: "/delete", - hander: async function (request, replay){ - const {username} = request.query as {username: string}; - - return accountService.deleteAccount(username); - }, - options: { - schema: { - querystring: Joi.object({ - [IAccountEnv.USERNAME]: Joi.string().required() - }) - } - } -} as IRoute \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/findRoute.ts b/src_refactory/controllers/account/routes/findRoute.ts deleted file mode 100644 index a54197c..0000000 --- a/src_refactory/controllers/account/routes/findRoute.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Joi from "joi"; - -import { AccountService } from "../../../applications/services/AccountService"; - -import { IRoute } from "../../../server/fastify/interfaces/IRoute"; -import { IAccount, IAccountEnv } from "../../../domain/interfaces/models/IAccount"; - -const accountService = new AccountService(); - -export default { - method: "GET", - url: "/find", - hander: async function (request, replay){ - const {username} = request.query as {username: string}; - - return accountService.findFromUsername(username); - }, - options: { - schema: { - querystring: Joi.object({ - [IAccountEnv.USERNAME]: Joi.string().max(250).required() - }) - } - } -} as IRoute \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/index.ts b/src_refactory/controllers/account/routes/index.ts deleted file mode 100644 index 9a1e7e3..0000000 --- a/src_refactory/controllers/account/routes/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export {default as createRoute} from "./createRoute"; -export {default as findRoute} from "./findRoute"; -export {default as updateRoute} from "./updateRoute"; -export {default as deleteRoute} from "./deleteRoute"; \ No newline at end of file diff --git a/src_refactory/controllers/account/routes/updateRoute.ts b/src_refactory/controllers/account/routes/updateRoute.ts deleted file mode 100644 index 643f04d..0000000 --- a/src_refactory/controllers/account/routes/updateRoute.ts +++ /dev/null @@ -1,29 +0,0 @@ -import Joi from "joi"; - -import { IRoute } from "../../../server/fastify/interfaces/IRoute"; -import { IAccount, IAccountEnv } from "../../../domain/interfaces/models/IAccount"; - -import { AccountService } from "../../../applications/services/AccountService"; -const accountService = new AccountService(); - -export default { - method: "PUT", - url: "/update", - hander: async function (request, replay){ - const {username} = request.query as {username: string}; - const account = request.body as IAccount; - - return accountService.updateAccount(username, account); - }, - options: { - schema: { - querystring: Joi.object({ - [IAccountEnv.USERNAME]: Joi.string().required() - }), - body: Joi.object({ - [IAccountEnv.CHANGE_PASSWORD]: Joi.boolean().optional(), - [IAccountEnv.PROFILE]: Joi.string().optional(), - }) - } - } -} as IRoute \ No newline at end of file diff --git a/src_refactory/controllers/account/update.ts b/src_refactory/controllers/account/update.ts new file mode 100644 index 0000000..be52ea0 --- /dev/null +++ b/src_refactory/controllers/account/update.ts @@ -0,0 +1,30 @@ +import { RouteShorthandOptions } from "fastify"; + +import { PATH_BASE_CONTROLLER, SCHEMA_RETURN_ACCOUNT, SCHEMA_UPDATE_ACCOUNT, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount, staticUpdateAccount } from "../../schemas/accountSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import { IAccount } from "../../domain/interfaces/models/IAccount"; +import fastify from "../../server/fastify"; +import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; + +const accountService = new AccountService(); + +const options: RouteShorthandOptions = { + schema: { + querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, + body: { $ref: SCHEMA_UPDATE_ACCOUNT }, + response: { + 200: { $ref: SCHEMA_RETURN_ACCOUNT }, + 500: { $ref: SCHEMA_ERROR }, + 404: { $ref: SCHEMA_ERROR }, + } + } +} + +fastify.put<{Querystring: staticQueryUsernameAccount, Body: staticUpdateAccount}>(`${PATH_BASE_CONTROLLER}/update`, options, async (request) => { + const {username} = request.query; + const account = request.body; + + return await accountService.updateAccount(username, account); +}) \ No newline at end of file diff --git a/src_refactory/controllers/request/action.ts b/src_refactory/controllers/request/action.ts new file mode 100644 index 0000000..32cd0c0 --- /dev/null +++ b/src_refactory/controllers/request/action.ts @@ -0,0 +1,26 @@ +import { RouteShorthandOptions } from "fastify"; + +import fastify from "../../server/fastify"; +import { RequestService } from "../../applications/services/RequestService"; +import { PATH_BASE_CONTROLLER, SCHEMA_ACTION_REQUEST, staticActionRequest } from "../../schemas/requestSchema"; +import { SCHEMA_ERROR, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; + +const requestService = new RequestService(); + +const options: RouteShorthandOptions = { + schema: { + querystring: { $ref: SCHEMA_ACTION_REQUEST }, + response: { + 200: { $ref: SCHEMA_RETURN_VOID }, + 500: { $ref: SCHEMA_ERROR }, + } + } +} + +fastify.post<{Querystring: staticActionRequest}>(`${PATH_BASE_CONTROLLER}/action`, options, async (request) => { + const {accept, request_from, request_to} = request.query; + + await requestService.action(request_from, request_to, accept); + + return { response: "ok" } +}) \ No newline at end of file diff --git a/src_refactory/controllers/request/create.ts b/src_refactory/controllers/request/create.ts new file mode 100644 index 0000000..d283bcd --- /dev/null +++ b/src_refactory/controllers/request/create.ts @@ -0,0 +1,25 @@ +import { RouteShorthandOptions } from "fastify"; + +import fastify from "../../server/fastify"; +import { RequestService } from "../../applications/services/RequestService"; +import { PATH_BASE_CONTROLLER, SCHEMA_CREATE_REQUEST, staticCreateRequest } from "../../schemas/requestSchema"; +import { SCHEMA_ERROR, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; + +const requestService = new RequestService(); + +const options: RouteShorthandOptions = { + schema: { + body: { $ref: SCHEMA_CREATE_REQUEST }, + response: { + 200: { $ref: SCHEMA_RETURN_VOID }, + 401: { $ref: SCHEMA_ERROR }, + 404: { $ref: SCHEMA_ERROR }, + } + } +} + +fastify.post<{Body: staticCreateRequest}>(`${PATH_BASE_CONTROLLER}/create`, options, async (request) => { + await requestService.create(request.body); + + return { response: "ok" } +}) \ No newline at end of file diff --git a/src_refactory/controllers/request/list.ts b/src_refactory/controllers/request/list.ts new file mode 100644 index 0000000..016f095 --- /dev/null +++ b/src_refactory/controllers/request/list.ts @@ -0,0 +1,24 @@ +import { RouteShorthandOptions } from "fastify"; + +import fastify from "../../server/fastify"; +import { RequestService } from "../../applications/services/RequestService"; +import { PATH_BASE_CONTROLLER, SCHEMA_QUERY_PAGINATED_REQUEST, SCHEMA_RETURN_PAGINATED_REQUEST, staticQueryPaginatedRequest } from "../../schemas/requestSchema"; +import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; + +const requestService = new RequestService(); + +const options: RouteShorthandOptions = { + schema: { + querystring: { $ref: SCHEMA_QUERY_PAGINATED_REQUEST }, + response: { + 200: { $ref: SCHEMA_RETURN_PAGINATED_REQUEST }, + 500: { $ref: SCHEMA_ERROR }, + } + } +} + +fastify.get<{Querystring: staticQueryPaginatedRequest}>(`${PATH_BASE_CONTROLLER}/list`, options, async (request) => { + const {length, request_from, skip} = request.query; + + return await requestService.listPaginated(request_from, skip, length); +}) \ No newline at end of file diff --git a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts index 39e4fbb..8dec18b 100644 --- a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts +++ b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts @@ -1,3 +1,5 @@ +import { Type } from "@sinclair/typebox"; + export enum IAccountDTOEnv { USERNAME = "username", LAST_ACCESS = "last_access", @@ -6,10 +8,12 @@ export enum IAccountDTOEnv { PROFILE = "profile" } -export interface IAccountDTO { - [IAccountDTOEnv.USERNAME]: string, - [IAccountDTOEnv.LAST_ACCESS]: Date, - [IAccountDTOEnv.CHANGE_PASSWORD]: Date, - [IAccountDTOEnv.EXPIRE_PASSWORD]: Date, - [IAccountDTOEnv.PROFILE]: string -} \ No newline at end of file +export const accountDTOSchema = Type.Object({ + [IAccountDTOEnv.USERNAME]: Type.String({ maxLength: 250 }), + [IAccountDTOEnv.EXPIRE_PASSWORD]: Type.String({ format: "date-time" }), + [IAccountDTOEnv.LAST_ACCESS]: Type.Union([Type.Null(), Type.String({ format: "date-time" })]), + [IAccountDTOEnv.PROFILE]: Type.Union([Type.Null(), Type.String()]), + [IAccountDTOEnv.CHANGE_PASSWORD]: Type.Boolean() +}); + +export type IAccountDTO = typeof accountDTOSchema.static \ No newline at end of file diff --git a/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts b/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts new file mode 100644 index 0000000..1b7ff89 --- /dev/null +++ b/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts @@ -0,0 +1,15 @@ +import { Type } from "@sinclair/typebox"; + +export enum IRequestDTOEnv { + REQUEST_TO = "request_to", + REQUEST_FROM = "request_from", + REQUEST_TIME = "request_time" +} + +export const requestDTOSchema = Type.Object({ + [IRequestDTOEnv.REQUEST_FROM]: Type.String({maxLength: 250}), + [IRequestDTOEnv.REQUEST_TO]: Type.String({maxLength: 250}), + [IRequestDTOEnv.REQUEST_TIME]: Type.String({format: 'date-time'}), +}) + +export type IRequestDTO = typeof requestDTOSchema.static \ No newline at end of file diff --git a/src_refactory/domain/interfaces/models/IAccount.ts b/src_refactory/domain/interfaces/models/IAccount.ts index 3bf31a3..09fc367 100644 --- a/src_refactory/domain/interfaces/models/IAccount.ts +++ b/src_refactory/domain/interfaces/models/IAccount.ts @@ -1,3 +1,5 @@ +import { Type } from "@sinclair/typebox"; + export enum IAccountEnv { USERNAME = "username", PASSWORD = "password", @@ -7,11 +9,13 @@ export enum IAccountEnv { PROFILE = "profile" } -export interface IAccount { - [IAccountEnv.USERNAME]: string, - [IAccountEnv.PASSWORD]: string, - [IAccountEnv.LAST_ACCESS]: Date | null, - [IAccountEnv.CHANGE_PASSWORD]: boolean, - [IAccountEnv.EXPIRE_PASSWORD]: Date, - [IAccountEnv.PROFILE]: string -} \ No newline at end of file +export const accountSchema = Type.Object({ + [IAccountEnv.USERNAME]: Type.String({ maxLength: 250 }), + [IAccountEnv.PASSWORD]: Type.String({ maxLength: 250 }), + [IAccountEnv.EXPIRE_PASSWORD]: Type.String({ format: "date-time" }), + [IAccountEnv.LAST_ACCESS]: Type.Union([Type.Null(), Type.String({ format: "date-time" })]), + [IAccountEnv.PROFILE]: Type.Union([Type.Null(), Type.String()]), + [IAccountEnv.CHANGE_PASSWORD]: Type.Boolean() +}); + +export type IAccount = typeof accountSchema.static \ No newline at end of file diff --git a/src_refactory/domain/interfaces/models/IRequest.ts b/src_refactory/domain/interfaces/models/IRequest.ts new file mode 100644 index 0000000..5fc7926 --- /dev/null +++ b/src_refactory/domain/interfaces/models/IRequest.ts @@ -0,0 +1,15 @@ +import { Type } from "@sinclair/typebox"; + +export enum IRequestEnv { + REQUEST_TO = "request_to", + REQUEST_FROM = "request_from", + REQUEST_TIME = "request_time" +} + +export const requestSchema = Type.Object({ + [IRequestEnv.REQUEST_FROM]: Type.String({maxLength: 250}), + [IRequestEnv.REQUEST_TO]: Type.String({maxLength: 250}), + [IRequestEnv.REQUEST_TIME]: Type.String({format: 'date-time'}), +}) + +export type IRequest = typeof requestSchema.static \ No newline at end of file diff --git a/src_refactory/domain/models/Account.ts b/src_refactory/domain/models/Account.ts index a9fe4c4..2e4e429 100644 --- a/src_refactory/domain/models/Account.ts +++ b/src_refactory/domain/models/Account.ts @@ -1,5 +1,6 @@ import { Entity, PrimaryColumn, Column } from "typeorm"; import { DateTime } from "luxon"; + import { IAccount, IAccountEnv } from "../interfaces/models/IAccount"; @Entity("account") @@ -11,13 +12,13 @@ export class Account implements IAccount{ [IAccountEnv.PASSWORD]: string; @Column({type: "timestamptz", nullable: true, default: null}) - [IAccountEnv.LAST_ACCESS]: Date | null; + [IAccountEnv.LAST_ACCESS]: string | null; @Column({type: "boolean", default: false}) [IAccountEnv.CHANGE_PASSWORD]: boolean; @Column({type: "timestamptz", default: DateTime.now().plus({month: 1})}) - [IAccountEnv.EXPIRE_PASSWORD]: Date; + [IAccountEnv.EXPIRE_PASSWORD]: string; @Column({type: "text", default: null, nullable: true}) [IAccountEnv.PROFILE]: string; diff --git a/src_refactory/domain/models/Request.ts b/src_refactory/domain/models/Request.ts new file mode 100644 index 0000000..b0a4c37 --- /dev/null +++ b/src_refactory/domain/models/Request.ts @@ -0,0 +1,16 @@ +import { Entity, PrimaryColumn, Column } from "typeorm"; +import { DateTime } from "luxon"; + +import { IRequest, IRequestEnv } from "../interfaces/models/IRequest"; + +@Entity("request") +export class Request implements IRequest{ + @PrimaryColumn({type: "varchar", length: 250}) + [IRequestEnv.REQUEST_FROM]: string; + + @PrimaryColumn({type: "varchar", length: 250}) + [IRequestEnv.REQUEST_TO]: string; + + @Column({type: "timestamptz", default: DateTime.now()}) + [IRequestEnv.REQUEST_TIME]: string; +} \ No newline at end of file diff --git a/src_refactory/modules/api.ts b/src_refactory/modules/api.ts index 9a37e43..37fa648 100644 --- a/src_refactory/modules/api.ts +++ b/src_refactory/modules/api.ts @@ -22,10 +22,17 @@ class ApiUnauthorized extends Error { this.name = "ApiUnauthorized"; } } +class ApiBadRequest extends Error { + constructor(message: string) { + super(message); + this.name = "ApiBadRequest"; + } +} export { ApiNotFound, ApiErrorGeneric, ApiConflict, - ApiUnauthorized + ApiUnauthorized, + ApiBadRequest } \ No newline at end of file diff --git a/src_refactory/package.json b/src_refactory/package.json index 309f4de..f9a262f 100644 --- a/src_refactory/package.json +++ b/src_refactory/package.json @@ -13,7 +13,12 @@ "license": "ISC", "description": "", "dependencies": { + "@fastify/swagger": "^8.15.0", + "@fastify/swagger-ui": "^4.1.0", + "@sinclair/typebox": "^0.33.7", + "@types/async": "^3.2.24", "@types/crypto-js": "^4.2.2", + "async": "^3.2.6", "chalk": "^5.3.0", "crypto-js": "^4.2.0", "dotenv": "^16.4.5", diff --git a/src_refactory/schemas/accountSchema.ts b/src_refactory/schemas/accountSchema.ts new file mode 100644 index 0000000..2062bcd --- /dev/null +++ b/src_refactory/schemas/accountSchema.ts @@ -0,0 +1,45 @@ +import { Type } from '@sinclair/typebox' + +import { accountSchema, IAccountEnv } from "../domain/interfaces/models/IAccount" +import { accountDTOSchema } from '../domain/interfaces/DTOs/IAccountDTO'; +import { convertToOptional } from '../utils/schemaUtils'; + +//path base +const PATH_BASE_CONTROLLER = "/account"; + +//schemas +const SCHEMA_CREATE_ACCOUNT = "SchemaCreateAccount"; +const SCHEMA_UPDATE_ACCOUNT = "SchemaUpdateAccount"; +const SCHEMA_RETURN_ACCOUNT = "SchemaReturnAccount"; +const SCHEMA_QUERY_USERNAME_ACCOUNT = "SchemaQueryUsernameAccount"; + + +//request +const createAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME, IAccountEnv.PASSWORD, IAccountEnv.CHANGE_PASSWORD], { $id: SCHEMA_CREATE_ACCOUNT }); +const updateAccount = convertToOptional(accountSchema, [IAccountEnv.PROFILE, IAccountEnv.CHANGE_PASSWORD], SCHEMA_UPDATE_ACCOUNT); +const queryUsernameAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME], { $id: SCHEMA_QUERY_USERNAME_ACCOUNT }); + +//replay +const returnAccount = Type.Intersect([accountDTOSchema], { $id: SCHEMA_RETURN_ACCOUNT }); + +//load schemas +export default [createAccount, updateAccount, returnAccount, queryUsernameAccount] + +type staticCreateAccount = typeof createAccount.static +type staticUpdateAccount = typeof updateAccount.static +type staticReturnAccount = typeof returnAccount.static +type staticQueryUsernameAccount = typeof queryUsernameAccount.static; + +export { + PATH_BASE_CONTROLLER, + + staticCreateAccount, + staticUpdateAccount, + staticReturnAccount, + staticQueryUsernameAccount, + + SCHEMA_CREATE_ACCOUNT, + SCHEMA_RETURN_ACCOUNT, + SCHEMA_UPDATE_ACCOUNT, + SCHEMA_QUERY_USERNAME_ACCOUNT +} \ No newline at end of file diff --git a/src_refactory/schemas/generic/genericSchema.ts b/src_refactory/schemas/generic/genericSchema.ts new file mode 100644 index 0000000..6184624 --- /dev/null +++ b/src_refactory/schemas/generic/genericSchema.ts @@ -0,0 +1,25 @@ +import { Type } from '@sinclair/typebox' + +const SCHEMA_RETURN_VOID = "SchemaReturnVoid"; +const SCHEMA_ERROR = "SchemaError"; + +const returnVoid = Type.Object({ + response: Type.String() +}, {$id: SCHEMA_RETURN_VOID}); + +const errorSchema = Type.Object({ + statusCode: Type.Number(), + message: Type.String(), + error: Type.String() +}, { $id: SCHEMA_ERROR }) + +export default [returnVoid, errorSchema] + +type staticReturnVoid = typeof returnVoid.static + +export { + staticReturnVoid, + + SCHEMA_RETURN_VOID, + SCHEMA_ERROR +} \ No newline at end of file diff --git a/src_refactory/schemas/generic/paginationSchema.ts b/src_refactory/schemas/generic/paginationSchema.ts new file mode 100644 index 0000000..72e1ec5 --- /dev/null +++ b/src_refactory/schemas/generic/paginationSchema.ts @@ -0,0 +1,17 @@ +import { Type, TObject } from '@sinclair/typebox' + +const queryPagination = Type.Object({ + skip: Type.Number({minimum: 0, default: 0}), + length: Type.Number({minimum: 10, default: 10}), +}); + +const schemaReturnPagination = (schema: T, id: string) => Type.Object({ + max_count: Type.Number(), + list: Type.Array(schema) +}, {$id: id}); + +export { + schemaReturnPagination, + + queryPagination +} \ No newline at end of file diff --git a/src_refactory/schemas/requestSchema.ts b/src_refactory/schemas/requestSchema.ts new file mode 100644 index 0000000..acd9a7b --- /dev/null +++ b/src_refactory/schemas/requestSchema.ts @@ -0,0 +1,48 @@ +import { Type } from '@sinclair/typebox' +import { queryPagination, schemaReturnPagination } from './generic/paginationSchema'; +import { requestDTOSchema } from '../domain/interfaces/DTOs/IRequestDTO'; +import { IRequestEnv, requestSchema } from '../domain/interfaces/models/IRequest'; + +//path base +const PATH_BASE_CONTROLLER = "/request"; + +//schemas +const SCHEMA_CREATE_REQUEST = "SchemaCreateRequest"; +const SCHEMA_ACTION_REQUEST = "SchemaActionRequest"; +const SCHEMA_RETURN_PAGINATED_REQUEST = "SchemaReturnPaginatedRequest"; +const SCHEMA_QUERY_PAGINATED_REQUEST = "SchemaQueryPaginatedRequest"; + +//request +const createRequest = Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO], { $id: SCHEMA_CREATE_REQUEST }); +const actionRequest = Type.Intersect([ + Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO]), + Type.Object({ + accept: Type.Boolean() + }) +], {$id: SCHEMA_ACTION_REQUEST}); +const queryPaginatedRequest = Type.Intersect([Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM]), queryPagination], {$id: SCHEMA_QUERY_PAGINATED_REQUEST}); + +//replay +const returnPaginatedRequest = schemaReturnPagination(requestDTOSchema, SCHEMA_RETURN_PAGINATED_REQUEST); + +//load schemas +export default [createRequest, actionRequest, returnPaginatedRequest, queryPaginatedRequest] + +type staticCreateRequest = typeof createRequest.static; +type staticActionRequest = typeof actionRequest.static; +type staticReturnPaginatedRequest = typeof returnPaginatedRequest.static; +type staticQueryPaginatedRequest = typeof queryPaginatedRequest.static; + +export { + PATH_BASE_CONTROLLER, + + staticCreateRequest, + staticActionRequest, + staticReturnPaginatedRequest, + staticQueryPaginatedRequest, + + SCHEMA_CREATE_REQUEST, + SCHEMA_ACTION_REQUEST, + SCHEMA_RETURN_PAGINATED_REQUEST, + SCHEMA_QUERY_PAGINATED_REQUEST +} \ No newline at end of file diff --git a/src_refactory/server/fastify/index.ts b/src_refactory/server/fastify/index.ts index 723cd56..2f18c39 100644 --- a/src_refactory/server/fastify/index.ts +++ b/src_refactory/server/fastify/index.ts @@ -1,13 +1,11 @@ -import { env, exit, platform } from "process"; +import { env, exit } from "process"; import fs from "fs"; import Fastify from 'fastify'; import { DateTime } from 'luxon'; import path from "path"; import _ from "lodash"; -import { ApiConflict, ApiErrorGeneric, ApiNotFound, ApiUnauthorized } from "../../modules/api"; - -import { IController } from "./interfaces/IController"; +import { ApiBadRequest, ApiConflict, ApiErrorGeneric, ApiNotFound, ApiUnauthorized } from "../../modules/api"; import Logger from '../../modules/logger'; const logger = new Logger("server-fastify"); @@ -18,14 +16,72 @@ const __dirname = path.resolve(); const fastify = Fastify(); //init -async function init(pathControllers = "controllers"){ +async function init(pathControllers = "controllers", pathSchemas){ logger.info("Starting service fastify..."); + await fastify.register(await import("@fastify/swagger"), { + openapi: { + openapi: '3.0.0', + info: { + title: 'Test swagger', + description: 'Testing the Fastify swagger API', + version: '0.1.0' + }, + servers: [ + { + url: 'http://localhost:3000', + description: 'Development server' + } + ], + tags: [ + { name: 'user', description: 'User related end-points' }, + { name: 'code', description: 'Code related end-points' } + ], + components: { + securitySchemes: { + apiKey: { + type: 'apiKey', + name: 'apiKey', + in: 'header' + } + } + }, + externalDocs: { + url: 'https://swagger.io', + description: 'Find more info here' + } + } + }); + + await fastify.register(await import('@fastify/swagger-ui'), { + routePrefix: '/documentation', + uiConfig: { + docExpansion: 'full', + deepLinking: false + }, + uiHooks: { + onRequest: function (request, reply, next) { next() }, + preHandler: function (request, reply, next) { next() } + }, + staticCSP: true, + transformStaticCSP: (header) => header, + transformSpecification: (swaggerObject, request, reply) => { return swaggerObject }, + transformSpecificationClone: true + }) + //controllers logger.debug("Starting load controllers"); await loadControllers(pathControllers); logger.debug("Finish load all controllers"); + //schemas + logger.debug("Starting load schemas"); + await loadSchemas(pathSchemas); + logger.debug("Finish load all schemas"); + + await fastify.ready() + fastify.swagger() + //server let connection = ""; try{ @@ -41,70 +97,111 @@ async function init(pathControllers = "controllers"){ logger.info(`Connection established ${connection}`); } -//load routers -async function loadControllers(path_controllers: string){ - const listFileControllers: Array = []; - const basePathController = path.join(__dirname, path_controllers); +//load controllers +async function loadControllers(pathControllers: string){ + const basePathController = path.join(__dirname, pathControllers); //get list folder inside controllers - const listControllers = fs.readdirSync(basePathController).map((singlePath) => path.join(path_controllers, singlePath)); - - //get index every controller - for (const controller of listControllers) { - try{ - listFileControllers.push(...(fs.readdirSync(controller)).filter((file) => file === "index.ts").map((singlePath) => path.join(controller, singlePath))); - }catch(err){ - logger.error("Failed load controllers reason:", err); - } + let listFileControllers: Array = []; + try{ + listFileControllers = fs.readdirSync(basePathController).filter((file) => file.indexOf('.') === -1).map((folder) => path.join(basePathController, folder)); + }catch(err){ + logger.fatal("Cannot read folder", pathControllers, "details: ", err); + exit(1); } - - logger.debug("List controllers available:", listFileControllers.join(', ')) + + logger.debug("List controllers available:", listFileControllers.map((file) => path.basename(file))); + logger.debug("Controllers", `(${listFileControllers.length})`, "available"); let success = 0; for (const fileController of listFileControllers) { - let controller: IController; + const totalRoutes = await loadRoutes(fileController); + + if(totalRoutes > 0){ + logger.debug("Done import controller", path.basename(fileController)); + success++; + }else{ + logger.error("Controller", path.basename(fileController), "maybe has some error"); + } + } + + if(success === 0){ + logger.fatal("controllers none loaded"); + exit(1); + } + logger.debug('Total controllers loaded', success); +} + +//load routes +async function loadRoutes(pathController: string){ + let listFileRoutes: Array = []; + + try{ + listFileRoutes = fs.readdirSync(pathController).filter((file) => file.indexOf(".") !== -1).map((file) => path.join(pathController, file)); + }catch(err){ + logger.error("Cannot read controller", path.basename(pathController), "details:", err); + } + + logger.debug("List routes available", listFileRoutes.map((file) => path.basename(file))); + logger.debug("Routes", `(${listFileRoutes.length})`, "available"); + + let success = 0; + for (const fileRoute of listFileRoutes) { try{ - controller = (await import(path.join(platform === "win32"? 'file://' : '', __dirname, fileController))).default; + await import(fileRoute); }catch(err){ - logger.error("Failed load", `"${fileController}", details:`, err); + logger.error("Failed load route", `"${fileRoute}" details:`, err); continue; } - loadRoutes(controller, fileController); - + logger.debug("Done import route", path.basename(fileRoute)); success++; } - logger.debug('Total controllers loaded', success); + logger.debug('Loaded', `(${success}) routes from`, path.basename(pathController)); + return success; } -function loadRoutes(controller: IController, nameController: string){ - logger.debug("Routes", `(${Object.keys(controller.routes).length})`, "available"); +//load schemas +async function loadSchemas(pathSchemas = "schemas"){ + const basePathSchemas = path.join(__dirname, pathSchemas); + + if(!fs.existsSync(basePathSchemas)){ + logger.warn("Not exist root folder schemas, skip schemas") + return; + } + + //get list folder inside controllers + const listFileSchemas = fs.readdirSync(basePathSchemas, {recursive: true, withFileTypes: true}).filter((singlePath) => singlePath.isFile()).map((singlePath) => path.join(singlePath.parentPath, singlePath.name)); + + logger.debug(`List schemas available: ${listFileSchemas.map((file) => path.basename(file))}`); let success = 0; - for (const route in controller.routes) { - const pathRoute = path.join(controller.pathBaseController, controller.routes[route].url); + let listSchemas: Array; + for (const fileSchema of listFileSchemas) { try{ - fastify.route({ - url: pathRoute, - method: controller.routes[route].method, - handler: controller.routes[route].hander, - validatorCompiler: ({ schema }) => { - //@ts-ignore - return data => schema.validate(data) - }, - ...controller.routes[route].options - }) + listSchemas = (await import(fileSchema)).default; }catch(err){ - logger.error("Failed load route", `"${pathRoute}" details:`, err); + logger.error(`Failed load schema "${path.basename(fileSchema)}", details:`, err); continue; } - + + if(!_.isNil(listSchemas)){ + for (const schema of listSchemas) { + try{ + fastify.addSchema(schema) + }catch(err){ + logger.error(`Failed add specific schema of ${schema['$id']}, details:`, err); + } + } + } + + logger.debug("Done import schema", path.basename(fileSchema)); success++; } - logger.debug('Loaded', `(${success}) routes from`, nameController); + logger.debug("Total schemas loaded", success); } //logging @@ -174,6 +271,11 @@ fastify.setErrorHandler((error, request, replay) => { ...message, statusCode: 500 }); + }else if(error instanceof ApiBadRequest){ + return replay.status(400).send({ + ...message, + statusCode: 400 + }); }else{ logger.error(error); return error; diff --git a/src_refactory/server/postgres/index.ts b/src_refactory/server/postgres/index.ts index 37d6cc0..dcbe366 100644 --- a/src_refactory/server/postgres/index.ts +++ b/src_refactory/server/postgres/index.ts @@ -4,7 +4,7 @@ import _ from "lodash"; import Logger from "../../modules/logger"; const logger = new Logger("pg"); -import { Account } from "../../domain/models/Account"; +import path from "path"; let pg: DataSource; @@ -22,7 +22,7 @@ async function init({ username, password, database, - entities: [Account], + entities: [`${path.resolve()}/domain/models/*.ts`], synchronize: process.env.NODE_ENV === 'dev', connectTimeoutMS: 5000 }); diff --git a/src_refactory/utils/schemaUtils.ts b/src_refactory/utils/schemaUtils.ts new file mode 100644 index 0000000..b502a62 --- /dev/null +++ b/src_refactory/utils/schemaUtils.ts @@ -0,0 +1,11 @@ +import { TSchema, Type } from "@sinclair/typebox"; + +function convertToOptional(schema: T, keys: Array, id: string){ + const pick = Type.Pick(schema, keys); + + return Type.Mapped(Type.KeyOf(pick), K => Type.Optional(Type.Index(pick, K)), { $id: id }); +} + +export { + convertToOptional +} \ No newline at end of file From 311b756f38a6caeeb4be9fc18f68393f0998badd Mon Sep 17 00:00:00 2001 From: cesxhin Date: Mon, 16 Sep 2024 22:31:47 +0200 Subject: [PATCH 08/21] add dynamic configuration server fastify and add service swagger --- src_refactory/controllers/account/create.ts | 8 +- src_refactory/controllers/account/delete.ts | 8 +- src_refactory/controllers/account/find.ts | 8 +- src_refactory/controllers/account/update.ts | 11 ++- src_refactory/controllers/request/action.ts | 10 ++- src_refactory/controllers/request/create.ts | 13 +++- src_refactory/controllers/request/list.ts | 10 ++- .../domain/interfaces/DTOs/IAccountDTO.ts | 2 +- .../domain/interfaces/models/IAccount.ts | 6 +- src_refactory/index.ts | 2 +- src_refactory/package.json | 2 +- .../schemas/generic/genericSchema.ts | 36 ++++++--- src_refactory/server/fastify/index.ts | 78 ++++++------------- .../server/fastify/interfaces/IConfig.ts | 5 ++ .../server/fastify/interfaces/IController.ts | 6 -- .../server/fastify/interfaces/IRoute.ts | 8 -- 16 files changed, 107 insertions(+), 106 deletions(-) create mode 100644 src_refactory/server/fastify/interfaces/IConfig.ts delete mode 100644 src_refactory/server/fastify/interfaces/IController.ts delete mode 100644 src_refactory/server/fastify/interfaces/IRoute.ts diff --git a/src_refactory/controllers/account/create.ts b/src_refactory/controllers/account/create.ts index cf90b17..fb85c2b 100644 --- a/src_refactory/controllers/account/create.ts +++ b/src_refactory/controllers/account/create.ts @@ -1,21 +1,23 @@ import { RouteShorthandOptions } from "fastify"; import { PATH_BASE_CONTROLLER, SCHEMA_CREATE_ACCOUNT, SCHEMA_RETURN_ACCOUNT, staticCreateAccount } from "../../schemas/accountSchema"; +import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; import { AccountService } from "../../applications/services/AccountService"; import fastify from "../../server/fastify"; -import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; const accountService = new AccountService(); const options: RouteShorthandOptions = { schema: { + tags: ['account'], + summary: 'Create new account', body: { $ref: SCHEMA_CREATE_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_ACCOUNT }, - 500: { $ref: SCHEMA_ERROR }, - 401: { $ref: SCHEMA_ERROR }, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 401: { $ref: SCHEMA_BAD_REQUEST }, } } } diff --git a/src_refactory/controllers/account/delete.ts b/src_refactory/controllers/account/delete.ts index 973eccc..e51c340 100644 --- a/src_refactory/controllers/account/delete.ts +++ b/src_refactory/controllers/account/delete.ts @@ -1,6 +1,6 @@ import { RouteShorthandOptions } from "fastify"; -import { SCHEMA_ERROR, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; +import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; import { PATH_BASE_CONTROLLER, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount } from "../../schemas/accountSchema"; import { AccountService } from "../../applications/services/AccountService"; @@ -11,11 +11,13 @@ const accountService = new AccountService(); const options: RouteShorthandOptions = { schema: { + tags: ['account'], + summary: 'Delete account', querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_VOID }, - 500: { $ref: SCHEMA_ERROR }, - 404: { $ref: SCHEMA_ERROR }, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 404: { $ref: SCHEMA_NOT_FOUND }, } } } diff --git a/src_refactory/controllers/account/find.ts b/src_refactory/controllers/account/find.ts index 2c4bdb8..b730977 100644 --- a/src_refactory/controllers/account/find.ts +++ b/src_refactory/controllers/account/find.ts @@ -1,21 +1,23 @@ import { RouteShorthandOptions } from "fastify"; import { PATH_BASE_CONTROLLER, SCHEMA_RETURN_ACCOUNT, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount } from "../../schemas/accountSchema"; +import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; import { AccountService } from "../../applications/services/AccountService"; import fastify from "../../server/fastify"; -import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; const accountService = new AccountService(); const options: RouteShorthandOptions = { schema: { + tags: ['account'], + summary: 'Find account', querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_ACCOUNT }, - 500: { $ref: SCHEMA_ERROR }, - 404: { $ref: SCHEMA_ERROR }, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 404: { $ref: SCHEMA_NOT_FOUND }, } } } diff --git a/src_refactory/controllers/account/update.ts b/src_refactory/controllers/account/update.ts index be52ea0..1c22703 100644 --- a/src_refactory/controllers/account/update.ts +++ b/src_refactory/controllers/account/update.ts @@ -1,23 +1,24 @@ import { RouteShorthandOptions } from "fastify"; import { PATH_BASE_CONTROLLER, SCHEMA_RETURN_ACCOUNT, SCHEMA_UPDATE_ACCOUNT, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount, staticUpdateAccount } from "../../schemas/accountSchema"; +import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; import { AccountService } from "../../applications/services/AccountService"; -import { IAccount } from "../../domain/interfaces/models/IAccount"; import fastify from "../../server/fastify"; -import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; const accountService = new AccountService(); const options: RouteShorthandOptions = { schema: { + tags: ['account'], + summary: 'Update values of account', querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, body: { $ref: SCHEMA_UPDATE_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_ACCOUNT }, - 500: { $ref: SCHEMA_ERROR }, - 404: { $ref: SCHEMA_ERROR }, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 404: { $ref: SCHEMA_NOT_FOUND }, } } } @@ -26,5 +27,7 @@ fastify.put<{Querystring: staticQueryUsernameAccount, Body: staticUpdateAccount} const {username} = request.query; const account = request.body; + console.log(request.body); + return await accountService.updateAccount(username, account); }) \ No newline at end of file diff --git a/src_refactory/controllers/request/action.ts b/src_refactory/controllers/request/action.ts index 32cd0c0..6f12d73 100644 --- a/src_refactory/controllers/request/action.ts +++ b/src_refactory/controllers/request/action.ts @@ -1,18 +1,22 @@ import { RouteShorthandOptions } from "fastify"; -import fastify from "../../server/fastify"; import { RequestService } from "../../applications/services/RequestService"; + import { PATH_BASE_CONTROLLER, SCHEMA_ACTION_REQUEST, staticActionRequest } from "../../schemas/requestSchema"; -import { SCHEMA_ERROR, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; +import { SCHEMA_INTERNAL_SERVER, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; const requestService = new RequestService(); const options: RouteShorthandOptions = { schema: { + tags: ['request'], + summary: 'Choose accept or refuse request friend', querystring: { $ref: SCHEMA_ACTION_REQUEST }, response: { 200: { $ref: SCHEMA_RETURN_VOID }, - 500: { $ref: SCHEMA_ERROR }, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, } } } diff --git a/src_refactory/controllers/request/create.ts b/src_refactory/controllers/request/create.ts index d283bcd..2955f4e 100644 --- a/src_refactory/controllers/request/create.ts +++ b/src_refactory/controllers/request/create.ts @@ -1,19 +1,24 @@ import { RouteShorthandOptions } from "fastify"; -import fastify from "../../server/fastify"; import { RequestService } from "../../applications/services/RequestService"; + import { PATH_BASE_CONTROLLER, SCHEMA_CREATE_REQUEST, staticCreateRequest } from "../../schemas/requestSchema"; -import { SCHEMA_ERROR, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; +import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; const requestService = new RequestService(); const options: RouteShorthandOptions = { schema: { + tags: ['request'], + summary: 'Create request friend', body: { $ref: SCHEMA_CREATE_REQUEST }, response: { 200: { $ref: SCHEMA_RETURN_VOID }, - 401: { $ref: SCHEMA_ERROR }, - 404: { $ref: SCHEMA_ERROR }, + 401: { $ref: SCHEMA_BAD_REQUEST }, + 404: { $ref: SCHEMA_NOT_FOUND }, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, } } } diff --git a/src_refactory/controllers/request/list.ts b/src_refactory/controllers/request/list.ts index 016f095..6bcf545 100644 --- a/src_refactory/controllers/request/list.ts +++ b/src_refactory/controllers/request/list.ts @@ -1,18 +1,22 @@ import { RouteShorthandOptions } from "fastify"; -import fastify from "../../server/fastify"; import { RequestService } from "../../applications/services/RequestService"; + import { PATH_BASE_CONTROLLER, SCHEMA_QUERY_PAGINATED_REQUEST, SCHEMA_RETURN_PAGINATED_REQUEST, staticQueryPaginatedRequest } from "../../schemas/requestSchema"; -import { SCHEMA_ERROR } from "../../schemas/generic/genericSchema"; +import { SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; const requestService = new RequestService(); const options: RouteShorthandOptions = { schema: { + tags: ['request'], + summary: 'List request for accept or reject', querystring: { $ref: SCHEMA_QUERY_PAGINATED_REQUEST }, response: { 200: { $ref: SCHEMA_RETURN_PAGINATED_REQUEST }, - 500: { $ref: SCHEMA_ERROR }, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, } } } diff --git a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts index 8dec18b..35d9470 100644 --- a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts +++ b/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts @@ -13,7 +13,7 @@ export const accountDTOSchema = Type.Object({ [IAccountDTOEnv.EXPIRE_PASSWORD]: Type.String({ format: "date-time" }), [IAccountDTOEnv.LAST_ACCESS]: Type.Union([Type.Null(), Type.String({ format: "date-time" })]), [IAccountDTOEnv.PROFILE]: Type.Union([Type.Null(), Type.String()]), - [IAccountDTOEnv.CHANGE_PASSWORD]: Type.Boolean() + [IAccountDTOEnv.CHANGE_PASSWORD]: Type.Boolean({ default: false }) }); export type IAccountDTO = typeof accountDTOSchema.static \ No newline at end of file diff --git a/src_refactory/domain/interfaces/models/IAccount.ts b/src_refactory/domain/interfaces/models/IAccount.ts index 09fc367..983349e 100644 --- a/src_refactory/domain/interfaces/models/IAccount.ts +++ b/src_refactory/domain/interfaces/models/IAccount.ts @@ -13,9 +13,9 @@ export const accountSchema = Type.Object({ [IAccountEnv.USERNAME]: Type.String({ maxLength: 250 }), [IAccountEnv.PASSWORD]: Type.String({ maxLength: 250 }), [IAccountEnv.EXPIRE_PASSWORD]: Type.String({ format: "date-time" }), - [IAccountEnv.LAST_ACCESS]: Type.Union([Type.Null(), Type.String({ format: "date-time" })]), - [IAccountEnv.PROFILE]: Type.Union([Type.Null(), Type.String()]), - [IAccountEnv.CHANGE_PASSWORD]: Type.Boolean() + [IAccountEnv.LAST_ACCESS]: Type.Union([Type.String({ format: "date-time" }), Type.Null()]), + [IAccountEnv.PROFILE]: Type.Union([Type.String(), Type.Null()]), + [IAccountEnv.CHANGE_PASSWORD]: Type.Boolean({ default: false }) }); export type IAccount = typeof accountSchema.static \ No newline at end of file diff --git a/src_refactory/index.ts b/src_refactory/index.ts index 028bb3f..74c09a4 100644 --- a/src_refactory/index.ts +++ b/src_refactory/index.ts @@ -12,4 +12,4 @@ await initPostgres({ database: process.env.POSTGRES_DB }); -await initServerFastify(); \ No newline at end of file +await initServerFastify({}); \ No newline at end of file diff --git a/src_refactory/package.json b/src_refactory/package.json index f9a262f..28e68e8 100644 --- a/src_refactory/package.json +++ b/src_refactory/package.json @@ -14,7 +14,7 @@ "description": "", "dependencies": { "@fastify/swagger": "^8.15.0", - "@fastify/swagger-ui": "^4.1.0", + "@fastify/swagger-ui": "4.1.0", "@sinclair/typebox": "^0.33.7", "@types/async": "^3.2.24", "@types/crypto-js": "^4.2.2", diff --git a/src_refactory/schemas/generic/genericSchema.ts b/src_refactory/schemas/generic/genericSchema.ts index 6184624..6ff77c1 100644 --- a/src_refactory/schemas/generic/genericSchema.ts +++ b/src_refactory/schemas/generic/genericSchema.ts @@ -1,19 +1,34 @@ import { Type } from '@sinclair/typebox' const SCHEMA_RETURN_VOID = "SchemaReturnVoid"; -const SCHEMA_ERROR = "SchemaError"; +const SCHEMA_NOT_FOUND = "SchemaNotFound"; +const SCHEMA_INTERNAL_SERVER = "SchemaInternalServer"; +const SCHEMA_CONFLICT = "SchemaConflict"; +const SCHEMA_BAD_REQUEST = "SchemaBadRequest"; const returnVoid = Type.Object({ - response: Type.String() + response: Type.String({default: 'ok'}) }, {$id: SCHEMA_RETURN_VOID}); -const errorSchema = Type.Object({ - statusCode: Type.Number(), - message: Type.String(), - error: Type.String() -}, { $id: SCHEMA_ERROR }) +const templateErrorSchema = Type.Object({ + message: Type.String({default: "Example error"}), + error: Type.String({default: "Name error"}) +}); -export default [returnVoid, errorSchema] +const notFound = Type.Intersect([templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 404}) +})], { $id: SCHEMA_NOT_FOUND }); +const internalServer = Type.Intersect([templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 500}) +})], { $id: SCHEMA_INTERNAL_SERVER }); +const conflict = Type.Intersect([templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 401}) +})], { $id: SCHEMA_CONFLICT }); +const badRequest = Type.Intersect([templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 400}) +})], { $id: SCHEMA_BAD_REQUEST }); + +export default [returnVoid, notFound, internalServer, conflict, badRequest] type staticReturnVoid = typeof returnVoid.static @@ -21,5 +36,8 @@ export { staticReturnVoid, SCHEMA_RETURN_VOID, - SCHEMA_ERROR + SCHEMA_NOT_FOUND, + SCHEMA_BAD_REQUEST, + SCHEMA_CONFLICT, + SCHEMA_INTERNAL_SERVER } \ No newline at end of file diff --git a/src_refactory/server/fastify/index.ts b/src_refactory/server/fastify/index.ts index 2f18c39..787c4e5 100644 --- a/src_refactory/server/fastify/index.ts +++ b/src_refactory/server/fastify/index.ts @@ -1,10 +1,11 @@ -import { env, exit } from "process"; import fs from "fs"; +import _ from "lodash"; +import path from "path"; import Fastify from 'fastify'; import { DateTime } from 'luxon'; -import path from "path"; -import _ from "lodash"; +import { env, exit } from "process"; +import { IConfig } from "./interfaces/IConfig"; import { ApiBadRequest, ApiConflict, ApiErrorGeneric, ApiNotFound, ApiUnauthorized } from "../../modules/api"; import Logger from '../../modules/logger'; @@ -16,58 +17,27 @@ const __dirname = path.resolve(); const fastify = Fastify(); //init -async function init(pathControllers = "controllers", pathSchemas){ +async function init({pathControllers = "controllers", pathSchemas = "schemas", swagger = true}: IConfig){ logger.info("Starting service fastify..."); - await fastify.register(await import("@fastify/swagger"), { - openapi: { - openapi: '3.0.0', - info: { - title: 'Test swagger', - description: 'Testing the Fastify swagger API', - version: '0.1.0' - }, - servers: [ - { - url: 'http://localhost:3000', - description: 'Development server' - } - ], - tags: [ - { name: 'user', description: 'User related end-points' }, - { name: 'code', description: 'Code related end-points' } - ], - components: { - securitySchemes: { - apiKey: { - type: 'apiKey', - name: 'apiKey', - in: 'header' - } - } - }, - externalDocs: { - url: 'https://swagger.io', - description: 'Find more info here' - } - } - }); - - await fastify.register(await import('@fastify/swagger-ui'), { - routePrefix: '/documentation', - uiConfig: { - docExpansion: 'full', - deepLinking: false - }, - uiHooks: { - onRequest: function (request, reply, next) { next() }, - preHandler: function (request, reply, next) { next() } - }, - staticCSP: true, - transformStaticCSP: (header) => header, - transformSpecification: (swaggerObject, request, reply) => { return swaggerObject }, - transformSpecificationClone: true - }) + //swagger + if(swagger){ + logger.debug("Starting load swagger"); + await fastify.register(await import("@fastify/swagger")); + await fastify.register(await import('@fastify/swagger-ui'), { + routePrefix: '/', + uiConfig: { + docExpansion: 'list', + deepLinking: false + }, + uiHooks: { + onRequest: function (request, reply, next) { next() }, + preHandler: function (request, reply, next) { next() } + }, + logLevel: "error" + }) + logger.debug("Finish load swagger"); + } //controllers logger.debug("Starting load controllers"); @@ -164,7 +134,7 @@ async function loadRoutes(pathController: string){ } //load schemas -async function loadSchemas(pathSchemas = "schemas"){ +async function loadSchemas(pathSchemas){ const basePathSchemas = path.join(__dirname, pathSchemas); if(!fs.existsSync(basePathSchemas)){ diff --git a/src_refactory/server/fastify/interfaces/IConfig.ts b/src_refactory/server/fastify/interfaces/IConfig.ts new file mode 100644 index 0000000..aad06dd --- /dev/null +++ b/src_refactory/server/fastify/interfaces/IConfig.ts @@ -0,0 +1,5 @@ +export interface IConfig{ + pathControllers?: string, + pathSchemas?: string, + swagger?: boolean +} \ No newline at end of file diff --git a/src_refactory/server/fastify/interfaces/IController.ts b/src_refactory/server/fastify/interfaces/IController.ts deleted file mode 100644 index e3ecb32..0000000 --- a/src_refactory/server/fastify/interfaces/IController.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { IRoute } from "./IRoute"; - -export interface IController { - routes: {[key: string]: IRoute}, - pathBaseController: string -} \ No newline at end of file diff --git a/src_refactory/server/fastify/interfaces/IRoute.ts b/src_refactory/server/fastify/interfaces/IRoute.ts deleted file mode 100644 index fea8345..0000000 --- a/src_refactory/server/fastify/interfaces/IRoute.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { RouteHandlerMethod, RouteShorthandOptions, HTTPMethods } from "fastify"; - -export interface IRoute { - url: string, - method: HTTPMethods, - options?: RouteShorthandOptions, - hander: RouteHandlerMethod -} \ No newline at end of file From f301ac4aa8663951b2535decb2bd9d9d75716acd Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 08:15:21 +0200 Subject: [PATCH 09/21] Improvment package --- src_refactory/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src_refactory/package.json b/src_refactory/package.json index 28e68e8..b878baa 100644 --- a/src_refactory/package.json +++ b/src_refactory/package.json @@ -9,8 +9,8 @@ "create_link_references": "cd ../references/src_refactory && ln -s ../../src_refactory/node_modules && ln -s ../../src_refactory/package.json && ln -s ../../src_refactory/tsconfig.json" }, "keywords": [], - "author": "", - "license": "ISC", + "author": "cesxhin", + "license": "MIT", "description": "", "dependencies": { "@fastify/swagger": "^8.15.0", @@ -39,4 +39,4 @@ "@types/pg-pool": "^2.0.6", "tsx": "^4.16.2" } -} +} \ No newline at end of file From 9f113c2f6e401f93c13cee7c303b022141761357 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 14:31:06 +0200 Subject: [PATCH 10/21] Added eslint and fix style code --- .../repositories/IAccountRepository.ts | 3 +- .../repositories/IRequestRepository.ts | 4 +- .../generic/IConnectionRepository.ts | 2 +- .../interfaces/services/IAccountService.ts | 6 +- .../interfaces/services/IRequestService.ts | 6 +- .../repositories/AccountRepository.ts | 24 ++-- .../repositories/RequestRepository.ts | 28 ++-- .../applications/services/AccountService.ts | 22 ++-- .../applications/services/RequestService.ts | 32 +++-- .../createRoute.ts} | 12 +- .../deleteRoute.ts} | 14 +- .../findRoute.ts} | 12 +- .../updateRoute.ts} | 12 +- .../actionRoute.ts} | 14 +- .../createRoute.ts} | 14 +- .../listRoute.ts} | 12 +- .../domain/interfaces/DTOs/IRequestDTO.ts | 4 +- .../domain/interfaces/models/IRequest.ts | 4 +- src_refactory/eslint.config.js | 76 +++++++++++ src_refactory/index.ts | 4 +- src_refactory/modules/api.ts | 2 +- src_refactory/package.json | 15 ++- src_refactory/schemas/accountSchema.ts | 12 +- .../schemas/generic/genericSchema.ts | 32 +++-- .../schemas/generic/paginationSchema.ts | 6 +- src_refactory/schemas/requestSchema.ts | 12 +- src_refactory/server/fastify/index.ts | 120 +++++++++--------- src_refactory/server/postgres/index.ts | 13 +- .../{AccountUtils.ts => accountUtils.ts} | 4 +- .../utils/{utils.ts => genericUtils.ts} | 6 +- src_refactory/utils/schemaUtils.ts | 4 +- 31 files changed, 310 insertions(+), 221 deletions(-) rename src_refactory/controllers/{account/create.ts => accountController/createRoute.ts} (83%) rename src_refactory/controllers/{account/delete.ts => accountController/deleteRoute.ts} (82%) rename src_refactory/controllers/{account/find.ts => accountController/findRoute.ts} (85%) rename src_refactory/controllers/{account/update.ts => accountController/updateRoute.ts} (87%) rename src_refactory/controllers/{request/action.ts => requestController/actionRoute.ts} (79%) rename src_refactory/controllers/{request/create.ts => requestController/createRoute.ts} (81%) rename src_refactory/controllers/{request/list.ts => requestController/listRoute.ts} (83%) create mode 100644 src_refactory/eslint.config.js rename src_refactory/utils/{AccountUtils.ts => accountUtils.ts} (67%) rename src_refactory/utils/{utils.ts => genericUtils.ts} (80%) diff --git a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts index 9e242d9..09d0a4c 100644 --- a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts +++ b/src_refactory/applications/interfaces/repositories/IAccountRepository.ts @@ -1,4 +1,3 @@ -import { Account } from "../../../domain/models/Account"; import { IAccount } from "../../../domain/interfaces/models/IAccount"; import IConnectionRepository from "./generic/IConnectionRepository"; @@ -11,4 +10,4 @@ export default interface IAccountRepository extends IConnectionRepository): Promise; //delete deleteAccount(username: string): void; -} \ No newline at end of file +} // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src_refactory/applications/interfaces/repositories/IRequestRepository.ts b/src_refactory/applications/interfaces/repositories/IRequestRepository.ts index ffbe6ef..9976dc4 100644 --- a/src_refactory/applications/interfaces/repositories/IRequestRepository.ts +++ b/src_refactory/applications/interfaces/repositories/IRequestRepository.ts @@ -1,4 +1,4 @@ -import { IRequest } from "../../../domain/interfaces/models/IRequest" +import { IRequest } from "../../../domain/interfaces/models/IRequest"; import { Request } from "../../../domain/models/Request"; import IConnectionRepository from "./generic/IConnectionRepository"; @@ -13,4 +13,4 @@ export default interface IRequestRepository extends IConnectionRepository -} \ No newline at end of file +} // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts b/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts index e61df93..1bba2fa 100644 --- a/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts +++ b/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts @@ -2,4 +2,4 @@ import { Repository } from "typeorm"; export default interface IConnectionRepository{ connectionRepository: Repository; -} \ No newline at end of file +} // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src_refactory/applications/interfaces/services/IAccountService.ts b/src_refactory/applications/interfaces/services/IAccountService.ts index 41e43f9..40e15da 100644 --- a/src_refactory/applications/interfaces/services/IAccountService.ts +++ b/src_refactory/applications/interfaces/services/IAccountService.ts @@ -1,5 +1,5 @@ -import {IAccountDTO} from "../../../domain/interfaces/DTOs/IAccountDTO" -import {IAccount} from "../../../domain/interfaces/models/IAccount" +import {IAccountDTO} from "../../../domain/interfaces/DTOs/IAccountDTO"; +import {IAccount} from "../../../domain/interfaces/models/IAccount"; export default interface IAccountService { //get @@ -11,4 +11,4 @@ export default interface IAccountService { updateAccount(username: string, data: Partial): Promise; //delete deleteAccount(username: string): void; -} \ No newline at end of file +} // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src_refactory/applications/interfaces/services/IRequestService.ts b/src_refactory/applications/interfaces/services/IRequestService.ts index a4eea74..f625564 100644 --- a/src_refactory/applications/interfaces/services/IRequestService.ts +++ b/src_refactory/applications/interfaces/services/IRequestService.ts @@ -1,5 +1,5 @@ -import { IRequest } from "../../../domain/interfaces/models/IRequest" -import { staticReturnPaginatedRequest } from "../../../schemas/requestSchema" +import { IRequest } from "../../../domain/interfaces/models/IRequest"; +import { staticReturnPaginatedRequest } from "../../../schemas/requestSchema"; export default interface IRequestService { //get @@ -10,4 +10,4 @@ export default interface IRequestService { //post action(request_from: string, request_to: string, accept: boolean): Promise -} \ No newline at end of file +} // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src_refactory/applications/repositories/AccountRepository.ts b/src_refactory/applications/repositories/AccountRepository.ts index e5e5edf..1a8cccc 100644 --- a/src_refactory/applications/repositories/AccountRepository.ts +++ b/src_refactory/applications/repositories/AccountRepository.ts @@ -18,14 +18,14 @@ export default class AccountRepository implements IAccountRepository { async findFromUsername(username: string): Promise { let rs: IAccount | null = null; - try{ + try { rs = await this.connectionRepository.findOneBy({ [IAccountEnv.USERNAME]: username }); - }catch(err){ + } catch (err){ logger.error("Failed exec query findFromUsername, details:", err); throw new ApiErrorGeneric(err); } - if(rs === null){ + if (rs === null){ throw new ApiNotFound(`Not found this username '${username}'`); } @@ -36,9 +36,9 @@ export default class AccountRepository implements IAccountRepository { async createAccount(data: Partial): Promise { data[IAccountEnv.USERNAME] = data[IAccountEnv.USERNAME].toLowerCase(); - try{ - await this.connectionRepository.insert(data) - }catch(err){ + try { + await this.connectionRepository.insert(data); + } catch (err){ logger.error("Failed exec query createAccount, details:", err); throw new ApiErrorGeneric(err); } @@ -47,14 +47,14 @@ export default class AccountRepository implements IAccountRepository { //put async updateAccount(username: string, data: Partial): Promise { let rs: UpdateResult; - try{ + try { rs = await this.connectionRepository.update({ [IAccountEnv.USERNAME]: username }, data); - }catch(err){ + } catch (err){ logger.error("Failed exec query updateAccount, details:", err); throw new ApiErrorGeneric(err); } - if(rs.affected <= 0){ + if (rs.affected <= 0){ throw new ApiNotFound(`Cannot update information of ${username}`); } } @@ -62,14 +62,14 @@ export default class AccountRepository implements IAccountRepository { //delete async deleteAccount(username: string): Promise { let rs: DeleteResult; - try{ + try { rs = await this.connectionRepository.delete({ [IAccountEnv.USERNAME]: username }); - }catch(err){ + } catch (err){ logger.error("Failed exec query updateAccount, details:", err); throw new ApiErrorGeneric(err); } - if(rs.affected <= 0){ + if (rs.affected <= 0){ throw new ApiNotFound(`Cannot delete ${username}`); } } diff --git a/src_refactory/applications/repositories/RequestRepository.ts b/src_refactory/applications/repositories/RequestRepository.ts index cf80a64..861f855 100644 --- a/src_refactory/applications/repositories/RequestRepository.ts +++ b/src_refactory/applications/repositories/RequestRepository.ts @@ -16,45 +16,45 @@ export default class RequestRepository implements IRequestRepository { async findByRequest(request_from: string, request_to: string): Promise { let request: IRequest; - try{ + try { request = await this.connectionRepository.findOneBy({ [IRequestEnv.REQUEST_FROM]: request_from, [IRequestEnv.REQUEST_TO]: request_to }); - }catch(err){ + } catch (err){ logger.error("Failed exec query findByTarget, details:", err); throw new ApiErrorGeneric(err); } - if(request === null){ + if (request === null){ throw new ApiNotFound(`Not found request with request_from: "${request_from}" request_to: "${request_to}"`); } return request; } async create(data: Partial): Promise { - try{ + try { await this.connectionRepository.insert(data); - }catch(err){ + } catch (err){ logger.error("Failed exec query create, details:", err); throw new ApiErrorGeneric(err); } } async delete(request_from: string, request_to: string): Promise { - let rs: DeleteResult - try{ + let rs: DeleteResult; + try { rs = await this.connectionRepository.delete({[IRequestEnv.REQUEST_FROM]: request_from, [IRequestEnv.REQUEST_TO]: request_to}); - }catch(err){ + } catch (err){ logger.error("Failed exec query delete, details:", err); throw new ApiErrorGeneric(err); } - if(rs.affected <= 0){ - throw new ApiNotFound(`Cannot delete request with request_from: "${request_from}" request_to: "${request_to}"`) + if (rs.affected <= 0){ + throw new ApiNotFound(`Cannot delete request with request_from: "${request_from}" request_to: "${request_to}"`); } } async listPaginated(request_from: string, skip: number = 0, length: number = 10): Promise> { let rs: Array = []; - try{ + try { rs = await this.connectionRepository.find({where: {[IRequestEnv.REQUEST_FROM]: request_from}, order: {[IRequestEnv.REQUEST_TIME]: "ASC"}, skip, take: length}); - }catch(err){ + } catch (err){ logger.error("Failed exec query listPaginated, details:", err); throw new ApiErrorGeneric(err); } @@ -62,9 +62,9 @@ export default class RequestRepository implements IRequestRepository { return rs; } async countTotalFromRequestFrom(request_from: string): Promise { - try{ + try { return await this.connectionRepository.count({where: {[IRequestEnv.REQUEST_FROM]: request_from}}); - }catch(err){ + } catch (err){ logger.error("Failed exec query countTotal, details:", err); throw new ApiErrorGeneric(err); } diff --git a/src_refactory/applications/services/AccountService.ts b/src_refactory/applications/services/AccountService.ts index ac0e46e..2a99c67 100644 --- a/src_refactory/applications/services/AccountService.ts +++ b/src_refactory/applications/services/AccountService.ts @@ -6,10 +6,10 @@ import { IAccount, IAccountEnv } from "../../domain/interfaces/models/IAccount"; import AccountRepository from "../repositories/AccountRepository"; -import {hashPassword} from "../../utils/AccountUtils"; +import {hashPassword} from "../../utils/accountUtils"; import { ApiConflict, ApiNotFound, ApiUnauthorized } from "../../modules/api"; -import { objectAssign } from "../../utils/utils"; +import { objectAssign } from "../../utils/genericUtils"; export class AccountService implements IAccountService { accountRepository = new AccountRepository(); @@ -25,17 +25,17 @@ export class AccountService implements IAccountService { async login(username: string, password: string): Promise { let user: IAccount; - try{ + try { user = await this.accountRepository.findFromUsername(username); - }catch(e){ - if(e instanceof ApiNotFound){ + } catch (e){ + if (e instanceof ApiNotFound){ throw new ApiUnauthorized("Username/Password wrong"); - }else{ + } else { throw new e; } } - if(hashPassword(password) !== user[IAccountEnv.PASSWORD]){ + if (hashPassword(password) !== user[IAccountEnv.PASSWORD]){ throw new ApiUnauthorized("Username/Password wrong"); } @@ -44,16 +44,16 @@ export class AccountService implements IAccountService { async createAccount(data: Partial): Promise { const username = data[IAccountEnv.USERNAME]; - try{ + try { await this.accountRepository.findFromUsername(username); - }catch(e){ - if(e instanceof ApiNotFound){ + } catch (e){ + if (e instanceof ApiNotFound){ data[IAccountEnv.PASSWORD] = hashPassword(data[IAccountEnv.PASSWORD]); await this.accountRepository.createAccount(data); const user = await this.accountRepository.findFromUsername(data[IAccountEnv.USERNAME]); return objectAssign(user, IAccountDTOEnv); - }else{ + } else { throw new e; } } diff --git a/src_refactory/applications/services/RequestService.ts b/src_refactory/applications/services/RequestService.ts index 2e9b728..914bd95 100644 --- a/src_refactory/applications/services/RequestService.ts +++ b/src_refactory/applications/services/RequestService.ts @@ -1,8 +1,6 @@ -import _ from "lodash"; - import { ApiBadRequest, ApiConflict, ApiNotFound } from "../../modules/api"; -import { objectAssign } from "../../utils/utils"; +import { objectAssign } from "../../utils/genericUtils"; import { IRequestDTO, IRequestDTOEnv } from "../../domain/interfaces/DTOs/IRequestDTO"; import { IRequest, IRequestEnv } from "../../domain/interfaces/models/IRequest"; @@ -18,18 +16,18 @@ export class RequestService implements IRequestService { accountRepository = new AccountRepository(); async create(data: Partial): Promise { - if(data[IRequestEnv.REQUEST_FROM].toLowerCase() === data[IRequestEnv.REQUEST_TO].toLowerCase()){ + if (data[IRequestEnv.REQUEST_FROM].toLowerCase() === data[IRequestEnv.REQUEST_TO].toLowerCase()){ throw new ApiBadRequest(`${IRequestEnv.REQUEST_FROM} cannot be same ${IRequestEnv.REQUEST_TO}`); } const {findRequest, findRequestTO} = await async.parallel({ findRequest: async () => { - try{ + try { await this.requestRepository.findByRequest(data[IRequestEnv.REQUEST_FROM], data[IRequestEnv.REQUEST_TO]); - }catch(err){ - if(err instanceof ApiNotFound){ + } catch (err){ + if (err instanceof ApiNotFound){ return false; - }else{ + } else { throw new err; } } @@ -37,25 +35,25 @@ export class RequestService implements IRequestService { return true; }, findRequestTO: async () => { - try{ + try { await this.accountRepository.findFromUsername(data[IRequestEnv.REQUEST_TO]); - }catch(err){ - if(err instanceof ApiNotFound){ + } catch (err){ + if (err instanceof ApiNotFound){ return false; - }else{ + } else { throw new err; } } return true; } - }) + }); - if(!findRequest && findRequestTO){ + if (!findRequest && findRequestTO){ return await this.requestRepository.create(data); - }else if(!findRequestTO){ + } else if (!findRequestTO){ throw new ApiNotFound(`The user "${data[IRequestEnv.REQUEST_TO]}" not exist!`); - }else{ + } else { throw new ApiConflict("The request to become a friend has already been sent"); } } @@ -72,6 +70,6 @@ export class RequestService implements IRequestService { return { list, max_count: count - } + }; } } \ No newline at end of file diff --git a/src_refactory/controllers/account/create.ts b/src_refactory/controllers/accountController/createRoute.ts similarity index 83% rename from src_refactory/controllers/account/create.ts rename to src_refactory/controllers/accountController/createRoute.ts index fb85c2b..86925eb 100644 --- a/src_refactory/controllers/account/create.ts +++ b/src_refactory/controllers/accountController/createRoute.ts @@ -9,19 +9,19 @@ import fastify from "../../server/fastify"; const accountService = new AccountService(); -const options: RouteShorthandOptions = { +const options: RouteShorthandOptions = { schema: { - tags: ['account'], - summary: 'Create new account', + tags: ["account"], + summary: "Create new account", body: { $ref: SCHEMA_CREATE_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_ACCOUNT }, 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 401: { $ref: SCHEMA_BAD_REQUEST }, + 401: { $ref: SCHEMA_BAD_REQUEST } } } -} +}; fastify.post<{Querystring: staticCreateAccount}>(`${PATH_BASE_CONTROLLER}/create`, options, async (request) => { return await accountService.createAccount(request.body); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src_refactory/controllers/account/delete.ts b/src_refactory/controllers/accountController/deleteRoute.ts similarity index 82% rename from src_refactory/controllers/account/delete.ts rename to src_refactory/controllers/accountController/deleteRoute.ts index e51c340..fc9cb95 100644 --- a/src_refactory/controllers/account/delete.ts +++ b/src_refactory/controllers/accountController/deleteRoute.ts @@ -9,23 +9,23 @@ import fastify from "../../server/fastify"; const accountService = new AccountService(); -const options: RouteShorthandOptions = { +const options: RouteShorthandOptions = { schema: { - tags: ['account'], - summary: 'Delete account', + tags: ["account"], + summary: "Delete account", querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_VOID }, 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 404: { $ref: SCHEMA_NOT_FOUND }, + 404: { $ref: SCHEMA_NOT_FOUND } } } -} +}; fastify.delete<{Querystring: staticQueryUsernameAccount}>(`${PATH_BASE_CONTROLLER}/delete`, options, async (request) => { const {username} = request.query; await accountService.deleteAccount(username); - return { response: "ok" } -}) \ No newline at end of file + return { response: "ok" }; +}); \ No newline at end of file diff --git a/src_refactory/controllers/account/find.ts b/src_refactory/controllers/accountController/findRoute.ts similarity index 85% rename from src_refactory/controllers/account/find.ts rename to src_refactory/controllers/accountController/findRoute.ts index b730977..459f482 100644 --- a/src_refactory/controllers/account/find.ts +++ b/src_refactory/controllers/accountController/findRoute.ts @@ -9,21 +9,21 @@ import fastify from "../../server/fastify"; const accountService = new AccountService(); -const options: RouteShorthandOptions = { +const options: RouteShorthandOptions = { schema: { - tags: ['account'], - summary: 'Find account', + tags: ["account"], + summary: "Find account", querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_ACCOUNT }, 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 404: { $ref: SCHEMA_NOT_FOUND }, + 404: { $ref: SCHEMA_NOT_FOUND } } } -} +}; fastify.get<{Querystring: staticQueryUsernameAccount}>(`${PATH_BASE_CONTROLLER}/find`, options, async (request) => { const {username} = request.query; return await accountService.findFromUsername(username); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src_refactory/controllers/account/update.ts b/src_refactory/controllers/accountController/updateRoute.ts similarity index 87% rename from src_refactory/controllers/account/update.ts rename to src_refactory/controllers/accountController/updateRoute.ts index 1c22703..6c73ad9 100644 --- a/src_refactory/controllers/account/update.ts +++ b/src_refactory/controllers/accountController/updateRoute.ts @@ -9,19 +9,19 @@ import fastify from "../../server/fastify"; const accountService = new AccountService(); -const options: RouteShorthandOptions = { +const options: RouteShorthandOptions = { schema: { - tags: ['account'], - summary: 'Update values of account', + tags: ["account"], + summary: "Update values of account", querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, body: { $ref: SCHEMA_UPDATE_ACCOUNT }, response: { 200: { $ref: SCHEMA_RETURN_ACCOUNT }, 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 404: { $ref: SCHEMA_NOT_FOUND }, + 404: { $ref: SCHEMA_NOT_FOUND } } } -} +}; fastify.put<{Querystring: staticQueryUsernameAccount, Body: staticUpdateAccount}>(`${PATH_BASE_CONTROLLER}/update`, options, async (request) => { const {username} = request.query; @@ -30,4 +30,4 @@ fastify.put<{Querystring: staticQueryUsernameAccount, Body: staticUpdateAccount} console.log(request.body); return await accountService.updateAccount(username, account); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src_refactory/controllers/request/action.ts b/src_refactory/controllers/requestController/actionRoute.ts similarity index 79% rename from src_refactory/controllers/request/action.ts rename to src_refactory/controllers/requestController/actionRoute.ts index 6f12d73..dc0f581 100644 --- a/src_refactory/controllers/request/action.ts +++ b/src_refactory/controllers/requestController/actionRoute.ts @@ -9,22 +9,22 @@ import fastify from "../../server/fastify"; const requestService = new RequestService(); -const options: RouteShorthandOptions = { +const options: RouteShorthandOptions = { schema: { - tags: ['request'], - summary: 'Choose accept or refuse request friend', + tags: ["request"], + summary: "Choose accept or refuse request friend", querystring: { $ref: SCHEMA_ACTION_REQUEST }, response: { 200: { $ref: SCHEMA_RETURN_VOID }, - 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 500: { $ref: SCHEMA_INTERNAL_SERVER } } } -} +}; fastify.post<{Querystring: staticActionRequest}>(`${PATH_BASE_CONTROLLER}/action`, options, async (request) => { const {accept, request_from, request_to} = request.query; await requestService.action(request_from, request_to, accept); - return { response: "ok" } -}) \ No newline at end of file + return { response: "ok" }; +}); \ No newline at end of file diff --git a/src_refactory/controllers/request/create.ts b/src_refactory/controllers/requestController/createRoute.ts similarity index 81% rename from src_refactory/controllers/request/create.ts rename to src_refactory/controllers/requestController/createRoute.ts index 2955f4e..f10511e 100644 --- a/src_refactory/controllers/request/create.ts +++ b/src_refactory/controllers/requestController/createRoute.ts @@ -9,22 +9,22 @@ import fastify from "../../server/fastify"; const requestService = new RequestService(); -const options: RouteShorthandOptions = { +const options: RouteShorthandOptions = { schema: { - tags: ['request'], - summary: 'Create request friend', + tags: ["request"], + summary: "Create request friend", body: { $ref: SCHEMA_CREATE_REQUEST }, response: { 200: { $ref: SCHEMA_RETURN_VOID }, 401: { $ref: SCHEMA_BAD_REQUEST }, 404: { $ref: SCHEMA_NOT_FOUND }, - 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 500: { $ref: SCHEMA_INTERNAL_SERVER } } } -} +}; fastify.post<{Body: staticCreateRequest}>(`${PATH_BASE_CONTROLLER}/create`, options, async (request) => { await requestService.create(request.body); - return { response: "ok" } -}) \ No newline at end of file + return { response: "ok" }; +}); \ No newline at end of file diff --git a/src_refactory/controllers/request/list.ts b/src_refactory/controllers/requestController/listRoute.ts similarity index 83% rename from src_refactory/controllers/request/list.ts rename to src_refactory/controllers/requestController/listRoute.ts index 6bcf545..168c3ea 100644 --- a/src_refactory/controllers/request/list.ts +++ b/src_refactory/controllers/requestController/listRoute.ts @@ -9,20 +9,20 @@ import fastify from "../../server/fastify"; const requestService = new RequestService(); -const options: RouteShorthandOptions = { +const options: RouteShorthandOptions = { schema: { - tags: ['request'], - summary: 'List request for accept or reject', + tags: ["request"], + summary: "List request for accept or reject", querystring: { $ref: SCHEMA_QUERY_PAGINATED_REQUEST }, response: { 200: { $ref: SCHEMA_RETURN_PAGINATED_REQUEST }, - 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 500: { $ref: SCHEMA_INTERNAL_SERVER } } } -} +}; fastify.get<{Querystring: staticQueryPaginatedRequest}>(`${PATH_BASE_CONTROLLER}/list`, options, async (request) => { const {length, request_from, skip} = request.query; return await requestService.listPaginated(request_from, skip, length); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts b/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts index 1b7ff89..5d5b321 100644 --- a/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts +++ b/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts @@ -9,7 +9,7 @@ export enum IRequestDTOEnv { export const requestDTOSchema = Type.Object({ [IRequestDTOEnv.REQUEST_FROM]: Type.String({maxLength: 250}), [IRequestDTOEnv.REQUEST_TO]: Type.String({maxLength: 250}), - [IRequestDTOEnv.REQUEST_TIME]: Type.String({format: 'date-time'}), -}) + [IRequestDTOEnv.REQUEST_TIME]: Type.String({format: "date-time"}) +}); export type IRequestDTO = typeof requestDTOSchema.static \ No newline at end of file diff --git a/src_refactory/domain/interfaces/models/IRequest.ts b/src_refactory/domain/interfaces/models/IRequest.ts index 5fc7926..e7c851e 100644 --- a/src_refactory/domain/interfaces/models/IRequest.ts +++ b/src_refactory/domain/interfaces/models/IRequest.ts @@ -9,7 +9,7 @@ export enum IRequestEnv { export const requestSchema = Type.Object({ [IRequestEnv.REQUEST_FROM]: Type.String({maxLength: 250}), [IRequestEnv.REQUEST_TO]: Type.String({maxLength: 250}), - [IRequestEnv.REQUEST_TIME]: Type.String({format: 'date-time'}), -}) + [IRequestEnv.REQUEST_TIME]: Type.String({format: "date-time"}) +}); export type IRequest = typeof requestSchema.static \ No newline at end of file diff --git a/src_refactory/eslint.config.js b/src_refactory/eslint.config.js new file mode 100644 index 0000000..c1552df --- /dev/null +++ b/src_refactory/eslint.config.js @@ -0,0 +1,76 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; +import stylisticJs from "@stylistic/eslint-plugin-js"; +import parserTs from "@typescript-eslint/parser"; +import checkFile from "eslint-plugin-check-file"; + + +export default [ + { + files: ["**/*.{js,mjs,cjs,ts}"] + }, + { + languageOptions: { + globals: globals.node, + parser: parserTs + } + }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + { + plugins: { + "@stylistic": stylisticJs, + "check-file": checkFile + }, + rules: { + //syntax code + "@typescript-eslint/no-unused-vars": "warn", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/ban-ts-comment": "off", + + //syntax code + plugin + "@stylistic/quotes": ["error", "double"], + "@stylistic/array-bracket-newline": ["error", { "multiline": true }], + "@stylistic/array-bracket-spacing": ["error", "never"], + "@stylistic/array-element-newline": ["error", "consistent"], + "@stylistic/arrow-parens": ["error", "always"], + "@stylistic/arrow-spacing": "error", + "@stylistic/block-spacing": "error", + "@stylistic/brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "@stylistic/comma-dangle": ["error", "never"], + "@stylistic/comma-spacing": ["error", { "before": false, "after": true }], + "@stylistic/dot-location": ["error", "object"], + "@stylistic/keyword-spacing": ["error", { "before": true }], + "@stylistic/no-multi-spaces": "error", + "@stylistic/no-mixed-operators": "error", + "@stylistic/no-floating-decimal": "error", + "@stylistic/semi": "error", + "@stylistic/wrap-regex": "error", + + + //syntax name file + plugin + "check-file/filename-naming-convention": [ + "error", + { + "applications/interfaces/services/**/*.{js,ts}": "I+([A-Z])+([a-zA-Z])Service", + "applications/interfaces/repositories/**/*.{js,ts}": "I+([A-Z])+([a-zA-Z])Repository", + "applications/services/**/*.{js,ts}": "([A-Z])+([a-zA-Z])Service", + "applications/repositories/**/*.{js,ts}": "([A-Z])+([a-zA-Z])Repository", + "controllers/**/*": "*([a-z])Route", + "domain/interfaces/DTOs/**/*": "I+([A-Z])+([a-zA-Z])DTO", + "domain/interfaces/models/**/*": "I+([A-Z])+([a-zA-Z])", + "domain/models/**/*": "PASCAL_CASE", + "schemas/**/*": "*([a-zA-Z])Schema", + "utils/**/*": "*([a-z])Utils" + } + ], + "check-file/folder-naming-convention": [ + "error", + { + "controllers/*/": "*([a-z])Controller" + } + ] + } + } +]; \ No newline at end of file diff --git a/src_refactory/index.ts b/src_refactory/index.ts index 74c09a4..ec64e68 100644 --- a/src_refactory/index.ts +++ b/src_refactory/index.ts @@ -1,7 +1,7 @@ import {config} from "dotenv"; -import {init as initServerFastify} from "./server/fastify" -import {init as initPostgres} from "./server/postgres" +import {init as initServerFastify} from "./server/fastify"; +import {init as initPostgres} from "./server/postgres"; //load env config(); diff --git a/src_refactory/modules/api.ts b/src_refactory/modules/api.ts index 37fa648..c1bdf67 100644 --- a/src_refactory/modules/api.ts +++ b/src_refactory/modules/api.ts @@ -35,4 +35,4 @@ export { ApiConflict, ApiUnauthorized, ApiBadRequest -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/package.json b/src_refactory/package.json index b878baa..21dc396 100644 --- a/src_refactory/package.json +++ b/src_refactory/package.json @@ -6,7 +6,9 @@ "scripts": { "start": "npx tsx index.ts", "clear": "rm -rf node_modules package-lock.json", - "create_link_references": "cd ../references/src_refactory && ln -s ../../src_refactory/node_modules && ln -s ../../src_refactory/package.json && ln -s ../../src_refactory/tsconfig.json" + "create_link_references": "cd ../references/src_refactory && ln -s ../../src_refactory/node_modules && ln -s ../../src_refactory/package.json && ln -s ../../src_refactory/tsconfig.json", + "eslint": "npx eslint .", + "eslint-fix": "npx eslint --fix ." }, "keywords": [], "author": "cesxhin", @@ -16,12 +18,15 @@ "@fastify/swagger": "^8.15.0", "@fastify/swagger-ui": "4.1.0", "@sinclair/typebox": "^0.33.7", + "@stylistic/eslint-plugin-js": "^2.8.0", "@types/async": "^3.2.24", "@types/crypto-js": "^4.2.2", + "@typescript-eslint/parser": "^8.6.0", "async": "^3.2.6", "chalk": "^5.3.0", "crypto-js": "^4.2.0", "dotenv": "^16.4.5", + "eslint-plugin-check-file": "^2.8.0", "fastify": "^4.28.1", "joi": "^17.13.3", "lodash": "^4.17.21", @@ -32,11 +37,15 @@ "typescript": "^5.5.4" }, "devDependencies": { + "@eslint/js": "^9.11.0", "@types/lodash": "^4.17.7", "@types/luxon": "^3.4.2", "@types/node": "^22.5.0", "@types/pg": "^8.11.6", "@types/pg-pool": "^2.0.6", - "tsx": "^4.16.2" + "eslint": "^9.11.0", + "globals": "^15.9.0", + "tsx": "^4.16.2", + "typescript-eslint": "^8.6.0" } -} \ No newline at end of file +} diff --git a/src_refactory/schemas/accountSchema.ts b/src_refactory/schemas/accountSchema.ts index 2062bcd..3ac302f 100644 --- a/src_refactory/schemas/accountSchema.ts +++ b/src_refactory/schemas/accountSchema.ts @@ -1,8 +1,8 @@ -import { Type } from '@sinclair/typebox' +import { Type } from "@sinclair/typebox"; -import { accountSchema, IAccountEnv } from "../domain/interfaces/models/IAccount" -import { accountDTOSchema } from '../domain/interfaces/DTOs/IAccountDTO'; -import { convertToOptional } from '../utils/schemaUtils'; +import { accountSchema, IAccountEnv } from "../domain/interfaces/models/IAccount"; +import { accountDTOSchema } from "../domain/interfaces/DTOs/IAccountDTO"; +import { convertToOptional } from "../utils/schemaUtils"; //path base const PATH_BASE_CONTROLLER = "/account"; @@ -23,7 +23,7 @@ const queryUsernameAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME], { const returnAccount = Type.Intersect([accountDTOSchema], { $id: SCHEMA_RETURN_ACCOUNT }); //load schemas -export default [createAccount, updateAccount, returnAccount, queryUsernameAccount] +export default [createAccount, updateAccount, returnAccount, queryUsernameAccount]; type staticCreateAccount = typeof createAccount.static type staticUpdateAccount = typeof updateAccount.static @@ -42,4 +42,4 @@ export { SCHEMA_RETURN_ACCOUNT, SCHEMA_UPDATE_ACCOUNT, SCHEMA_QUERY_USERNAME_ACCOUNT -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/schemas/generic/genericSchema.ts b/src_refactory/schemas/generic/genericSchema.ts index 6ff77c1..a3d69ff 100644 --- a/src_refactory/schemas/generic/genericSchema.ts +++ b/src_refactory/schemas/generic/genericSchema.ts @@ -1,4 +1,4 @@ -import { Type } from '@sinclair/typebox' +import { Type } from "@sinclair/typebox"; const SCHEMA_RETURN_VOID = "SchemaReturnVoid"; const SCHEMA_NOT_FOUND = "SchemaNotFound"; @@ -7,7 +7,7 @@ const SCHEMA_CONFLICT = "SchemaConflict"; const SCHEMA_BAD_REQUEST = "SchemaBadRequest"; const returnVoid = Type.Object({ - response: Type.String({default: 'ok'}) + response: Type.String({default: "ok"}) }, {$id: SCHEMA_RETURN_VOID}); const templateErrorSchema = Type.Object({ @@ -15,20 +15,28 @@ const templateErrorSchema = Type.Object({ error: Type.String({default: "Name error"}) }); -const notFound = Type.Intersect([templateErrorSchema, Type.Object({ +const notFound = Type.Intersect([ +templateErrorSchema, Type.Object({ statusCode: Type.Number({default: 404}) -})], { $id: SCHEMA_NOT_FOUND }); -const internalServer = Type.Intersect([templateErrorSchema, Type.Object({ +}) +], { $id: SCHEMA_NOT_FOUND }); +const internalServer = Type.Intersect([ +templateErrorSchema, Type.Object({ statusCode: Type.Number({default: 500}) -})], { $id: SCHEMA_INTERNAL_SERVER }); -const conflict = Type.Intersect([templateErrorSchema, Type.Object({ +}) +], { $id: SCHEMA_INTERNAL_SERVER }); +const conflict = Type.Intersect([ +templateErrorSchema, Type.Object({ statusCode: Type.Number({default: 401}) -})], { $id: SCHEMA_CONFLICT }); -const badRequest = Type.Intersect([templateErrorSchema, Type.Object({ +}) +], { $id: SCHEMA_CONFLICT }); +const badRequest = Type.Intersect([ +templateErrorSchema, Type.Object({ statusCode: Type.Number({default: 400}) -})], { $id: SCHEMA_BAD_REQUEST }); +}) +], { $id: SCHEMA_BAD_REQUEST }); -export default [returnVoid, notFound, internalServer, conflict, badRequest] +export default [returnVoid, notFound, internalServer, conflict, badRequest]; type staticReturnVoid = typeof returnVoid.static @@ -40,4 +48,4 @@ export { SCHEMA_BAD_REQUEST, SCHEMA_CONFLICT, SCHEMA_INTERNAL_SERVER -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/schemas/generic/paginationSchema.ts b/src_refactory/schemas/generic/paginationSchema.ts index 72e1ec5..70d775c 100644 --- a/src_refactory/schemas/generic/paginationSchema.ts +++ b/src_refactory/schemas/generic/paginationSchema.ts @@ -1,8 +1,8 @@ -import { Type, TObject } from '@sinclair/typebox' +import { Type, TObject } from "@sinclair/typebox"; const queryPagination = Type.Object({ skip: Type.Number({minimum: 0, default: 0}), - length: Type.Number({minimum: 10, default: 10}), + length: Type.Number({minimum: 10, default: 10}) }); const schemaReturnPagination = (schema: T, id: string) => Type.Object({ @@ -14,4 +14,4 @@ export { schemaReturnPagination, queryPagination -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/schemas/requestSchema.ts b/src_refactory/schemas/requestSchema.ts index acd9a7b..6a62dbd 100644 --- a/src_refactory/schemas/requestSchema.ts +++ b/src_refactory/schemas/requestSchema.ts @@ -1,7 +1,7 @@ -import { Type } from '@sinclair/typebox' -import { queryPagination, schemaReturnPagination } from './generic/paginationSchema'; -import { requestDTOSchema } from '../domain/interfaces/DTOs/IRequestDTO'; -import { IRequestEnv, requestSchema } from '../domain/interfaces/models/IRequest'; +import { Type } from "@sinclair/typebox"; +import { queryPagination, schemaReturnPagination } from "./generic/paginationSchema"; +import { requestDTOSchema } from "../domain/interfaces/DTOs/IRequestDTO"; +import { IRequestEnv, requestSchema } from "../domain/interfaces/models/IRequest"; //path base const PATH_BASE_CONTROLLER = "/request"; @@ -26,7 +26,7 @@ const queryPaginatedRequest = Type.Intersect([Type.Pick(requestSchema, [IRequest const returnPaginatedRequest = schemaReturnPagination(requestDTOSchema, SCHEMA_RETURN_PAGINATED_REQUEST); //load schemas -export default [createRequest, actionRequest, returnPaginatedRequest, queryPaginatedRequest] +export default [createRequest, actionRequest, returnPaginatedRequest, queryPaginatedRequest]; type staticCreateRequest = typeof createRequest.static; type staticActionRequest = typeof actionRequest.static; @@ -45,4 +45,4 @@ export { SCHEMA_ACTION_REQUEST, SCHEMA_RETURN_PAGINATED_REQUEST, SCHEMA_QUERY_PAGINATED_REQUEST -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/server/fastify/index.ts b/src_refactory/server/fastify/index.ts index 787c4e5..ef50716 100644 --- a/src_refactory/server/fastify/index.ts +++ b/src_refactory/server/fastify/index.ts @@ -1,14 +1,14 @@ import fs from "fs"; import _ from "lodash"; import path from "path"; -import Fastify from 'fastify'; -import { DateTime } from 'luxon'; +import Fastify from "fastify"; +import { DateTime } from "luxon"; import { env, exit } from "process"; import { IConfig } from "./interfaces/IConfig"; import { ApiBadRequest, ApiConflict, ApiErrorGeneric, ApiNotFound, ApiUnauthorized } from "../../modules/api"; -import Logger from '../../modules/logger'; +import Logger from "../../modules/logger"; const logger = new Logger("server-fastify"); const __dirname = path.resolve(); @@ -21,21 +21,21 @@ async function init({pathControllers = "controllers", pathSchemas = "schemas", s logger.info("Starting service fastify..."); //swagger - if(swagger){ + if (swagger){ logger.debug("Starting load swagger"); await fastify.register(await import("@fastify/swagger")); - await fastify.register(await import('@fastify/swagger-ui'), { - routePrefix: '/', + await fastify.register(await import("@fastify/swagger-ui"), { + routePrefix: "/", uiConfig: { - docExpansion: 'list', + docExpansion: "list", deepLinking: false }, uiHooks: { - onRequest: function (request, reply, next) { next() }, - preHandler: function (request, reply, next) { next() } + onRequest: function (request, reply, next) { next(); }, + preHandler: function (request, reply, next) { next(); } }, logLevel: "error" - }) + }); logger.debug("Finish load swagger"); } @@ -49,18 +49,18 @@ async function init({pathControllers = "controllers", pathSchemas = "schemas", s await loadSchemas(pathSchemas); logger.debug("Finish load all schemas"); - await fastify.ready() - fastify.swagger() + await fastify.ready(); + fastify.swagger(); //server let connection = ""; - try{ + try { connection = await fastify.listen({ port: _.isNil(env.SERVER_PORT)? 3001 : parseInt(env.SERVER_PORT), - host: env.SERVER_PORT || "127.0.0.1", - }) - }catch(err){ - logger.fatal(`Stop service fastify reason:`, err); + host: env.SERVER_PORT || "127.0.0.1" + }); + } catch (err){ + logger.fatal("Stop service fastify reason:", err); exit(1); } @@ -73,9 +73,9 @@ async function loadControllers(pathControllers: string){ //get list folder inside controllers let listFileControllers: Array = []; - try{ - listFileControllers = fs.readdirSync(basePathController).filter((file) => file.indexOf('.') === -1).map((folder) => path.join(basePathController, folder)); - }catch(err){ + try { + listFileControllers = fs.readdirSync(basePathController).filter((file) => file.indexOf(".") === -1).map((folder) => path.join(basePathController, folder)); + } catch (err){ logger.fatal("Cannot read folder", pathControllers, "details: ", err); exit(1); } @@ -87,29 +87,29 @@ async function loadControllers(pathControllers: string){ for (const fileController of listFileControllers) { const totalRoutes = await loadRoutes(fileController); - if(totalRoutes > 0){ + if (totalRoutes > 0){ logger.debug("Done import controller", path.basename(fileController)); success++; - }else{ + } else { logger.error("Controller", path.basename(fileController), "maybe has some error"); } } - if(success === 0){ + if (success === 0){ logger.fatal("controllers none loaded"); exit(1); } - logger.debug('Total controllers loaded', success); + logger.debug("Total controllers loaded", success); } //load routes async function loadRoutes(pathController: string){ let listFileRoutes: Array = []; - try{ + try { listFileRoutes = fs.readdirSync(pathController).filter((file) => file.indexOf(".") !== -1).map((file) => path.join(pathController, file)); - }catch(err){ + } catch (err){ logger.error("Cannot read controller", path.basename(pathController), "details:", err); } @@ -118,9 +118,9 @@ async function loadRoutes(pathController: string){ let success = 0; for (const fileRoute of listFileRoutes) { - try{ + try { await import(fileRoute); - }catch(err){ + } catch (err){ logger.error("Failed load route", `"${fileRoute}" details:`, err); continue; } @@ -129,7 +129,7 @@ async function loadRoutes(pathController: string){ success++; } - logger.debug('Loaded', `(${success}) routes from`, path.basename(pathController)); + logger.debug("Loaded", `(${success}) routes from`, path.basename(pathController)); return success; } @@ -137,32 +137,32 @@ async function loadRoutes(pathController: string){ async function loadSchemas(pathSchemas){ const basePathSchemas = path.join(__dirname, pathSchemas); - if(!fs.existsSync(basePathSchemas)){ - logger.warn("Not exist root folder schemas, skip schemas") + if (!fs.existsSync(basePathSchemas)){ + logger.warn("Not exist root folder schemas, skip schemas"); return; } //get list folder inside controllers - const listFileSchemas = fs.readdirSync(basePathSchemas, {recursive: true, withFileTypes: true}).filter((singlePath) => singlePath.isFile()).map((singlePath) => path.join(singlePath.parentPath, singlePath.name)); + const listFileSchemas = fs.readdirSync(basePathSchemas, {recursive: true, withFileTypes: true}).filter((singlePath) => singlePath.isFile()).map((singlePath) => path.join(singlePath.parentPath, singlePath.name)); logger.debug(`List schemas available: ${listFileSchemas.map((file) => path.basename(file))}`); let success = 0; let listSchemas: Array; for (const fileSchema of listFileSchemas) { - try{ + try { listSchemas = (await import(fileSchema)).default; - }catch(err){ + } catch (err){ logger.error(`Failed load schema "${path.basename(fileSchema)}", details:`, err); continue; } - if(!_.isNil(listSchemas)){ + if (!_.isNil(listSchemas)){ for (const schema of listSchemas) { - try{ - fastify.addSchema(schema) - }catch(err){ - logger.error(`Failed add specific schema of ${schema['$id']}, details:`, err); + try { + fastify.addSchema(schema); + } catch (err){ + logger.error(`Failed add specific schema of ${schema["$id"]}, details:`, err); } } } @@ -180,7 +180,7 @@ fastify.addHook("onRequest", (req, replay, next) => { replay.startTime = DateTime.now().toISO(); next(); -}) +}); fastify.addHook("onResponse", (req, replay, next) => { //@ts-ignore @@ -188,72 +188,72 @@ fastify.addHook("onResponse", (req, replay, next) => { let bodyJson = {}; - if(env.LOG_LEVEL === "debug"){ + if (env.LOG_LEVEL === "debug"){ const body = req.body; - if(!_.isObject(body)){ - try{ + if (!_.isObject(body)){ + try { bodyJson = JSON.parse(body as string); - }catch{ + } catch { //ignore } - }else{ + } else { bodyJson = body; } } - const message = [req.raw.method, req.url.split('?')[0], JSON.stringify(req.query), JSON.stringify(bodyJson), replay.statusCode, `(${DateTime.now().diff(time).toMillis()} ms)`]; + const message = [req.raw.method, req.url.split("?")[0], JSON.stringify(req.query), JSON.stringify(bodyJson), replay.statusCode, `(${DateTime.now().diff(time).toMillis()} ms)`]; - if(replay.statusCode === 500){ + if (replay.statusCode === 500){ logger.error(...message); - }else if(replay.statusCode !== 200){ + } else if (replay.statusCode !== 200){ logger.warn(...message); - }else{ + } else { logger.info(...message); } next(); -}) +}); fastify.setErrorHandler((error, request, replay) => { const message = { error: error.name, message: error.message - } + }; - if(error instanceof ApiConflict){ + if (error instanceof ApiConflict){ return replay.status(409).send({ ...message, statusCode: 409 - }) - }else if(error instanceof ApiNotFound){ + }); + } else if (error instanceof ApiNotFound){ return replay.status(404).send({ ...message, statusCode: 404 }); - }else if(error instanceof ApiUnauthorized){ + } else if (error instanceof ApiUnauthorized){ return replay.status(401).send({ ...message, statusCode: 401 }); - }else if(error instanceof ApiErrorGeneric){ + } else if (error instanceof ApiErrorGeneric){ return replay.status(500).send({ ...message, statusCode: 500 }); - }else if(error instanceof ApiBadRequest){ + } else if (error instanceof ApiBadRequest){ return replay.status(400).send({ ...message, statusCode: 400 }); - }else{ + } else { logger.error(error); return error; } -}) +}); export default fastify; export { init -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/server/postgres/index.ts b/src_refactory/server/postgres/index.ts index dcbe366..8f0d2e1 100644 --- a/src_refactory/server/postgres/index.ts +++ b/src_refactory/server/postgres/index.ts @@ -1,5 +1,4 @@ import { DataSource } from "typeorm"; -import _ from "lodash"; import Logger from "../../modules/logger"; const logger = new Logger("pg"); @@ -23,22 +22,22 @@ async function init({ password, database, entities: [`${path.resolve()}/domain/models/*.ts`], - synchronize: process.env.NODE_ENV === 'dev', + synchronize: process.env.NODE_ENV === "dev", connectTimeoutMS: 5000 }); - try{ + try { pg = await pg.initialize(); - }catch(err){ - logger.error('Error initialize postgres, reason:', err); + } catch (err){ + logger.error("Error initialize postgres, reason:", err); return; } logger.debug("String connection:", `${address}:${port}`); - logger.info("Connected to pg!") + logger.info("Connected to pg!"); } export { pg, init -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/utils/AccountUtils.ts b/src_refactory/utils/accountUtils.ts similarity index 67% rename from src_refactory/utils/AccountUtils.ts rename to src_refactory/utils/accountUtils.ts index 5a6c411..346a933 100644 --- a/src_refactory/utils/AccountUtils.ts +++ b/src_refactory/utils/accountUtils.ts @@ -1,9 +1,9 @@ import CryptoJS from "crypto-js"; function hashPassword(password: string){ - return CryptoJS.SHA256(password).toString() + return CryptoJS.SHA256(password).toString(); } export { hashPassword -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/utils/utils.ts b/src_refactory/utils/genericUtils.ts similarity index 80% rename from src_refactory/utils/utils.ts rename to src_refactory/utils/genericUtils.ts index eb79693..57ff132 100644 --- a/src_refactory/utils/utils.ts +++ b/src_refactory/utils/genericUtils.ts @@ -1,9 +1,9 @@ import _ from "lodash"; function objectAssign(data: any, Idata: any){ - let newData = {}; + const newData = {}; for (const key in Idata) { - if(_.isObject(data)){ + if (_.isObject(data)){ newData[Idata[key]] = data[Idata[key]]; } } @@ -13,4 +13,4 @@ function objectAssign(data: any, Idata: any){ export { objectAssign -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src_refactory/utils/schemaUtils.ts b/src_refactory/utils/schemaUtils.ts index b502a62..79633b8 100644 --- a/src_refactory/utils/schemaUtils.ts +++ b/src_refactory/utils/schemaUtils.ts @@ -3,9 +3,9 @@ import { TSchema, Type } from "@sinclair/typebox"; function convertToOptional(schema: T, keys: Array, id: string){ const pick = Type.Pick(schema, keys); - return Type.Mapped(Type.KeyOf(pick), K => Type.Optional(Type.Index(pick, K)), { $id: id }); + return Type.Mapped(Type.KeyOf(pick), (K) => Type.Optional(Type.Index(pick, K)), { $id: id }); } export { convertToOptional -} \ No newline at end of file +}; \ No newline at end of file From 88e8d460e91ef36f9ee616d822fd7b784913ec03 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 15:48:51 +0200 Subject: [PATCH 11/21] Update fastify to v5, improvment types of request and replay and removed old project --- references | 1 - .../Cesxhin.AnimeManga.Api.csproj | 35 - .../Controllers/AccountController.cs | 134 --- .../Controllers/BookController.cs | 1044 ----------------- .../Controllers/GenericController.cs | 217 ---- .../Controllers/VideoController.cs | 981 ---------------- src/Cesxhin.AnimeManga.Api/Program.cs | 20 - src/Cesxhin.AnimeManga.Api/Startup.cs | 127 -- .../appsettings.Development.json | 9 - src/Cesxhin.AnimeManga.Api/appsettings.json | 10 - .../schema_template.json | 28 - .../Cesxhin.AnimeManga.Application.csproj | 26 - .../Controllers/IGeneralControllerBase.cs | 40 - .../Repositories/IAccountRepository.cs | 18 - .../IChapterBlackListRepository.cs | 8 - .../Repositories/IChapterQueueRepository.cs | 8 - .../IChapterRegisterRepository.cs | 8 - .../Repositories/IChapterRepository.cs | 10 - .../Repositories/IDescriptionRepository.cs | 9 - .../IEpisodeBlackListRepository.cs | 8 - .../Repositories/IEpisodeQueueRepository.cs | 8 - .../IEpisodeRegisterRepository.cs | 8 - .../Repositories/IEpisodeRepository.cs | 10 - .../Repositories/IGeneralNameRepository.cs | 22 - .../IGeneralObjectBlackListRepository.cs | 15 - .../IGeneralObjectQueueRepository.cs | 18 - .../IGeneralObjectRegisterRepository.cs | 19 - .../Repositories/IGeneralObjectRepository.cs | 23 - .../IProgressChapterRepository.cs | 12 - .../IProgressEpisodeRepository.cs | 12 - .../Interfaces/Services/IAccountService.cs | 18 - .../Services/IChapterBlackListService.cs | 8 - .../Services/IChapterQueueService.cs | 8 - .../Services/IChapterRegisterService.cs | 8 - .../Interfaces/Services/IChapterService.cs | 8 - .../Services/IDescriptionBookService.cs | 9 - .../Services/IDescriptionVideoService.cs | 9 - .../Services/IEpisodeBlackListService.cs | 13 - .../Services/IEpisodeQueueService.cs | 8 - .../Services/IEpisodeRegisterService.cs | 8 - .../Interfaces/Services/IEpisodeService.cs | 8 - .../Services/IGeneralNameService.cs | 24 - .../Interfaces/Services/IGeneralObject.cs | 23 - .../IGeneralObjectBlackListService.cs | 15 - .../Services/IGeneralObjectQueueService.cs | 18 - .../Services/IGeneralObjectRegister.cs | 19 - .../Services/IProgressChapterService.cs | 14 - .../Services/IProgressEpisodeService.cs | 14 - .../Services/AccountService.cs | 111 -- .../Services/ChapterBlackListService.cs | 61 - .../Services/ChapterQueueService.cs | 65 - .../Services/ChapterRegisterService.cs | 85 -- .../Services/ChapterService.cs | 99 -- .../Services/DescriptionBookService.cs | 278 ----- .../Services/DescriptionVideoService.cs | 286 ----- .../Services/EpisodeBlackListService.cs | 61 - .../Services/EpisodeQueueService.cs | 67 -- .../Services/EpisodeRegisterService.cs | 76 -- .../Services/EpisodeService.cs | 95 -- .../Services/ProgressChapterService.cs | 42 - .../Services/ProgressEpisodeService.cs | 42 - .../Cesxhin.AnimeManga.Persistence.csproj | 19 - .../Repositories/AccountRepository.cs | 152 --- .../ChapterBlackListRepository.cs | 90 -- .../Repositories/ChapterQueueRepository.cs | 113 -- .../Repositories/ChapterRegisterRepository.cs | 136 --- .../Repositories/ChapterRepository.cs | 219 ---- .../Repositories/DescriptionRepository.cs | 187 --- .../EpisodeBlackListRepository.cs | 90 -- .../Repositories/EpisodeQueueRepository.cs | 113 -- .../Repositories/EpisodeRegisterRepository.cs | 141 --- .../Repositories/EpisodeRepository.cs | 228 ---- .../Repositories/ProgressChapterRepository.cs | 91 -- .../Repositories/ProgressEpisodeRepository.cs | 91 -- .../repositories/IAccountRepository.ts | 0 .../repositories/IRequestRepository.ts | 0 .../generic/IConnectionRepository.ts | 0 .../interfaces/services/IAccountService.ts | 0 .../interfaces/services/IRequestService.ts | 0 .../repositories/AccountRepository.ts | 0 .../repositories/RequestRepository.ts | 0 .../applications/services/AccountService.ts | 0 .../applications/services/RequestService.ts | 0 .../accountController/createRoute.ts | 21 + .../accountController/deleteRoute.ts | 27 + .../accountController/findRoute.ts | 25 + .../accountController/updateRoute.ts | 27 + .../requestController/actionRoute.ts | 26 + .../requestController/createRoute.ts | 18 +- .../requestController/listRoute.ts | 14 +- .../domain/interfaces/DTOs/IAccountDTO.ts | 0 .../domain/interfaces/DTOs/IRequestDTO.ts | 0 .../domain/interfaces/models/IAccount.ts | 0 .../domain/interfaces/models/IRequest.ts | 0 .../domain/models/Account.ts | 0 .../domain/models/Request.ts | 0 {src_refactory => src}/eslint.config.js | 0 {src_refactory => src}/index.ts | 0 {src_refactory => src}/modules/api.ts | 0 src/modules/logger.ts | 64 + {src_refactory => src}/package.json | 14 +- .../Cesxhin.AnimeManga.Domain.csproj | 12 - .../Cesxhin.AnimeManga.Domain/DTO/AuthDTO.cs | 20 - .../DTO/AuthLoginDTO.cs | 8 - .../DTO/ChapterDTO.cs | 34 - .../DTO/ChapterRegisterDTO.cs | 22 - .../DTO/ConversionDTO.cs | 11 - .../DTO/DownloadDTO.cs | 8 - .../DTO/EpisodeDTO.cs | 53 - .../DTO/EpisodeRegisterDTO.cs | 22 - .../DTO/GenericBlackListDTO.cs | 33 - .../DTO/GenericBookDTO.cs | 12 - .../DTO/GenericQueueDTO.cs | 37 - .../DTO/GenericUrlDTO.cs | 25 - .../DTO/GenericVideoDTO.cs | 12 - .../DTO/NotifyAnimeDTO.cs | 8 - .../DTO/NotifyMangaDTO.cs | 8 - .../DTO/NotifyRequestAnimeDTO.cs | 8 - .../DTO/NotifyRequestMangaDTO.cs | 8 - .../DTO/ProgressChapterDTO.cs | 28 - .../DTO/ProgressEpisodeDTO.cs | 32 - .../Cesxhin.AnimeManga.Domain/DTO/ProxyDTO.cs | 8 - .../DTO/WatchListDTO.cs | 22 - .../Cesxhin.AnimeManga.Domain/Models/Auth.cs | 29 - .../Models/Chapter.cs | 54 - .../Models/ChapterBlacklist.cs | 31 - .../Models/ChapterQueue.cs | 42 - .../Models/ChapterRegister.cs | 30 - .../Models/Episode.cs | 81 -- .../Models/EpisodeBlacklist.cs | 31 - .../Models/EpisodeBuffer.cs | 10 - .../Models/EpisodeQueue.cs | 41 - .../Models/EpisodeRegister.cs | 30 - .../Models/GenericNotify.cs | 48 - .../Models/GenericUrl.cs | 10 - .../Models/PlayerUrl.cs | 19 - .../Models/ProgressChapter.cs | 37 - .../Models/ProgressEpisode.cs | 43 - .../Models/WatchList.cs | 32 - .../Cesxhin.AnimeManga.Modules.csproj | 24 - .../Exceptions/ApiConflictException.cs | 11 - .../Exceptions/ApiGenericException.cs | 11 - .../Exceptions/ApiNotAuthorizeException.cs | 11 - .../Exceptions/ApiNotFoundException.cs | 12 - .../Cesxhin.AnimeManga.Modules/Generic/Api.cs | 238 ---- .../Generic/ConvertGeneric.cs | 18 - .../Generic/Hash.cs | 38 - .../HtmlAgilityPack/RipperBookGeneric.cs | 223 ---- .../HtmlAgilityPack/RipperSchema.cs | 356 ------ .../HtmlAgilityPack/RipperVideoGeneric.cs | 200 ---- .../NlogManager/NLogConsole.cs | 108 -- .../NlogManager/NLogManager.cs | 41 - .../Parallel/ParallelManager.cs | 154 --- .../Proxy/ProxyManagement.cs | 65 - .../Schema/SchemaControl.cs | 207 ---- src/schemas/accountSchema.ts | 28 + .../schemas/generic/genericSchema.ts | 14 +- .../schemas/generic/paginationSchema.ts | 4 +- src/schemas/requestSchema.ts | 32 + .../server/fastify/index.ts | 3 +- .../server/fastify/interfaces/IConfig.ts | 0 .../server/postgres/index.ts | 0 .../postgres/interfaces/IConfigPostgres.ts | 0 {src_refactory => src}/tsconfig.json | 0 {src_refactory => src}/utils/accountUtils.ts | 0 {src_refactory => src}/utils/genericUtils.ts | 0 {src_refactory => src}/utils/schemaUtils.ts | 4 +- .../accountController/createRoute.ts | 27 - .../accountController/deleteRoute.ts | 31 - .../accountController/findRoute.ts | 29 - .../accountController/updateRoute.ts | 33 - .../requestController/actionRoute.ts | 30 - src_refactory/modules/logger.ts | 1 - src_refactory/schemas/accountSchema.ts | 45 - src_refactory/schemas/requestSchema.ts | 48 - 175 files changed, 280 insertions(+), 9159 deletions(-) delete mode 160000 references delete mode 100644 src/Cesxhin.AnimeManga.Api/Cesxhin.AnimeManga.Api.csproj delete mode 100644 src/Cesxhin.AnimeManga.Api/Controllers/AccountController.cs delete mode 100644 src/Cesxhin.AnimeManga.Api/Controllers/BookController.cs delete mode 100644 src/Cesxhin.AnimeManga.Api/Controllers/GenericController.cs delete mode 100644 src/Cesxhin.AnimeManga.Api/Controllers/VideoController.cs delete mode 100644 src/Cesxhin.AnimeManga.Api/Program.cs delete mode 100644 src/Cesxhin.AnimeManga.Api/Startup.cs delete mode 100644 src/Cesxhin.AnimeManga.Api/appsettings.Development.json delete mode 100644 src/Cesxhin.AnimeManga.Api/appsettings.json delete mode 100644 src/Cesxhin.AnimeManga.Api/schema_template.json delete mode 100644 src/Cesxhin.AnimeManga.Application/Cesxhin.AnimeManga.Application.csproj delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Controllers/IGeneralControllerBase.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IAccountRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterBlackListRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterQueueRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRegisterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IDescriptionRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeBlackListRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeQueueRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRegisterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralNameRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectBlackListRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectQueueRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRegisterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressChapterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressEpisodeRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IAccountService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterBlackListService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterQueueService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterRegisterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionBookService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionVideoService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeBlackListService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeQueueService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeRegisterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralNameService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObject.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectBlackListService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectQueueService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectRegister.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressChapterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressEpisodeService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/AccountService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/ChapterBlackListService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/ChapterQueueService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/ChapterRegisterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/ChapterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/DescriptionBookService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/DescriptionVideoService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/EpisodeBlackListService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/EpisodeQueueService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/EpisodeRegisterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/EpisodeService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/ProgressChapterService.cs delete mode 100644 src/Cesxhin.AnimeManga.Application/Services/ProgressEpisodeService.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Cesxhin.AnimeManga.Persistence.csproj delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/AccountRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterBlackListRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterQueueRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRegisterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/DescriptionRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeBlackListRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeQueueRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRegisterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressChapterRepository.cs delete mode 100644 src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressEpisodeRepository.cs rename {src_refactory => src}/applications/interfaces/repositories/IAccountRepository.ts (100%) rename {src_refactory => src}/applications/interfaces/repositories/IRequestRepository.ts (100%) rename {src_refactory => src}/applications/interfaces/repositories/generic/IConnectionRepository.ts (100%) rename {src_refactory => src}/applications/interfaces/services/IAccountService.ts (100%) rename {src_refactory => src}/applications/interfaces/services/IRequestService.ts (100%) rename {src_refactory => src}/applications/repositories/AccountRepository.ts (100%) rename {src_refactory => src}/applications/repositories/RequestRepository.ts (100%) rename {src_refactory => src}/applications/services/AccountService.ts (100%) rename {src_refactory => src}/applications/services/RequestService.ts (100%) create mode 100644 src/controllers/accountController/createRoute.ts create mode 100644 src/controllers/accountController/deleteRoute.ts create mode 100644 src/controllers/accountController/findRoute.ts create mode 100644 src/controllers/accountController/updateRoute.ts create mode 100644 src/controllers/requestController/actionRoute.ts rename {src_refactory => src}/controllers/requestController/createRoute.ts (51%) rename {src_refactory => src}/controllers/requestController/listRoute.ts (50%) rename {src_refactory => src}/domain/interfaces/DTOs/IAccountDTO.ts (100%) rename {src_refactory => src}/domain/interfaces/DTOs/IRequestDTO.ts (100%) rename {src_refactory => src}/domain/interfaces/models/IAccount.ts (100%) rename {src_refactory => src}/domain/interfaces/models/IRequest.ts (100%) rename {src_refactory => src}/domain/models/Account.ts (100%) rename {src_refactory => src}/domain/models/Request.ts (100%) rename {src_refactory => src}/eslint.config.js (100%) rename {src_refactory => src}/index.ts (100%) rename {src_refactory => src}/modules/api.ts (100%) create mode 100644 src/modules/logger.ts rename {src_refactory => src}/package.json (73%) delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Cesxhin.AnimeManga.Domain.csproj delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/AuthDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/AuthLoginDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterRegisterDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/ConversionDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/DownloadDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeRegisterDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBlackListDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBookDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/GenericQueueDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/GenericUrlDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/GenericVideoDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyAnimeDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyMangaDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestAnimeDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestMangaDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressChapterDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressEpisodeDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/ProxyDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/DTO/WatchListDTO.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/Auth.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/Chapter.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/ChapterBlacklist.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/ChapterQueue.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/ChapterRegister.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/Episode.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBlacklist.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBuffer.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeQueue.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeRegister.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/GenericNotify.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/GenericUrl.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/PlayerUrl.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/ProgressChapter.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/ProgressEpisode.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Domain/Models/WatchList.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Cesxhin.AnimeManga.Modules.csproj delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiConflictException.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiGenericException.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotAuthorizeException.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotFoundException.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Generic/Api.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Generic/ConvertGeneric.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Generic/Hash.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperBookGeneric.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperSchema.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperVideoGeneric.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogConsole.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogManager.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Parallel/ParallelManager.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Proxy/ProxyManagement.cs delete mode 100644 src/references/Cesxhin.AnimeManga.Modules/Schema/SchemaControl.cs create mode 100644 src/schemas/accountSchema.ts rename {src_refactory => src}/schemas/generic/genericSchema.ts (80%) rename {src_refactory => src}/schemas/generic/paginationSchema.ts (74%) create mode 100644 src/schemas/requestSchema.ts rename {src_refactory => src}/server/fastify/index.ts (98%) rename {src_refactory => src}/server/fastify/interfaces/IConfig.ts (100%) rename {src_refactory => src}/server/postgres/index.ts (100%) rename {src_refactory => src}/server/postgres/interfaces/IConfigPostgres.ts (100%) rename {src_refactory => src}/tsconfig.json (100%) rename {src_refactory => src}/utils/accountUtils.ts (100%) rename {src_refactory => src}/utils/genericUtils.ts (100%) rename {src_refactory => src}/utils/schemaUtils.ts (76%) delete mode 100644 src_refactory/controllers/accountController/createRoute.ts delete mode 100644 src_refactory/controllers/accountController/deleteRoute.ts delete mode 100644 src_refactory/controllers/accountController/findRoute.ts delete mode 100644 src_refactory/controllers/accountController/updateRoute.ts delete mode 100644 src_refactory/controllers/requestController/actionRoute.ts delete mode 120000 src_refactory/modules/logger.ts delete mode 100644 src_refactory/schemas/accountSchema.ts delete mode 100644 src_refactory/schemas/requestSchema.ts diff --git a/references b/references deleted file mode 160000 index 2506e62..0000000 --- a/references +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2506e62a45b3fc058b9eee925374a25a73a9bdce diff --git a/src/Cesxhin.AnimeManga.Api/Cesxhin.AnimeManga.Api.csproj b/src/Cesxhin.AnimeManga.Api/Cesxhin.AnimeManga.Api.csproj deleted file mode 100644 index 0e1104a..0000000 --- a/src/Cesxhin.AnimeManga.Api/Cesxhin.AnimeManga.Api.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - net5.0 - f1d2050b-ac80-4560-808c-e1e1bb2c67ea - Linux - - - - - - - - - - - - - - - - - - - - - - - Always - - - - - - diff --git a/src/Cesxhin.AnimeManga.Api/Controllers/AccountController.cs b/src/Cesxhin.AnimeManga.Api/Controllers/AccountController.cs deleted file mode 100644 index d95aa4c..0000000 --- a/src/Cesxhin.AnimeManga.Api/Controllers/AccountController.cs +++ /dev/null @@ -1,134 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using System; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Api.Controllers -{ - [Route("api/[controller]")] - [ApiController] - public class AccountController : ControllerBase - { - private readonly IAccountService _accountService; - public AccountController(IAccountService accountService) - { - _accountService = accountService; - } - - //login - [HttpPost("/auth/login")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AuthDTO))] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task Login(AuthLoginDTO auth) - { - try - { - if (string.IsNullOrEmpty(auth.Username) || string.IsNullOrEmpty(auth.Password)) - return BadRequest(); - - var user = await _accountService.Login(auth.Username, auth.Password); - return Ok(user); - } - catch (ApiNotAuthorizeException) - { - return Unauthorized(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //register - [HttpPost("/auth/register")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AuthDTO))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task Register(AuthLoginDTO auth) - { - try - { - if (string.IsNullOrEmpty(auth.Username) || string.IsNullOrEmpty(auth.Password)) - return BadRequest(); - - var user = await _accountService.CreateAccount(auth.Username, auth.Password); - return Ok(user); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //add whiteList - [HttpPost("/auth/watchlist")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(WatchListDTO))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task AddWatchList(WatchListDTO whiteListDTO) - { - try - { - var rs = await _accountService.InsertWatchList(whiteListDTO); - return Ok(rs); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //delete whiteList - [HttpDelete("/auth/watchlist")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(WatchListDTO))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task DeleteWatchList(WatchListDTO whiteListDTO) - { - try - { - var rs = await _accountService.DeleteWatchList(whiteListDTO); - if (rs != null) - return Ok(rs); - - return Conflict(); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Api/Controllers/BookController.cs b/src/Cesxhin.AnimeManga.Api/Controllers/BookController.cs deleted file mode 100644 index 98dbcd5..0000000 --- a/src/Cesxhin.AnimeManga.Api/Controllers/BookController.cs +++ /dev/null @@ -1,1044 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Controllers; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Modules.HtmlAgilityPack; -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Domain.DTO; -using MassTransit; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Api.Controllers -{ - [Route("api")] - [ApiController] - public class BookController : ControllerBase, IGeneralControllerBase - { - //interfaces - private readonly IDescriptionBookService _bookService; - private readonly IChapterService _chapterService; - private readonly IChapterRegisterService _chapterRegisterService; - private readonly IProgressChapterService _progressChapterService; - private readonly IChapterQueueService _chapterQueueService; - private readonly IAccountService _accountService; - private readonly IChapterBlackListService _chapterBlackListService; - private readonly IBus _publishEndpoint; - - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - private readonly string _folder = Environment.GetEnvironmentVariable("BASE_PATH") ?? "/"; - private readonly JObject _schema = JObject.Parse(Environment.GetEnvironmentVariable("SCHEMA")); - - public BookController( - IDescriptionBookService bookService, - IChapterService chapterService, - IChapterRegisterService chapterRegisterService, - IProgressChapterService progressChapterService, - IChapterQueueService chapterQueueService, - IAccountService accountService, - IChapterBlackListService chapterBlackListService, - IBus publishEndpoint - ) - { - _publishEndpoint = publishEndpoint; - _bookService = bookService; - _chapterService = chapterService; - _chapterRegisterService = chapterRegisterService; - _progressChapterService = progressChapterService; - _chapterQueueService = chapterQueueService; - _accountService = accountService; - _chapterBlackListService = chapterBlackListService; - } - - //get list all manga without filter - [HttpGet("/book")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetInfoAll(string nameCfg, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var listManga = await _bookService.GetNameAllAsync(nameCfg, username); - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(listManga)); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get manga by name - [HttpGet("/book/name/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetInfoByName(string nameCfg, string name, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var anime = await _bookService.GetNameByNameAsync(nameCfg, name, username); - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(anime)); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get list manga by start name similar - [HttpGet("/book/names/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetMostInfoByName(string nameCfg, string name, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var searchSchema = _schema.GetValue(nameCfg).ToObject().GetValue("search").ToObject(); - var bookUrls = RipperBookGeneric.GetBookUrl(searchSchema, name); - - //list anime - List listManga = new(); - - foreach (var book in bookUrls) - { - var bookDTO = GenericUrlDTO.GenericUrlToGenericUrlDTO(book); - - var checkManga = await _bookService.GetNameByNameAsync(nameCfg, book.Name, username); - if (checkManga != null) - bookDTO.Exists = true; - - listManga.Add(bookDTO); - } - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(listManga)); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get all db manga - [HttpGet("/book/all")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetAll(string nameCfg, string username) - { - try - { - if (nameCfg != null && _schema.ContainsKey(nameCfg)) - { - var listManga = await _bookService.GetNameAllWithAllAsync(nameCfg, username); - return Ok(listManga); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get chapter by name anime - [HttpGet("/chapter/name/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectByName(string name) - { - try - { - var listChapters = await _chapterService.GetObjectsByNameAsync(name); - return Ok(listChapters); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get chapter by id - [HttpGet("/chapter/id/{id}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ChapterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectById(string id) - { - try - { - var chapter = await _chapterService.GetObjectByIDAsync(id); - return Ok(chapter); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get chapterRegister by id - [HttpGet("/chapter/register/chapterid/{id}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ChapterRegisterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectRegisterByObjectId(string id) - { - try - { - var chapterRegister = await _chapterRegisterService.GetObjectRegisterByObjectId(id); - return Ok(chapterRegister); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get list name by external db - [HttpGet("/book/list/name/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetListSearchByName(string nameCfg, string name) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var searchSchema = _schema.GetValue(nameCfg).ToObject().GetValue("search").ToObject(); - var bookUrls = RipperBookGeneric.GetBookUrl(searchSchema, name); - - List listBlackList = new(); - try - { - listBlackList = await _chapterBlackListService.GetObjectsBlackList(); - } - catch (ApiNotFoundException) { } - - if (listBlackList.Any()) - { - bookUrls = bookUrls.Where(book => - listBlackList.Where(blackList => - book.Name == blackList.Name && - book.Url == blackList.Url && - nameCfg == blackList.NameCfg - ).ToList().Count == 0 - ).ToList(); - } - - //list manga - List list = new(); - - foreach (var bookUrl in bookUrls) - { - var bookUrlDTO = GenericUrlDTO.GenericUrlToGenericUrlDTO(bookUrl); - - //check if already exists - try - { - await _chapterService.GetObjectsByNameAsync(bookUrlDTO.Name); - bookUrlDTO.Exists = true; - } - catch (ApiNotFoundException) { } - - list.Add(bookUrlDTO); - } - return Ok(list); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert manga - [HttpPost("/book")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutInfo(string nameCfg, string infoClass) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - //insert - var mangaResult = await _bookService.InsertNameAsync(nameCfg, JObject.Parse(infoClass)); - return Created("none", Newtonsoft.Json.JsonConvert.SerializeObject(mangaResult)); - } - else - return BadRequest(); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //update manga - [HttpPut("/book")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task UpdateInfo([FromBody] string content) - { - try - { - var description = JObject.Parse(content); - string nameCfg = (string)description["nameCfg"]; - - if (_schema.ContainsKey(nameCfg)) - { - //update - var mangaResult = await _bookService.UpdateNameAsync(nameCfg, description); - return Created("none", Newtonsoft.Json.JsonConvert.SerializeObject(mangaResult)); - } - else - return BadRequest(); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert chapter - [HttpPost("/chapter")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ChapterDTO))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObject(ChapterDTO objectClass) - { - try - { - //insert - var chapterResult = await _chapterService.InsertObjectAsync(objectClass); - return Created("none", chapterResult); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert list chapters - [HttpPost("/chapters")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjects(List objectsClass) - { - try - { - //insert - var chaptersResult = await _chapterService.InsertObjectsAsync(objectsClass); - return Created("none", chaptersResult); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert list chaptersRegisters - [HttpPost("/chapters/registers")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjectsRegisters(List objectsRegistersClass) - { - try - { - //insert - var chapterResult = await _chapterRegisterService.InsertObjectsRegistersAsync(objectsRegistersClass); - return Created("none", chapterResult); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //put chapterRegister into db - [HttpPut("/chapter/register")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ChapterRegisterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task UpdateObjectRegister(ChapterRegisterDTO objectRegisterClass) - { - try - { - var chapterRegisterResult = await _chapterRegisterService.UpdateObjectRegisterAsync(objectRegisterClass); - return Ok(chapterRegisterResult); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - - //reset state download of chapterRegister into db - [HttpPut("/book/redownload")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task RedownloadObjectByUrlPage(string name, string username) - { - try - { - AuthDTO account = null; - try - { - account = await _accountService.FindAccountByUsername(username); - } - catch (ApiNotFoundException) - { - throw new ApiNotAuthorizeException(); - } - - if (account.Role != 100) - throw new ApiNotAuthorizeException(); - - var result = await _chapterService.ResetStatusMultipleDownloadObjectByIdAsync(name); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (ApiNotAuthorizeException) - { - return StatusCode(401); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //put manga into db - [HttpPost("/book/download")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task DownloadInfoByUrlPage(DownloadDTO downloadClass, string username) - { - try - { - AuthDTO account = null; - try - { - account = await _accountService.FindAccountByUsername(username); - } - catch (ApiNotFoundException) - { - throw new ApiNotAuthorizeException(); - } - - if (account.Role != 100) - throw new ApiNotAuthorizeException(); - - if (!_schema.ContainsKey(downloadClass.nameCfg)) - return BadRequest(); - - //get manga - var manga = RipperBookGeneric.GetDescriptionBook(_schema.GetValue(downloadClass.nameCfg).ToObject(), downloadClass.Url, downloadClass.nameCfg); - string name = manga.GetValue("name_id").ToString(); - string cover = manga.GetValue("cover").ToString(); - - //get chapters - var chapters = RipperBookGeneric.GetChapters( - _schema.GetValue(downloadClass.nameCfg).ToObject(), - downloadClass.Url, - name, - downloadClass.nameCfg - ); - - try - { - manga.GetValue("totalVolumes").ToObject(); - manga.GetValue("totalChapters").ToObject(); - } - catch - { - float maxVolumes = 0; - int maxChapters = chapters.Count; - - foreach (var chapter in chapters) - { - if (chapter.CurrentVolume > maxVolumes) - maxVolumes = chapter.CurrentVolume; - } - - manga["totalVolumes"] = maxVolumes; - manga["totalChapters"] = maxChapters; - } - - //insert manga - var resultDescription = await _bookService.InsertNameAsync(downloadClass.nameCfg, manga); - - //insert chapters - var listChapters = await _chapterService.InsertObjectsAsync(chapters); - - var listChapterRegister = new List(); - List chapterPaths = new(); - - foreach (var chapter in chapters) - { - - for (int i = 0; i <= chapter.NumberMaxImage; i++) - { - chapterPaths.Add($"{_folder}/{chapter.NameManga}/Volume {chapter.CurrentVolume}/Chapter {chapter.CurrentChapter}/{chapter.NameManga} s{chapter.CurrentVolume}c{chapter.CurrentChapter}n{i}.png"); - } - - listChapterRegister.Add(new ChapterRegisterDTO - { - ChapterId = chapter.ID, - ChapterPath = chapterPaths.ToArray() - }); - - chapterPaths.Clear(); - } - - //insert episodesRegisters - var episodeRegisterResult = await _chapterRegisterService.InsertObjectsRegistersAsync(listChapterRegister); - - //delete if exist queue - try - { - await _chapterQueueService.DeleteObjectQueue(new GenericQueueDTO - { - NameCfg = downloadClass.nameCfg, - Url = downloadClass.Url - }); - } - catch (ApiNotFoundException) { } - - //create message for notify - string message = $"Added: {name} [Manga]\n"; - - try - { - var messageNotify = new NotifyMangaDTO - { - Message = message, - Image = cover - }; - await _publishEndpoint.Publish(messageNotify); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - - return Created("none", Newtonsoft.Json.JsonConvert.SerializeObject(resultDescription)); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (ApiNotAuthorizeException) - { - return StatusCode(401); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - //update status chapter - [HttpPut("/book/statusDownload")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ChapterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutUpdateStateDownload(ChapterDTO objectClass) - { - try - { - //update - var chapterResult = await _chapterService.UpdateStateDownloadAsync(objectClass); - return Ok(chapterResult); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - //delete manga - [HttpDelete("/book/{id}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task DeleteInfo(string nameCfg, string id, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - AuthDTO account = null; - try - { - account = await _accountService.FindAccountByUsername(username); - } - catch (ApiNotFoundException) - { - throw new ApiNotAuthorizeException(); - } - - if (account.Role != 100) - throw new ApiNotAuthorizeException(); - - var listChapterService = await _chapterService.GetObjectsByNameAsync(id); - var listChapterRegister = await _chapterRegisterService.GetObjectsRegistersByListObjectId(listChapterService.ToList()); - var bookDescription = await _bookService.GetNameByNameAsync(nameCfg, id, null); - - var book = await _bookService.DeleteNameByIdAsync(nameCfg, id); - - //create message for notify - string message = $"Removed: {id} [Manga]\n"; - - try - { - var messageNotify = new NotifyMangaDTO - { - Message = message, - Image = bookDescription.GetValue("cover").ToString() - }; - - await _publishEndpoint.Publish(messageNotify); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - - foreach (var chapterRegister in listChapterRegister) - { - try - { - await _publishEndpoint.Publish(chapterRegister); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - } - - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(book)); - } - else - return BadRequest(); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - //put progress for tracker - [HttpPut("/chapter/progress")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ProgressChapterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutStateProgress(ProgressChapterDTO progress) - { - try - { - var result = await _progressChapterService.UpdateProgress(progress); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - //get progress for tracker - [HttpGet("/chapter/progress")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ProgressChapterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetStateProgress(string name, string username, string nameCfg) - { - try - { - var result = await _progressChapterService.GetProgressByName(name, username, nameCfg); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpGet("/chapter/all-queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectsQueue() - { - try - { - var result = await _chapterQueueService.GetObjectsQueue(); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpPut("/chapter/queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericQueueDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjectQueue(GenericQueueDTO objectClass) - { - try - { - var result = await _chapterQueueService.PutObjectQueue(objectClass); - - //create message for notify - string message = $"Someone likes: {objectClass.Name} [Manga]\n"; - - try - { - var messageNotify = new NotifyRequestMangaDTO - { - Message = message - }; - - await _publishEndpoint.Publish(messageNotify); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpDelete("/chapter/queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericQueueDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task DeleteObjectQueue(GenericQueueDTO objectClass) - { - try - { - var result = await _chapterQueueService.DeleteObjectQueue(objectClass); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpGet("/chapter/queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericQueueDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectQueue(string name, string url, string nameCfg) - { - try - { - var result = await _chapterQueueService.GetObjectQueue(new GenericQueueDTO - { - Name = name, - NameCfg = nameCfg, - Url = url - }); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpPut("/chapter/blacklist")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericBlackListDTO))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjectBlackList(GenericBlackListDTO objectClass) - { - try - { - var result = await _chapterBlackListService.PutObjectBlackList(objectClass); - - await _chapterQueueService.DeleteObjectQueue(new GenericQueueDTO - { - Name = objectClass.Name, - Url = objectClass.Url, - NameCfg = objectClass.NameCfg, - }); - - return Ok(result); - } - catch (ApiConflictException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Api/Controllers/GenericController.cs b/src/Cesxhin.AnimeManga.Api/Controllers/GenericController.cs deleted file mode 100644 index b50375a..0000000 --- a/src/Cesxhin.AnimeManga.Api/Controllers/GenericController.cs +++ /dev/null @@ -1,217 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Modules.Parallel; -using Cesxhin.AnimeManga.Domain.DTO; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Api.Controllers -{ - [Route("api")] - [ApiController] - public class GenericController : ControllerBase - { - //interfaces - private readonly IDescriptionVideoService _descriptionVideoService; - private readonly IDescriptionBookService _descriptionBookService; - - //env - private readonly JObject schemas = JObject.Parse(Environment.GetEnvironmentVariable("SCHEMA")); - - public GenericController( - IDescriptionVideoService descriptionVideoService, - IDescriptionBookService descriptionBookService - ) - { - _descriptionVideoService = descriptionVideoService; - _descriptionBookService = descriptionBookService; - } - //check test - [HttpGet("/cfg")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task getSchema() - { - try - { - return Ok(Environment.GetEnvironmentVariable("SCHEMA")); - } - catch - { - return StatusCode(500); - } - } - - //check test - [HttpGet("/check")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task Check() - { - try - { - return Ok("Ok"); - } - catch - { - return StatusCode(500); - } - } - //get all db only saved by account - [HttpGet("/all/watchlist")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetAllOnlyWatchList(string username) - { - List listGeneric = new(); - dynamic result; - try - { - foreach (var item in schemas) - { - var schema = schemas.GetValue(item.Key).ToObject(); - if (schema.GetValue("type").ToString() == "video") - { - result = await _descriptionVideoService.GetNameAllOnlyWatchListAsync(item.Key, username); - } - else - { - result = await _descriptionBookService.GetNameAllOnlyWatchListAsync(item.Key, username); - } - - if (result != null) - listGeneric.AddRange(result); - } - - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(listGeneric)); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get all db - [HttpGet("/all")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetAll(string username) - { - List listGeneric = new(); - dynamic result; - try - { - foreach (var item in schemas) - { - var schema = schemas.GetValue(item.Key).ToObject(); - result = null; - - if (schema.GetValue("type").ToString() == "video") - { - try - { - result = await _descriptionVideoService.GetNameAllAsync(item.Key, username); - } - catch (ApiNotFoundException) { } - } - else - { - try - { - result = await _descriptionBookService.GetNameAllAsync(item.Key, username); - } - catch (ApiNotFoundException) { } - } - - if (result != null) - listGeneric.AddRange(result); - } - - if (listGeneric.Count > 0) - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(listGeneric)); - else - throw new ApiNotFoundException(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get all db - [HttpGet("/search")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetSearch(string username) - { - List listGeneric = new(); - ParallelManager> parallel = new(); - List>> tasks = new(); - dynamic result; - try - { - foreach (var item in schemas) - { - var schema = schemas.GetValue(item.Key).ToObject(); - if (schema.GetValue("type").ToString() == "video") - { - var key = item.Key; - tasks.Add(new Func>(() => _descriptionVideoService.GetNameAllAsync(key, username).GetAwaiter().GetResult())); - } - else - { - var key = item.Key; - tasks.Add(new Func>(() => _descriptionBookService.GetNameAllAsync(key, username).GetAwaiter().GetResult())); - } - - } - - parallel.AddTasks(tasks); - parallel.Start(); - parallel.WhenCompleted(); - - result = parallel.GetResult(); - - foreach (var item in result) - listGeneric.AddRange(item); - - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(listGeneric)); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Api/Controllers/VideoController.cs b/src/Cesxhin.AnimeManga.Api/Controllers/VideoController.cs deleted file mode 100644 index ab992dd..0000000 --- a/src/Cesxhin.AnimeManga.Api/Controllers/VideoController.cs +++ /dev/null @@ -1,981 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Modules.HtmlAgilityPack; -using Cesxhin.AnimeManga.Application.Interfaces.Controllers; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.DTO; -using MassTransit; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Api.Controllers -{ - [Route("api")] - [ApiController] - public class AnimeController : ControllerBase, IGeneralControllerBase - { - //interfaces - private readonly IDescriptionVideoService _descriptionService; - private readonly IEpisodeService _episodeService; - private readonly IEpisodeRegisterService _episodeRegisterService; - private readonly IProgressEpisodeService _progressEpisodeService; - private readonly IEpisodeQueueService _episodeQueueService; - private readonly IAccountService _accountService; - private readonly IEpisodeBlackListService _episodeBlackListService; - private readonly IBus _publishEndpoint; - - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - private readonly string _folder = Environment.GetEnvironmentVariable("BASE_PATH") ?? "/"; - private readonly JObject _schema = JObject.Parse(Environment.GetEnvironmentVariable("SCHEMA")); - - public AnimeController( - IEpisodeService episodeService, - IEpisodeRegisterService episodeRegisterService, - IDescriptionVideoService descriptionService, - IProgressEpisodeService progressEpisodeService, - IEpisodeQueueService episodeQueueService, - IEpisodeBlackListService episodeBlackListService, - IAccountService accountService, - IBus publishEndpoint - ) - { - _descriptionService = descriptionService; - _episodeService = episodeService; - _episodeRegisterService = episodeRegisterService; - _publishEndpoint = publishEndpoint; - _episodeQueueService = episodeQueueService; - _progressEpisodeService = progressEpisodeService; - _accountService = accountService; - _episodeBlackListService = episodeBlackListService; - } - - //get list all anime without filter - [HttpGet("/video")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetInfoAll(string nameCfg, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var listAll = await _descriptionService.GetNameAllAsync(nameCfg, username); - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(listAll)); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get anime by name - [HttpGet("/video/name/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetInfoByName(string name, string nameCfg, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var description = await _descriptionService.GetNameByNameAsync(nameCfg, name, username); - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(description)); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get list anime by start name similar - [HttpGet("/video/names/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetMostInfoByName(string nameCfg, string name, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var description = await _descriptionService.GetMostNameByNameAsync(nameCfg, name, username); - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(description)); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get episode by name anime - [HttpGet("/episode/name/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectByName(string name) - { - try - { - var listEpisodes = await _episodeService.GetObjectsByNameAsync(name); - return Ok(listEpisodes); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get episode by id - [HttpGet("/episode/id/{id}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(EpisodeDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectById(string id) - { - try - { - var episode = await _episodeService.GetObjectByIDAsync(id); - return Ok(episode); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //get episodeRegister by id - [HttpGet("/episode/register/episodeid/{id}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(EpisodeRegisterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectRegisterByObjectId(string id) - { - try - { - var episodeRegister = await _episodeRegisterService.GetObjectRegisterByObjectId(id); - return Ok(episodeRegister); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert anime - [HttpPost("/video")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutInfo(string nameCfg, string description) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - //insert - var descriptionResult = await _descriptionService.InsertNameAsync(nameCfg, JObject.Parse(description)); - return Created("none", Newtonsoft.Json.JsonConvert.SerializeObject(descriptionResult)); - } - else - return BadRequest(); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //update anime - [HttpPut("/video")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task UpdateInfo([FromBody] string content) - { - try - { - var description = JObject.Parse(content); - string nameCfg = (string)description["nameCfg"]; - - if (_schema.ContainsKey(nameCfg)) - { - //update - var descriptionResult = await _descriptionService.UpdateNameAsync(nameCfg, description); - return Created("none", Newtonsoft.Json.JsonConvert.SerializeObject(descriptionResult)); - } - else - return BadRequest(); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert episode - [HttpPost("/episode")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(EpisodeDTO))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObject(EpisodeDTO objectClass) - { - try - { - //insert - var episodeResult = await _episodeService.InsertObjectAsync(objectClass); - return Created("none", episodeResult); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert list episodes - [HttpPost("/episodes")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjects(List objectsClass) - { - try - { - //insert - var episodeResult = await _episodeService.InsertObjectsAsync(objectsClass); - return Created("none", episodeResult); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //insert list episodesRegisters - [HttpPost("/episodes/registers")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjectsRegisters(List objectsRegistersClass) - { - try - { - //insert - var episodeResult = await _episodeRegisterService.InsertObjectsRegistersAsync(objectsRegistersClass); - return Created("none", episodeResult); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //put episodeRegister into db - [HttpPut("/episode/register")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(EpisodeRegisterDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task UpdateObjectRegister(EpisodeRegisterDTO objectRegisterClass) - { - try - { - var rs = await _episodeRegisterService.UpdateObjectRegisterAsync(objectRegisterClass); - return Ok(rs); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } - } - - //put anime into db - [HttpPost("/video/download")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task DownloadInfoByUrlPage(DownloadDTO downloadClass, string username) - { - try - { - AuthDTO account = null; - try - { - account = await _accountService.FindAccountByUsername(username); - } - catch(ApiNotFoundException) - { - throw new ApiNotAuthorizeException(); - } - - if (account.Role != 100) - throw new ApiNotAuthorizeException(); - - JObject cfg = null; - - if (!_schema.ContainsKey(downloadClass.nameCfg)) - return BadRequest(); - - cfg = _schema.GetValue(downloadClass.nameCfg).ToObject(); - - //get anime and episodes - var description = RipperVideoGeneric.GetDescriptionVideo(cfg, downloadClass.Url, downloadClass.nameCfg); - var episodes = RipperVideoGeneric.GetEpisodes(cfg, downloadClass.Url, description["name_id"].ToString(), downloadClass.nameCfg); - - var listEpisodeRegister = new List(); - - foreach (var episode in episodes) - { - listEpisodeRegister.Add(new EpisodeRegisterDTO - { - EpisodeId = episode.ID, - EpisodePath = $"{_folder}/{episode.VideoId}/Season {episode.NumberSeasonCurrent.ToString("D2")}/{episode.VideoId} s{episode.NumberSeasonCurrent.ToString("D2")}e{episode.NumberEpisodeCurrent.ToString("D2")}.mp4" - }); - } - - var descriptionResult = await _descriptionService.InsertNameAsync(downloadClass.nameCfg, JObject.Parse(description.ToString())); - - //insert episodes - var episodeResult = await _episodeService.InsertObjectsAsync(episodes); - - //insert episodesRegisters - var episodeRegisterResult = await _episodeRegisterService.InsertObjectsRegistersAsync(listEpisodeRegister); - - //delete if exist queue - try - { - await _episodeQueueService.DeleteObjectQueue(new GenericQueueDTO { - NameCfg = downloadClass.nameCfg, - Url = downloadClass.Url - }); - } - catch (ApiNotFoundException) { } - - //create message for notify - string message = $"Added: {description["name_id"]} [Anime]\n"; - - try - { - var messageNotify = new NotifyAnimeDTO - { - Message = message, - Image = description["cover"].ToString() - }; - await _publishEndpoint.Publish(messageNotify); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - - return Created("none", Newtonsoft.Json.JsonConvert.SerializeObject(descriptionResult)); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (ApiNotAuthorizeException) - { - return StatusCode(401); - } - catch (Exception e) - { - _logger.Error(e); - return StatusCode(500); - } - } - - //reset state download of episodeRegister into db - [HttpPut("/video/redownload")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task RedownloadObjectByUrlPage(string name, string username) - { - try - { - AuthDTO account = null; - try - { - account = await _accountService.FindAccountByUsername(username); - } - catch (ApiNotFoundException) - { - throw new ApiNotAuthorizeException(); - } - - if (account.Role != 100) - throw new ApiNotAuthorizeException(); - - var rs = await _episodeService.ResetStatusMultipleDownloadObjectByIdAsync(name); - return Ok(rs); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (ApiNotAuthorizeException) - { - return StatusCode(401); - } - catch (Exception) - { - return StatusCode(500); - } - } - - //delete description - [HttpDelete("/video/{id}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task DeleteInfo(string nameCfg, string id, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - AuthDTO account = null; - try - { - account = await _accountService.FindAccountByUsername(username); - } - catch (ApiNotFoundException) - { - throw new ApiNotAuthorizeException(); - } - - if (account.Role != 100) - throw new ApiNotAuthorizeException(); - - var listEpisodeService = await _episodeService.GetObjectsByNameAsync(id); - var listEpisodeRegister = await _episodeRegisterService.GetObjectsRegistersByListObjectId(listEpisodeService.ToList()); - var videoDescription = await _descriptionService.GetNameByNameAsync(nameCfg, id, null); - - //delete - var videoResult = await _descriptionService.DeleteNameByIdAsync(nameCfg, id); - - //create message for notify - string message = $"Removed: {id} [Anime]\n"; - - try - { - var messageNotify = new NotifyAnimeDTO - { - Message = message, - Image = videoDescription.GetValue("cover").ToString() - }; - await _publishEndpoint.Publish(messageNotify); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - - foreach (var episode in listEpisodeRegister) - { - try - { - await _publishEndpoint.Publish(episode); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - } - - return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(videoResult)); - } - else - return BadRequest(); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception) - { - return StatusCode(500); - } - } - - //get all db anime - [HttpGet("/video/all")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetAll(string nameCfg, string username) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var listDescription = await _descriptionService.GetNameAllWithAllAsync(nameCfg, username); - return Ok(listDescription); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception) - { - return StatusCode(500); - } - } - - //get list name by external db - [HttpGet("/video/list/name/{name}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetListSearchByName(string nameCfg, string name) - { - try - { - if (_schema.ContainsKey(nameCfg)) - { - var searchSchema = _schema.GetValue(nameCfg).ToObject().GetValue("search").ToObject(); - var descriptionUrls = RipperVideoGeneric.GetVideoUrl(searchSchema, name); - - List listBlackList = new(); - try - { - listBlackList = await _episodeBlackListService.GetObjectsBlackList(); - } - catch (ApiNotFoundException) { } - - if (listBlackList.Any()) - { - descriptionUrls = descriptionUrls.Where(book => - listBlackList.Where(blackList => - book.Name == blackList.Name && - book.Url == blackList.Url && - nameCfg == blackList.NameCfg - ).ToList().Count == 0 - ).ToList(); - } - - //list anime - List list = new(); - - foreach (var descrptionUrl in descriptionUrls) - { - var descriptionUrlDTO = GenericUrlDTO.GenericUrlToGenericUrlDTO(descrptionUrl); - - //check if already exists - try - { - await _descriptionService.GetNameByNameAsync(nameCfg, descriptionUrlDTO.Name, null); - descriptionUrlDTO.Exists = true; - } - catch (ApiNotFoundException) { } - - list.Add(descriptionUrlDTO); - } - return Ok(list); - } - else - return BadRequest(); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception) - { - return StatusCode(500); - } - } - - //update status episode - [HttpPut("/video/statusDownload")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(EpisodeDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutUpdateStateDownload(EpisodeDTO objectClass) - { - try - { - //update - var resultEpisode = await _episodeService.UpdateStateDownloadAsync(objectClass); - return Ok(resultEpisode); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception) - { - return StatusCode(500); - } - } - - //put progress for tracker - [HttpPut("/episode/progress")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ProgressEpisodeDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutStateProgress(ProgressEpisodeDTO progress) - { - try - { - var result = await _progressEpisodeService.UpdateProgress(progress); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception) - { - return StatusCode(500); - } - } - - //put progress for tracker - [HttpGet("/episode/progress")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ProgressEpisodeDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetStateProgress(string name, string username, string nameCfg) - { - try - { - var result = await _progressEpisodeService.GetProgressByName(name, username, nameCfg); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception) - { - return StatusCode(500); - } - } - - [HttpGet("/episode/all-queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectsQueue() - { - try - { - var result = await _episodeQueueService.GetObjectsQueue(); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpPut("/episode/queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericQueueDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjectQueue(GenericQueueDTO objectClass) - { - try - { - var result = await _episodeQueueService.PutObjectQueue(objectClass); - - //create message for notify - string message = $"Someone likes: {objectClass.Name} [Anime]\n"; - - try - { - var messageNotify = new NotifyRequestAnimeDTO - { - Message = message - }; - - await _publishEndpoint.Publish(messageNotify); - } - catch (Exception ex) - { - _logger.Error($"Cannot send message rabbit, details: {ex.Message}"); - } - - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (ApiConflictException) - { - return Conflict(); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpDelete("/episode/queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericQueueDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task DeleteObjectQueue(GenericQueueDTO objectClass) - { - try - { - var result = await _episodeQueueService.DeleteObjectQueue(objectClass); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpGet("/episode/queue")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericQueueDTO))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task GetObjectQueue(string name, string url, string nameCfg) - { - try - { - var result = await _episodeQueueService.GetObjectQueue(new GenericQueueDTO - { - Name = name, - NameCfg = nameCfg, - Url = url - }); - return Ok(result); - } - catch (ApiNotFoundException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - - [HttpPut("/episode/blacklist")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GenericBlackListDTO))] - [ProducesResponseType(StatusCodes.Status409Conflict)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task PutObjectBlackList(GenericBlackListDTO objectClass) - { - try - { - var result = await _episodeBlackListService.PutObjectBlackList(objectClass); - - await _episodeQueueService.DeleteObjectQueue(new GenericQueueDTO { - Name = objectClass.Name, - Url = objectClass.Url, - NameCfg = objectClass.NameCfg, - }); - - return Ok(result); - } - catch (ApiConflictException) - { - return NotFound(); - } - catch (ApiGenericException) - { - return StatusCode(500); - } - catch (Exception ex) - { - _logger.Error(ex.Message); - return StatusCode(500, ex.Message); - } - } - } -} \ No newline at end of file diff --git a/src/Cesxhin.AnimeManga.Api/Program.cs b/src/Cesxhin.AnimeManga.Api/Program.cs deleted file mode 100644 index a58a48f..0000000 --- a/src/Cesxhin.AnimeManga.Api/Program.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace Cesxhin.AnimeManga.Api -{ - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } -} diff --git a/src/Cesxhin.AnimeManga.Api/Startup.cs b/src/Cesxhin.AnimeManga.Api/Startup.cs deleted file mode 100644 index d0928a7..0000000 --- a/src/Cesxhin.AnimeManga.Api/Startup.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Generic; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Modules.Schema; -using Cesxhin.AnimeManga.Application.Services; -using Cesxhin.AnimeManga.Persistence.Repositories; -using MassTransit; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.OpenApi.Models; -using NLog; -using Quartz; -using System; - -namespace Cesxhin.AnimeManga.Api -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - - SchemaControl.Check(); - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - //interfaces - //services - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - //repositories - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - //init repoDb - RepoDb.PostgreSqlBootstrap.Initialize(); - - //rabbit - services.AddMassTransit( - x => - { - x.UsingRabbitMq((context, cfg) => - { - cfg.Host( - Environment.GetEnvironmentVariable("ADDRESS_RABBIT") ?? "localhost", - "/", - credentials => - { - credentials.Username(Environment.GetEnvironmentVariable("USERNAME_RABBIT") ?? "guest"); - credentials.Password(Environment.GetEnvironmentVariable("PASSWORD_RABBIT") ?? "guest"); - }); - }); - }); - - - services.AddCors(); - services.AddControllers(); - services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "Cesxhin.AnimeManga.Api", Version = "v1" }); - }); - - //setup nlog - var level = Environment.GetEnvironmentVariable("LOG_LEVEL")?.ToLower() ?? "info"; - LogLevel logLevel = NLogManager.GetLevel(level); - NLogManager.Configure(logLevel); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Cesxhin.AnimeManga.Api v1")); - } - - app.UseHttpsRedirection(); - - app.UseRouting(); - - // global cors policy - app.UseCors(x => x - .AllowAnyMethod() - .AllowAnyHeader() - .SetIsOriginAllowed(origin => true)); - - app.UseAuthorization(); - app.UseAuthentication(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - } - } -} diff --git a/src/Cesxhin.AnimeManga.Api/appsettings.Development.json b/src/Cesxhin.AnimeManga.Api/appsettings.Development.json deleted file mode 100644 index 8983e0f..0000000 --- a/src/Cesxhin.AnimeManga.Api/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - } -} diff --git a/src/Cesxhin.AnimeManga.Api/appsettings.json b/src/Cesxhin.AnimeManga.Api/appsettings.json deleted file mode 100644 index 222224e..0000000 --- a/src/Cesxhin.AnimeManga.Api/appsettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*" -} \ No newline at end of file diff --git a/src/Cesxhin.AnimeManga.Api/schema_template.json b/src/Cesxhin.AnimeManga.Api/schema_template.json deleted file mode 100644 index 305b5c8..0000000 --- a/src/Cesxhin.AnimeManga.Api/schema_template.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "*": { - "name": "string", - "type": "string", - "search": { - "url_search": "string", - "page": "boolean", - "prefixSearch": "string", - - "collection": "*", - - "description": { - "imageUrl": "*", - "urlPage": "*", - "name": "*" - } - }, - "description": { - "*": "*" - }, - "video": { - "collection": "*", - "procedure": { - "*":"*" - } - } - } -} \ No newline at end of file diff --git a/src/Cesxhin.AnimeManga.Application/Cesxhin.AnimeManga.Application.csproj b/src/Cesxhin.AnimeManga.Application/Cesxhin.AnimeManga.Application.csproj deleted file mode 100644 index 05a0d02..0000000 --- a/src/Cesxhin.AnimeManga.Application/Cesxhin.AnimeManga.Application.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net5.0 - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Controllers/IGeneralControllerBase.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Controllers/IGeneralControllerBase.cs deleted file mode 100644 index ba293e2..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Controllers/IGeneralControllerBase.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Controllers -{ - public interface IGeneralControllerBase - { - //get - public Task GetInfoAll(string nameCfg, string username); - public Task GetInfoByName(string nameCfg, string name, string username); - public Task GetMostInfoByName(string nameCfg, string name, string username); - public Task GetAll(string nameCfg, string username); - public Task GetObjectByName(string name); - public Task GetObjectById(string id); - public Task GetObjectRegisterByObjectId(string id); - public Task GetListSearchByName(string nameCfg, string name); - public Task GetStateProgress(string name, string username, string nameCfg); - public Task GetObjectsQueue(); - public Task GetObjectQueue(string name, string url, string nameCfg); - - //put - public Task PutInfo(string nameCfg, I infoClass); - public Task UpdateInfo(string content); - public Task PutObject(O objectClass); - public Task PutObjects(List objectsClass); - public Task PutObjectsRegisters(List objectsRegistersClass); - public Task UpdateObjectRegister(R objectRegisterClass); - public Task RedownloadObjectByUrlPage(string id, string username); - public Task DownloadInfoByUrlPage(D objectsClass, string username); - public Task PutUpdateStateDownload(O objectClass); - public Task PutStateProgress(E objectClass); - public Task PutObjectQueue(Q objectClass); - public Task PutObjectBlackList(S objectClass); - - //delete - public Task DeleteInfo(string nameCfg, string id, string username); - public Task DeleteObjectQueue(Q objectClass); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IAccountRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IAccountRepository.cs deleted file mode 100644 index 395dd53..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IAccountRepository.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IAccountRepository - { - public Task CreateAccount(Auth auth); - public Task FindAccountByUsername(string username); - - //whitelist generic - public Task> GetListWatchListByUsername(string username); - public Task InsertWhiteList(WatchList whiteList); - public Task DeleteWhiteList(WatchList whiteList); - public Task WhiteListCheckByName(string name, string username); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterBlackListRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterBlackListRepository.cs deleted file mode 100644 index c54e089..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterBlackListRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IChapterBlackListRepository : IGeneralObjectBlackListRepository - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterQueueRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterQueueRepository.cs deleted file mode 100644 index c8f4c53..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterQueueRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IChapterQueueRepository : IGeneralObjectQueueRepository - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRegisterRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRegisterRepository.cs deleted file mode 100644 index dbb1c89..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRegisterRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IChapterRegisterRepository : IGeneralObjectRegisterRepository - { - } -} \ No newline at end of file diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRepository.cs deleted file mode 100644 index 7129947..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IChapterRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IChapterRepository : IGeneralObjectRepository - { - public Task DeleteByNameAsync(string id); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IDescriptionRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IDescriptionRepository.cs deleted file mode 100644 index d8b649c..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IDescriptionRepository.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Newtonsoft.Json.Linq; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IDescriptionRepository : IGeneralNameRepository - { - - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeBlackListRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeBlackListRepository.cs deleted file mode 100644 index 84c7681..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeBlackListRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IEpisodeBlackListRepository : IGeneralObjectBlackListRepository - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeQueueRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeQueueRepository.cs deleted file mode 100644 index 68d8d2a..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeQueueRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IEpisodeQueueRepository : IGeneralObjectQueueRepository - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRegisterRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRegisterRepository.cs deleted file mode 100644 index 98ab7f3..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRegisterRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IEpisodeRegisterRepository : IGeneralObjectRegisterRepository - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRepository.cs deleted file mode 100644 index 1d86b29..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IEpisodeRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IEpisodeRepository : IGeneralObjectRepository - { - public Task DeleteByNameAsync(string id); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralNameRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralNameRepository.cs deleted file mode 100644 index 537bb44..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralNameRepository.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IGeneralNameRepository - { - //get - Task> GetNameAllAsync(string nameCfg); - Task GetNameByNameAsync(string nameCfg, string name); - Task> GetMostNameByNameAsync(string nameCfg, string name); - - //Insert - Task InsertNameAsync(string nameCfg, TGeneralName generalName); - - //Update - Task UpdateNameAsync(string nameCfg, TGeneralName generalName); - - //delete - Task DeleteNameAsync(string nameCfg, string id); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectBlackListRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectBlackListRepository.cs deleted file mode 100644 index dbca8bf..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectBlackListRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IGeneralObjectBlackListRepository - { - //get - Task GetObjectBlackList(T objectGeneral); - Task> GetObjectsBlackList(); - - //put - Task PutObjectBlackList(T objectGeneral); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectQueueRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectQueueRepository.cs deleted file mode 100644 index a8bd2f4..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectQueueRepository.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IGeneralObjectQueueRepository - { - //get - Task> GetObjectsQueue(); - Task GetObjectQueue(T objectGeneral); - - //put - Task PutObjectQueue(T objectGeneral); - - //delete - Task DeleteObjectQueue(T objectGeneral); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRegisterRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRegisterRepository.cs deleted file mode 100644 index c71d4b8..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRegisterRepository.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IGeneralObjectRegisterRepository - { - //get - Task GetObjectRegisterByObjectId(string id); - Task> GetObjectsRegistersByListObjectId(List listObjects); - - //insert - Task> InsertObjectsRegisterAsync(List objectRegister); - Task InsertObjectRegisterAsync(T objectRegister); - - //put - Task UpdateObjectRegisterAsync(T objectRegister); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRepository.cs deleted file mode 100644 index b8cec89..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IGeneralObjectRepository.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IGeneralObjectRepository - { - //get - Task GetObjectByIDAsync(string id); - Task> GetObjectsByNameAsync(string nameGeneral); - - //insert - Task> InsertObjectsAsync(List objectsGeneral); - Task InsertObjectAsync(T objectGeneral); - - //update - Task UpdateStateDownloadAsync(T objectGeneral); - - //reset - Task ResetStatusDownloadObjectByIdAsync(T objectGeneral); - Task> ResetStatusDownloadObjectsByIdAsync(List objectsGeneral); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressChapterRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressChapterRepository.cs deleted file mode 100644 index 5a555f0..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressChapterRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IProgressChapterRepository - { - public Task UpdateProgress(ProgressChapter progress); - public Task CheckProgress(string name, string username, string nameCfg); - public Task CreateProgress(ProgressChapter progress); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressEpisodeRepository.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressEpisodeRepository.cs deleted file mode 100644 index 6c413ad..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Repositories/IProgressEpisodeRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Repositories -{ - public interface IProgressEpisodeRepository - { - public Task UpdateProgress(ProgressEpisode progress); - public Task CheckProgress(string name, string username, string nameCfg); - public Task CreateProgress(ProgressEpisode progress); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IAccountService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IAccountService.cs deleted file mode 100644 index a8b1109..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IAccountService.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IAccountService - { - public Task Login(string username, string password); - public Task CreateAccount(string username, string password); - public Task FindAccountByUsername(string username); - - //whitelist generic - public Task> GetListWatchListByUsername(string username); - public Task InsertWatchList(WatchListDTO whiteListDTO); - public Task DeleteWatchList(WatchListDTO whiteListDTO); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterBlackListService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterBlackListService.cs deleted file mode 100644 index 995bff4..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterBlackListService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IChapterBlackListService : IGeneralObjectBlackListService - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterQueueService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterQueueService.cs deleted file mode 100644 index f75139b..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterQueueService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IChapterQueueService : IGeneralObjectQueueService - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterRegisterService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterRegisterService.cs deleted file mode 100644 index 6196df2..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterRegisterService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IChapterRegisterService : IGeneralObjectRegister - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterService.cs deleted file mode 100644 index b3a07b8..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IChapterService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IChapterService : IGeneralObject - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionBookService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionBookService.cs deleted file mode 100644 index aa60034..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionBookService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using Newtonsoft.Json.Linq; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IDescriptionBookService : IGeneralNameService - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionVideoService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionVideoService.cs deleted file mode 100644 index c460181..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IDescriptionVideoService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using Newtonsoft.Json.Linq; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IDescriptionVideoService : IGeneralNameService - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeBlackListService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeBlackListService.cs deleted file mode 100644 index f1a9e7c..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeBlackListService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IEpisodeBlackListService : IGeneralObjectBlackListService - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeQueueService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeQueueService.cs deleted file mode 100644 index 4d3fd7c..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeQueueService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IEpisodeQueueService : IGeneralObjectQueueService - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeRegisterService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeRegisterService.cs deleted file mode 100644 index 0067900..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeRegisterService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IEpisodeRegisterService : IGeneralObjectRegister - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeService.cs deleted file mode 100644 index 5757c3d..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IEpisodeService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IEpisodeService : IGeneralObject - { - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralNameService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralNameService.cs deleted file mode 100644 index 70c94ea..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralNameService.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IGeneralNameService - { - //get - Task> GetNameAllAsync(string nameCfg, string username); - Task GetNameByNameAsync(string nameCfg, string name, string username); - Task> GetMostNameByNameAsync(string nameCfg, string name, string username); - Task> GetNameAllWithAllAsync(string nameCfg, string username); - Task> GetNameAllOnlyWatchListAsync(string nameCfg, string username); - - //insert - Task InsertNameAsync(string nameCfg, TGeneralNameDTO anime); - - //update - Task UpdateNameAsync(string nameCfg, TGeneralNameDTO anime); - - //delete - Task DeleteNameByIdAsync(string nameCfg, string id); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObject.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObject.cs deleted file mode 100644 index f19fc2d..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObject.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IGeneralObject - { - //get - Task GetObjectByIDAsync(string id); - Task> GetObjectsByNameAsync(string name); - - //insert - Task> InsertObjectsAsync(List generalObjects); - Task InsertObjectAsync(TObjectDTO generalObject); - - //update - Task UpdateStateDownloadAsync(TObjectDTO generalObject); - - //reset - Task ResetStatusDownloadObjectByIdAsync(TObjectDTO generalObject); - Task> ResetStatusMultipleDownloadObjectByIdAsync(string name); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectBlackListService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectBlackListService.cs deleted file mode 100644 index 6b952de..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectBlackListService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IGeneralObjectBlackListService - { - //get - Task GetObjectBlackList(TObjectDTO objectGeneral); - Task> GetObjectsBlackList(); - - //put - Task PutObjectBlackList(TObjectDTO objectGeneral); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectQueueService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectQueueService.cs deleted file mode 100644 index 5f74f49..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectQueueService.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IGeneralObjectQueueService - { - //get - Task> GetObjectsQueue(); - Task GetObjectQueue(TObjectDTO objectGeneral); - - //put - Task PutObjectQueue(TObjectDTO objectGeneral); - - //delete - Task DeleteObjectQueue(TObjectDTO objectGeneral); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectRegister.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectRegister.cs deleted file mode 100644 index 2c70119..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IGeneralObjectRegister.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IGeneralObjectRegister - { - //get - Task GetObjectRegisterByObjectId(string id); - Task> GetObjectsRegistersByListObjectId(List objectDTOs); - - //insert - Task InsertObjectRegisterAsync(TObjectRegisterDTO objectGeneralRegister); - Task> InsertObjectsRegistersAsync(List objectGeneralRegister); - - //put - Task UpdateObjectRegisterAsync(TObjectRegisterDTO objectGeneralRegister); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressChapterService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressChapterService.cs deleted file mode 100644 index f0d1178..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressChapterService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IProgressChapterService - { - //get - public Task GetProgressByName(string name, string username, string nameCfg); - - //update - public Task UpdateProgress(ProgressChapterDTO progress); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressEpisodeService.cs b/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressEpisodeService.cs deleted file mode 100644 index b7ef3f7..0000000 --- a/src/Cesxhin.AnimeManga.Application/Interfaces/Services/IProgressEpisodeService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Interfaces.Services -{ - public interface IProgressEpisodeService - { - //get - public Task GetProgressByName(string name, string username, string nameCfg); - - //update - public Task UpdateProgress(ProgressEpisodeDTO progress); - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/AccountService.cs b/src/Cesxhin.AnimeManga.Application/Services/AccountService.cs deleted file mode 100644 index 908b57d..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/AccountService.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class AccountService : IAccountService - { - public readonly IAccountRepository _accountRepository; - public AccountService(IAccountRepository accountRepository) - { - _accountRepository = accountRepository; - } - - private static bool ValidPassword(string password, string hasedPassword) - { - return BCrypt.Net.BCrypt.Verify(password, hasedPassword); - } - - private static string CryptPasword(string password) - { - return BCrypt.Net.BCrypt.HashPassword(password); - } - - public async Task CreateAccount(string username, string password) - { - try - { - await _accountRepository.FindAccountByUsername(username); - throw new ApiConflictException("Conflict CreateAccount"); - } - catch (ApiNotFoundException) - { - var auth = new Auth - { - Username = username, - Password = password - }; - - auth.Password = CryptPasword(auth.Password); - var authResult = await _accountRepository.CreateAccount(auth); - - return AuthDTO.AuthToAuthDTO(authResult); - } - } - - public async Task Login(string username, string password) - { - Auth findUser; - try - { - findUser = await _accountRepository.FindAccountByUsername(username); - } - catch (ApiNotFoundException) - { - throw new ApiNotAuthorizeException("Not Authorize Login"); - } - - if (findUser != null && ValidPassword(password, findUser.Password)) - return AuthDTO.AuthToAuthDTO(findUser); - else - throw new ApiNotAuthorizeException("Not Authorize Login"); - - } - - public async Task InsertWatchList(WatchListDTO whiteListDTO) - { - try - { - await _accountRepository.WhiteListCheckByName(whiteListDTO.Name, whiteListDTO.Username); - throw new ApiConflictException("Conflict InsertWatchList"); - } - catch (ApiNotFoundException) - { - var result = await _accountRepository.InsertWhiteList(WatchList.WatchListDTOToWatchList(whiteListDTO)); - return WatchListDTO.WatchListToWatchListDTO(result); - } - } - - public async Task DeleteWatchList(WatchListDTO whiteListDTO) - { - var result = await _accountRepository.DeleteWhiteList(WatchList.WatchListDTOToWatchList(whiteListDTO)); - return WatchListDTO.WatchListToWatchListDTO(result); - } - - public async Task> GetListWatchListByUsername(string username) - { - var result = await _accountRepository.GetListWatchListByUsername(username); - - var resultArray = new List(); - - foreach (var item in result) - { - resultArray.Add(WatchListDTO.WatchListToWatchListDTO(item)); - } - - return resultArray; - } - - public async Task FindAccountByUsername(string username) - { - var result = await _accountRepository.FindAccountByUsername(username); - - return AuthDTO.AuthToAuthDTO(result); - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/ChapterBlackListService.cs b/src/Cesxhin.AnimeManga.Application/Services/ChapterBlackListService.cs deleted file mode 100644 index 7d112db..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/ChapterBlackListService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class ChapterBlackListService : IChapterBlackListService - { - public readonly IChapterBlackListRepository _chapterBlackListRepository; - public ChapterBlackListService(IChapterBlackListRepository chapterBlackListRepository) - { - _chapterBlackListRepository = chapterBlackListRepository; - } - - public async Task GetObjectBlackList(GenericBlackListDTO objectGeneral) - { - { - var find = await _chapterBlackListRepository.GetObjectBlackList(ChapterBlacklist.GenericQueueDTOToChapterBlacklist(objectGeneral)); - - return GenericBlackListDTO.ChapterBlackListToGenericBlackListDTO(find); - } - } - - public async Task> GetObjectsBlackList() - { - var rs = await _chapterBlackListRepository.GetObjectsBlackList(); - - List listGenericQueueDTO = new(); - - foreach (var EpisodeQueue in rs.ToList()) - { - listGenericQueueDTO.Add(GenericBlackListDTO.ChapterBlackListToGenericBlackListDTO(EpisodeQueue)); - } - - return listGenericQueueDTO; - } - - public async Task PutObjectBlackList(GenericBlackListDTO objectGeneral) - { - var objectGeneralRepository = ChapterBlacklist.GenericQueueDTOToChapterBlacklist(objectGeneral); - - try - { - await _chapterBlackListRepository.GetObjectBlackList(objectGeneralRepository); - throw new ApiConflictException("Conflict Chapter queue"); - } - catch (ApiNotFoundException) - { - var rs = await _chapterBlackListRepository.PutObjectBlackList(objectGeneralRepository); - return GenericBlackListDTO.ChapterBlackListToGenericBlackListDTO(rs); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/ChapterQueueService.cs b/src/Cesxhin.AnimeManga.Application/Services/ChapterQueueService.cs deleted file mode 100644 index ef29536..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/ChapterQueueService.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class ChapterQueueService : IChapterQueueService - { - public readonly IChapterQueueRepository _chapterQueueRepository; - public ChapterQueueService(IChapterQueueRepository chapterQueueRepository) - { - _chapterQueueRepository = chapterQueueRepository; - } - - public async Task DeleteObjectQueue(GenericQueueDTO objectGeneral) - { - var find = await _chapterQueueRepository.GetObjectQueue(ChapterQueue.GenericQueueDTOToChapterQueue(objectGeneral)); - await _chapterQueueRepository.DeleteObjectQueue(find); - - return objectGeneral; - } - - public async Task GetObjectQueue(GenericQueueDTO objectGeneral) - { - var find = await _chapterQueueRepository.GetObjectQueue(ChapterQueue.GenericQueueDTOToChapterQueue(objectGeneral)); - - return GenericQueueDTO.ChapterQueueToGenericQueueDTO(find); - } - - public async Task> GetObjectsQueue() - { - var rs = await _chapterQueueRepository.GetObjectsQueue(); - - List listGenericQueueDTO = new(); - - foreach (var ChapterQueue in rs.ToList()) - { - listGenericQueueDTO.Add(GenericQueueDTO.ChapterQueueToGenericQueueDTO(ChapterQueue)); - } - - return listGenericQueueDTO; - } - - public async Task PutObjectQueue(GenericQueueDTO objectGeneral) - { - var objectGeneralRepository = ChapterQueue.GenericQueueDTOToChapterQueue(objectGeneral); - - try - { - await _chapterQueueRepository.GetObjectQueue(objectGeneralRepository); - throw new ApiConflictException("Conflict Chapter queue"); - } - catch (ApiNotFoundException) - { - var rs = await _chapterQueueRepository.PutObjectQueue(objectGeneralRepository); - return GenericQueueDTO.ChapterQueueToGenericQueueDTO(rs); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/ChapterRegisterService.cs b/src/Cesxhin.AnimeManga.Application/Services/ChapterRegisterService.cs deleted file mode 100644 index d0b787d..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/ChapterRegisterService.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class ChapterRegisterService : IChapterRegisterService - { - //interfaces - private readonly IChapterRegisterRepository _chapterRegisterRepository; - - public ChapterRegisterService(IChapterRegisterRepository chapterRegisterRepository) - { - _chapterRegisterRepository = chapterRegisterRepository; - } - - //get chapterRegister by chapter id - public async Task GetObjectRegisterByObjectId(string id) - { - var chapterRegister = await _chapterRegisterRepository.GetObjectRegisterByObjectId(id); - return ChapterRegisterDTO.ChapterRegisterToChapterRegisterDTO(chapterRegister); - } - - public async Task> GetObjectsRegistersByListObjectId(List listChapterDTO) - { - List listChapter = new(); - - foreach (var chapterDTO in listChapterDTO) - { - listChapter.Add(Chapter.ChapterDTOToChapter(chapterDTO)); - } - - var rs = await _chapterRegisterRepository.GetObjectsRegistersByListObjectId(listChapter); - - - List listChapterRegisterDTO = new(); - - foreach (var chapterRegister in rs.ToList()) - { - listChapterRegisterDTO.Add(ChapterRegisterDTO.ChapterRegisterToChapterRegisterDTO(chapterRegister)); - } - - return listChapterRegisterDTO; - } - - //insert chapterRegister - public async Task InsertObjectRegisterAsync(ChapterRegisterDTO chapterRegister) - { - var result = await _chapterRegisterRepository.InsertObjectRegisterAsync(ChapterRegister.ChapterRegisterDTOToChapterRegister(chapterRegister)); - return ChapterRegisterDTO.ChapterRegisterToChapterRegisterDTO(result); - } - - //insert list chapterRegister - public async Task> InsertObjectsRegistersAsync(List chaptersRegisters) - { - List chapterRegistersConvert = new(); - foreach (var chapter in chaptersRegisters) - { - chapterRegistersConvert.Add(ChapterRegister.ChapterRegisterDTOToChapterRegister(chapter)); - } - - var resultChapters = await _chapterRegisterRepository.InsertObjectsRegisterAsync(chapterRegistersConvert); - - - List chapterRegistersDTOConvert = new(); - foreach (var chapter in resultChapters) - { - chapterRegistersDTOConvert.Add(ChapterRegisterDTO.ChapterRegisterToChapterRegisterDTO(chapter)); - } - - return chapterRegistersDTOConvert; - } - - //Update chapterRegister - public async Task UpdateObjectRegisterAsync(ChapterRegisterDTO chapterRegister) - { - var chapterResult = await _chapterRegisterRepository.UpdateObjectRegisterAsync(ChapterRegister.ChapterRegisterDTOToChapterRegister(chapterRegister)); - return ChapterRegisterDTO.ChapterRegisterToChapterRegisterDTO(chapterResult); - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/ChapterService.cs b/src/Cesxhin.AnimeManga.Application/Services/ChapterService.cs deleted file mode 100644 index 054774c..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/ChapterService.cs +++ /dev/null @@ -1,99 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class ChapterService : IChapterService - { - //interfaces - private readonly IChapterRepository _chapterRepository; - - public ChapterService(IChapterRepository chapterRepository) - { - _chapterRepository = chapterRepository; - } - - //get chapter by id - public async Task GetObjectByIDAsync(string id) - { - var rs = await _chapterRepository.GetObjectByIDAsync(id); - return ChapterDTO.ChapterToChapterDTO(rs); - } - - //get chapters by name - public async Task> GetObjectsByNameAsync(string name) - { - var listChapter = await _chapterRepository.GetObjectsByNameAsync(name); - - List chapters = new(); - foreach (var chapter in listChapter) - { - chapters.Add(ChapterDTO.ChapterToChapterDTO(chapter)); - } - - return chapters; - } - - //insert one chapter - public async Task InsertObjectAsync(ChapterDTO chapter) - { - var chapterResult = await _chapterRepository.InsertObjectAsync(Chapter.ChapterDTOToChapter(chapter)); - return ChapterDTO.ChapterToChapterDTO(chapterResult); - } - - //insert chapters - public async Task> InsertObjectsAsync(List chapters) - { - List chaptersConvert = new(); - foreach (var chapter in chapters) - { - chaptersConvert.Add(Chapter.ChapterDTOToChapter(chapter)); - } - - var resultChapters = await _chapterRepository.InsertObjectsAsync(chaptersConvert); - - List chaptersDTOConvert = new(); - foreach (var chapter in resultChapters) - { - chaptersDTOConvert.Add(ChapterDTO.ChapterToChapterDTO(chapter)); - } - - return chaptersDTOConvert; - } - - //reset manual - public async Task ResetStatusDownloadObjectByIdAsync(ChapterDTO chapter) - { - var rs = await _chapterRepository.ResetStatusDownloadObjectByIdAsync(Chapter.ChapterDTOToChapter(chapter)); - return ChapterDTO.ChapterToChapterDTO(rs); - } - - //reset automatic - public async Task> ResetStatusMultipleDownloadObjectByIdAsync(string name) - { - var listChapters = await _chapterRepository.GetObjectsByNameAsync(name); - - var resultChapters = await _chapterRepository.ResetStatusDownloadObjectsByIdAsync(listChapters.ToList()); - - List chaptersDTOConvert = new(); - foreach (var chapter in resultChapters) - { - chaptersDTOConvert.Add(ChapterDTO.ChapterToChapterDTO(chapter)); - } - - return chaptersDTOConvert; - } - - //update PercentualState - public async Task UpdateStateDownloadAsync(ChapterDTO chapter) - { - var chapterResult = await _chapterRepository.UpdateStateDownloadAsync(Chapter.ChapterDTOToChapter(chapter)); - return ChapterDTO.ChapterToChapterDTO(chapterResult); - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/DescriptionBookService.cs b/src/Cesxhin.AnimeManga.Application/Services/DescriptionBookService.cs deleted file mode 100644 index 3630acd..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/DescriptionBookService.cs +++ /dev/null @@ -1,278 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.DTO; -using Newtonsoft.Json.Linq; -using NLog; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class DescriptionBookService : IDescriptionBookService - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //interfaces - private readonly IDescriptionRepository _descriptionRepository; - private readonly IChapterRepository _chapterRepository; - private readonly IChapterRegisterRepository _chapterRegisterRepository; - private readonly IAccountService _accountService; - - public DescriptionBookService(IAccountService accountService, IDescriptionRepository descriptionRepository, IChapterRepository chapterRepository, IChapterRegisterRepository chapterRegisterRepository) - { - _descriptionRepository = descriptionRepository; - _chapterRepository = chapterRepository; - _chapterRegisterRepository = chapterRegisterRepository; - _accountService = accountService; - } - - public async Task DeleteNameByIdAsync(string nameCfg, string name) - { - //get episodes - var episodes = await _chapterRepository.GetObjectsByNameAsync(name); - - foreach (var episode in episodes) - { - if (!(episode.StateDownload == "completed" || episode.StateDownload == null)) - throw new ApiConflictException("Conflict DeleteNameByIdAsync"); - } - - try - { - await _descriptionRepository.DeleteNameAsync(nameCfg, name); - } - catch (ApiNotFoundException) - { - _logger.Warn($"I tried delete description book name: {name} nameCfg: {nameCfg}"); - } - - try - { - await _chapterRepository.DeleteByNameAsync(name); - } - catch (ApiNotFoundException) - { - _logger.Warn($"I tried delete chapters name: {name} nameCfg: {nameCfg}"); - } - - return name; - } - - public async Task> GetMostNameByNameAsync(string nameCfg, string name, string username) - { - var result = await _descriptionRepository.GetMostNameByNameAsync(nameCfg, name); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - result.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - item["watchList"] = true; - else - item["watchList"] = false; - }); - } - catch (ApiNotFoundException) { } - - return result; - } - - public async Task> GetNameAllAsync(string nameCfg, string username) - { - var result = await _descriptionRepository.GetNameAllAsync(nameCfg); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - result.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - item["watchList"] = true; - else - item["watchList"] = false; - }); - } - catch (ApiNotFoundException) { } - - return result; - } - - public async Task> GetNameAllOnlyWatchListAsync(string nameCfg, string username) - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - var result = new List(); - JObject resultFind; - - foreach (var watch in watchList) - { - if (watch.NameCfg == nameCfg) - { - try - { - resultFind = await _descriptionRepository.GetNameByNameAsync(watch.NameCfg, watch.Name); - - if (resultFind != null) - result.Add(resultFind); - } - catch (ApiNotFoundException) { } - } - } - - result.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - item["watchList"] = true; - else - item["watchList"] = false; - }); - - return result; - } - - public async Task> GetNameAllWithAllAsync(string nameCfg, string username) - { - List listGenericDTO = new(); - List listEpisodeDTO = new(); - List listEpisodeRegisterDTO = new(); - - var listDescriptions = await _descriptionRepository.GetNameAllAsync(nameCfg); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - listDescriptions.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - item["watchList"] = true; - else - item["watchList"] = false; - }); - } - catch (ApiNotFoundException) { } - - //anime - foreach (var description in listDescriptions) - { - var episodes = await _chapterRepository.GetObjectsByNameAsync(description.GetValue("name_id").ToString()); - - //episodes - foreach (var episode in episodes) - { - var episodeRegister = await _chapterRegisterRepository.GetObjectRegisterByObjectId(episode.ID); - - listEpisodeRegisterDTO.Add(ChapterRegisterDTO.ChapterRegisterToChapterRegisterDTO(episodeRegister)); - listEpisodeDTO.Add(ChapterDTO.ChapterToChapterDTO(episode)); - } - - listGenericDTO.Add(new GenericBookDTO - { - Book = description.ToString(), - Chapters = listEpisodeDTO, - ChapterRegister = listEpisodeRegisterDTO - }); - - //reset - listEpisodeDTO = new(); - listEpisodeRegisterDTO = new(); - } - - return listGenericDTO; - } - - public async Task GetNameByNameAsync(string nameCfg, string name, string username) - { - var result = await _descriptionRepository.GetNameByNameAsync(nameCfg, name); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == result["name_id"].ToString() && singleWatchList.NameCfg == result["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - result["watchList"] = true; - else - result["watchList"] = false; - } - catch (ApiNotFoundException) { } - - return result; - } - - public async Task InsertNameAsync(string nameCfg, JObject description) - { - if (description.ContainsKey("name_id")) - { - try - { - await _descriptionRepository.GetNameByNameAsync(nameCfg, description.GetValue("name_id").ToString()); - throw new ApiConflictException(); - } - catch (ApiNotFoundException) - { - return await _descriptionRepository.InsertNameAsync(nameCfg, description); - } - } - else - { - _logger.Error("Not found field 'name_id' of book"); - throw new ApiNotFoundException("Not found field 'name_id' of book"); - } - } - - public async Task UpdateNameAsync(string nameCfg, JObject description) - { - if (description.ContainsKey("name_id")) - { - await _descriptionRepository.GetNameByNameAsync(nameCfg, description.GetValue("name_id").ToString()); - return await _descriptionRepository.UpdateNameAsync(nameCfg, description); - } - else - { - _logger.Error("Not found field 'name_id' of book"); - throw new ApiNotFoundException("Not found field 'name_id' of book"); - } - } - } -} \ No newline at end of file diff --git a/src/Cesxhin.AnimeManga.Application/Services/DescriptionVideoService.cs b/src/Cesxhin.AnimeManga.Application/Services/DescriptionVideoService.cs deleted file mode 100644 index f51aa44..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/DescriptionVideoService.cs +++ /dev/null @@ -1,286 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.DTO; -using Newtonsoft.Json.Linq; -using NLog; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class DescriptionVideoService : IDescriptionVideoService - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //interfaces - private readonly IDescriptionRepository _descriptionRepository; - private readonly IEpisodeRepository _episodeRepository; - private readonly IEpisodeRegisterRepository _episodeRegisterRepository; - private readonly IAccountService _accountService; - - public DescriptionVideoService(IAccountService accountService, IDescriptionRepository descriptionRepository, IEpisodeRepository episodeRepository, IEpisodeRegisterRepository episodeRegisterRepository) - { - _descriptionRepository = descriptionRepository; - _episodeRepository = episodeRepository; - _episodeRegisterRepository = episodeRegisterRepository; - _accountService = accountService; - } - public async Task DeleteNameByIdAsync(string nameCfg, string name) - { - //get episodes - var episodes = await _episodeRepository.GetObjectsByNameAsync(name); - - foreach (var episode in episodes) - { - if (!(episode.StateDownload == "completed" || episode.StateDownload == null)) - throw new ApiConflictException(); - } - - try - { - await _descriptionRepository.DeleteNameAsync(nameCfg, name); - } - catch (ApiNotFoundException) - { - _logger.Warn($"I tried delete description video name: {name} nameCfg: {nameCfg}"); - } - - try - { - await _episodeRepository.DeleteByNameAsync(name); - } - catch (ApiNotFoundException) - { - _logger.Warn($"I tried delete episodes name: {name} nameCfg: {nameCfg}"); - } - - return name; - } - - public async Task> GetMostNameByNameAsync(string nameCfg, string name, string username) - { - var result = await _descriptionRepository.GetMostNameByNameAsync(nameCfg, name); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - result.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - item["watchList"] = true; - else - item["watchList"] = false; - }); - } - catch (ApiNotFoundException) { } - - return result; - } - - public async Task> GetNameAllAsync(string nameCfg, string username) - { - var result = await _descriptionRepository.GetNameAllAsync(nameCfg); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - result.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - item["watchList"] = true; - else - item["watchList"] = false; - }); - } - catch (ApiNotFoundException) { } - - return result; - } - - public async Task> GetNameAllOnlyWatchListAsync(string nameCfg, string username) - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - var result = new List(); - JObject resultFind; - - foreach (var watch in watchList) - { - if (watch.NameCfg == nameCfg) - { - try - { - resultFind = await _descriptionRepository.GetNameByNameAsync(watch.NameCfg, watch.Name); - - if (resultFind != null) - result.Add(resultFind); - } - catch (ApiNotFoundException) { } - } - } - - result.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - item["watchList"] = true; - else - item["watchList"] = false; - }); - - return result; - } - - public async Task> GetNameAllWithAllAsync(string nameCfg, string username) - { - List listGenericDTO = new(); - - List listEpisodeDTO = new(); - List listEpisodeRegisterDTO = new(); - - var listDescriptions = await _descriptionRepository.GetNameAllAsync(nameCfg); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - listDescriptions.ForEach(item => - { - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == item["name_id"].ToString() && singleWatchList.NameCfg == item["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Any()) - item["watchList"] = true; - else - item["watchList"] = false; - }); - } - catch (ApiNotFoundException) { } - - //anime - foreach (var description in listDescriptions) - { - var episodes = await _episodeRepository.GetObjectsByNameAsync(description.GetValue("name_id").ToString()); - - //episodes - foreach (var episode in episodes) - { - var episodeRegister = await _episodeRegisterRepository.GetObjectRegisterByObjectId(episode.ID); - - listEpisodeRegisterDTO.Add(EpisodeRegisterDTO.EpisodeRegisterToEpisodeRegisterDTO(episodeRegister)); - listEpisodeDTO.Add(EpisodeDTO.EpisodeToEpisodeDTO(episode)); - } - - var objectAll = JObject.FromObject(new - { - description, - listEpisodeDTO, - listEpisodeRegisterDTO - }); - - listGenericDTO.Add(new GenericVideoDTO() - { - Video = description.ToString(), - Episodes = listEpisodeDTO, - EpisodesRegister = listEpisodeRegisterDTO - }); - - //reset - listEpisodeDTO = new(); - listEpisodeRegisterDTO = new(); - } - - return listGenericDTO; - } - - public async Task GetNameByNameAsync(string nameCfg, string name, string username) - { - var result = await _descriptionRepository.GetNameByNameAsync(nameCfg, name); - - try - { - var watchList = await _accountService.GetListWatchListByUsername(username); - - var filterWatchList = watchList.Where((singleWatchList) => - { - if (singleWatchList.Name == result["name_id"].ToString() && singleWatchList.NameCfg == result["nameCfg"].ToString()) - return true; - return false; - }); - - if (filterWatchList.Count() > 0) - result["watchList"] = true; - else - result["watchList"] = false; - } - catch (ApiNotFoundException) { } - - return result; - } - - public async Task InsertNameAsync(string nameCfg, JObject description) - { - if (description.ContainsKey("name_id")) - { - try - { - await _descriptionRepository.GetNameByNameAsync(nameCfg, description.GetValue("name_id").ToString()); - throw new ApiConflictException(); - } - catch (ApiNotFoundException) - { - return await _descriptionRepository.InsertNameAsync(nameCfg, description); - } - } - else - { - _logger.Error("Not found field 'name_id' of video"); - throw new ApiConflictException("Not found field 'name_id' of video"); - } - } - - public async Task UpdateNameAsync(string nameCfg, JObject description) - { - if (description.ContainsKey("name_id")) - { - await _descriptionRepository.GetNameByNameAsync(nameCfg, description.GetValue("name_id").ToString()); - return await _descriptionRepository.UpdateNameAsync(nameCfg, description); - } - else - { - _logger.Error("Not found field 'name_id' of video"); - throw new ApiConflictException("Not found field 'name_id' of video"); - } - } - } -} \ No newline at end of file diff --git a/src/Cesxhin.AnimeManga.Application/Services/EpisodeBlackListService.cs b/src/Cesxhin.AnimeManga.Application/Services/EpisodeBlackListService.cs deleted file mode 100644 index 850c265..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/EpisodeBlackListService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class EpisodeBlackListService : IEpisodeBlackListService - { - public readonly IEpisodeBlackListRepository _episodeBlackListRepository; - public EpisodeBlackListService(IEpisodeBlackListRepository episodeBlackListRepository) - { - _episodeBlackListRepository = episodeBlackListRepository; - } - - public async Task GetObjectBlackList(GenericBlackListDTO objectGeneral) - { - { - var find = await _episodeBlackListRepository.GetObjectBlackList(EpisodeBlacklist.GenericQueueDTOToEpisodeBlacklist(objectGeneral)); - - return GenericBlackListDTO.EpisodeBlackListToGenericBlackListDTO(find); - } - } - - public async Task> GetObjectsBlackList() - { - var rs = await _episodeBlackListRepository.GetObjectsBlackList(); - - List listGenericQueueDTO = new(); - - foreach (var EpisodeQueue in rs.ToList()) - { - listGenericQueueDTO.Add(GenericBlackListDTO.EpisodeBlackListToGenericBlackListDTO(EpisodeQueue)); - } - - return listGenericQueueDTO; - } - - public async Task PutObjectBlackList(GenericBlackListDTO objectGeneral) - { - var objectGeneralRepository = EpisodeBlacklist.GenericQueueDTOToEpisodeBlacklist(objectGeneral); - - try - { - await _episodeBlackListRepository.GetObjectBlackList(objectGeneralRepository); - throw new ApiConflictException("Conflict Chapter BlackList"); - } - catch (ApiNotFoundException) - { - var rs = await _episodeBlackListRepository.PutObjectBlackList(objectGeneralRepository); - return GenericBlackListDTO.EpisodeBlackListToGenericBlackListDTO(rs); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/EpisodeQueueService.cs b/src/Cesxhin.AnimeManga.Application/Services/EpisodeQueueService.cs deleted file mode 100644 index 3b005ef..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/EpisodeQueueService.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class EpisodeQueueService : IEpisodeQueueService - { - public readonly IEpisodeQueueRepository _episodeQueueRepository; - public EpisodeQueueService(IEpisodeQueueRepository episodeQueueRepository) - { - _episodeQueueRepository = episodeQueueRepository; - } - - public async Task DeleteObjectQueue(GenericQueueDTO objectGeneral) - { - var find = await _episodeQueueRepository.GetObjectQueue(EpisodeQueue.GenericQueueDTOToEpisodeQueue(objectGeneral)); - await _episodeQueueRepository.DeleteObjectQueue(find); - - return objectGeneral; - } - - public async Task GetObjectQueue(GenericQueueDTO objectGeneral) - { - var find = await _episodeQueueRepository.GetObjectQueue(EpisodeQueue.GenericQueueDTOToEpisodeQueue(objectGeneral)); - - return GenericQueueDTO.EpisodeQueueToGenericQueueDTO(find); - } - - public async Task> GetObjectsQueue() - { - var rs = await _episodeQueueRepository.GetObjectsQueue(); - - List listGenericQueueDTO = new(); - - foreach (var EpisodeQueue in rs.ToList()) - { - listGenericQueueDTO.Add(GenericQueueDTO.EpisodeQueueToGenericQueueDTO(EpisodeQueue)); - } - - return listGenericQueueDTO; - } - - public async Task PutObjectQueue(GenericQueueDTO objectGeneral) - { - var objectGeneralRepository = EpisodeQueue.GenericQueueDTOToEpisodeQueue(objectGeneral); - - try - { - await _episodeQueueRepository.GetObjectQueue(objectGeneralRepository); - throw new ApiConflictException("Conflict Chapter queue"); - } - catch (ApiNotFoundException) - { - var rs = await _episodeQueueRepository.PutObjectQueue(objectGeneralRepository); - return GenericQueueDTO.EpisodeQueueToGenericQueueDTO(rs); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/EpisodeRegisterService.cs b/src/Cesxhin.AnimeManga.Application/Services/EpisodeRegisterService.cs deleted file mode 100644 index 86626ed..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/EpisodeRegisterService.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class EpisodeRegisterService : IEpisodeRegisterService - { - //interfaces - private readonly IEpisodeRegisterRepository _episodeRegisterRepository; - - public EpisodeRegisterService(IEpisodeRegisterRepository episodeRegisterRepository) - { - _episodeRegisterRepository = episodeRegisterRepository; - } - - //get episodeRegister by episode id - public async Task GetObjectRegisterByObjectId(string id) - { - var episodeRegister = await _episodeRegisterRepository.GetObjectRegisterByObjectId(id); - return EpisodeRegisterDTO.EpisodeRegisterToEpisodeRegisterDTO(episodeRegister); - } - - public async Task> GetObjectsRegistersByListObjectId(List listEpisodeDTO) - { - List listEpisode = new(); - - foreach(var episodeDTO in listEpisodeDTO) - { - listEpisode.Add(Episode.EpisodeDTOToEpisode(episodeDTO)); - } - - var rs = await _episodeRegisterRepository.GetObjectsRegistersByListObjectId(listEpisode); - - - List listEpisodeRegisterDTO = new(); - - foreach (var episodeRegister in rs.ToList()) - { - listEpisodeRegisterDTO.Add(EpisodeRegisterDTO.EpisodeRegisterToEpisodeRegisterDTO(episodeRegister)); - } - - return listEpisodeRegisterDTO; - } - - //insert episodeRegister - public async Task InsertObjectRegisterAsync(EpisodeRegisterDTO episodeRegister) - { - var rs = await _episodeRegisterRepository.InsertObjectRegisterAsync(EpisodeRegister.EpisodeRegisterToEpisodeRegisterDTO(episodeRegister)); - return EpisodeRegisterDTO.EpisodeRegisterToEpisodeRegisterDTO(rs); - } - - //insert list episodeRegister - public async Task> InsertObjectsRegistersAsync(List episodesRegistersDTO) - { - List resultEpisodes = new(); - foreach (var episode in episodesRegistersDTO) - { - var episodeResult = await _episodeRegisterRepository.InsertObjectRegisterAsync(EpisodeRegister.EpisodeRegisterToEpisodeRegisterDTO(episode)); - resultEpisodes.Add(EpisodeRegisterDTO.EpisodeRegisterToEpisodeRegisterDTO(episodeResult)); - } - return resultEpisodes; - } - - //Update episodeRegister - public async Task UpdateObjectRegisterAsync(EpisodeRegisterDTO episodeRegister) - { - var rs = await _episodeRegisterRepository.UpdateObjectRegisterAsync(EpisodeRegister.EpisodeRegisterToEpisodeRegisterDTO(episodeRegister)); - return EpisodeRegisterDTO.EpisodeRegisterToEpisodeRegisterDTO(rs); - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/EpisodeService.cs b/src/Cesxhin.AnimeManga.Application/Services/EpisodeService.cs deleted file mode 100644 index 06a24df..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/EpisodeService.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class EpisodeService : IEpisodeService - { - //interfaces - private readonly IEpisodeRepository _episodeRepository; - - public EpisodeService(IEpisodeRepository episodeRepository) - { - _episodeRepository = episodeRepository; - } - - //get episode by id - public async Task GetObjectByIDAsync(string id) - { - var episode = await _episodeRepository.GetObjectByIDAsync(id); - return EpisodeDTO.EpisodeToEpisodeDTO(episode); - } - - //get episodes by name - public async Task> GetObjectsByNameAsync(string name) - { - var listEpisode = await _episodeRepository.GetObjectsByNameAsync(name); - - List episodes = new(); - foreach (var episode in listEpisode) - { - episodes.Add(EpisodeDTO.EpisodeToEpisodeDTO(episode)); - } - - return episodes; - } - - //insert one episode - public async Task InsertObjectAsync(EpisodeDTO episode) - { - var episodeResult = await _episodeRepository.InsertObjectAsync(Episode.EpisodeDTOToEpisode(episode)); - return EpisodeDTO.EpisodeToEpisodeDTO(episodeResult); - } - - //insert episodes - public async Task> InsertObjectsAsync(List episodes) - { - List resultEpisodes = new(); - foreach (var episode in episodes) - { - var episodeResult = await _episodeRepository.InsertObjectAsync(Episode.EpisodeDTOToEpisode(episode)); - resultEpisodes.Add(EpisodeDTO.EpisodeToEpisodeDTO(episodeResult)); - } - return resultEpisodes; - } - - //reset StatusDownload to null - public async Task ResetStatusDownloadObjectByIdAsync(EpisodeDTO episode) - { - var episodeResult = await _episodeRepository.ResetStatusDownloadObjectByIdAsync(Episode.EpisodeDTOToEpisode(episode)); - return EpisodeDTO.EpisodeToEpisodeDTO(episodeResult); - } - - //reset all state - public async Task> ResetStatusMultipleDownloadObjectByIdAsync(string name) - { - var listEpisodes = await _episodeRepository.GetObjectsByNameAsync(name); - - var resultEpisodes = await _episodeRepository.ResetStatusDownloadObjectsByIdAsync(listEpisodes.ToList()); - - List episodesDTOConvert = new(); - foreach (var episode in resultEpisodes) - { - episodesDTOConvert.Add(EpisodeDTO.EpisodeToEpisodeDTO(episode)); - } - - return episodesDTOConvert; - } - - //update PercentualState - public async Task UpdateStateDownloadAsync(EpisodeDTO episode) - { - var episodeResult = await _episodeRepository.UpdateStateDownloadAsync(Episode.EpisodeDTOToEpisode(episode)); - - if (episodeResult == null) - return null; - - return EpisodeDTO.EpisodeToEpisodeDTO(episodeResult); - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/ProgressChapterService.cs b/src/Cesxhin.AnimeManga.Application/Services/ProgressChapterService.cs deleted file mode 100644 index 3bbb2e9..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/ProgressChapterService.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class ProgressChapterService : IProgressChapterService - { - public readonly IProgressChapterRepository _progressChapterRepository; - public ProgressChapterService(IProgressChapterRepository progressChapterRepository) - { - _progressChapterRepository = progressChapterRepository; - } - - public async Task GetProgressByName(string name, string username, string nameCfg) - { - var result = await _progressChapterRepository.CheckProgress(name, username, nameCfg); - return ProgressChapterDTO.ProgressChapterToProgressChapterDTO(result); - } - - public async Task UpdateProgress(ProgressChapterDTO progress) - { - ProgressChapter result; - - try - { - await _progressChapterRepository.CheckProgress(progress.Name, progress.Username, progress.NameCfg); - result = await _progressChapterRepository.UpdateProgress(ProgressChapter.ProgressChapterDTOToProgressChapter(progress)); - } - catch (ApiNotFoundException) - { - result = await _progressChapterRepository.CreateProgress(ProgressChapter.ProgressChapterDTOToProgressChapter(progress)); - } - - return ProgressChapterDTO.ProgressChapterToProgressChapterDTO(result); - - } - } -} diff --git a/src/Cesxhin.AnimeManga.Application/Services/ProgressEpisodeService.cs b/src/Cesxhin.AnimeManga.Application/Services/ProgressEpisodeService.cs deleted file mode 100644 index 27a9b72..0000000 --- a/src/Cesxhin.AnimeManga.Application/Services/ProgressEpisodeService.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Application.Interfaces.Services; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Application.Services -{ - public class ProgressEpisodeService : IProgressEpisodeService - { - public readonly IProgressEpisodeRepository _progressEpisodeRepository; - public ProgressEpisodeService(IProgressEpisodeRepository progressEpisodeRepository) - { - _progressEpisodeRepository = progressEpisodeRepository; - } - - public async Task GetProgressByName(string name, string username, string nameCfg) - { - var result = await _progressEpisodeRepository.CheckProgress(name, username, nameCfg); - return ProgressEpisodeDTO.ProgressEpisodeToProgressEpisodeDTO(result); - } - - public async Task UpdateProgress(ProgressEpisodeDTO progress) - { - ProgressEpisode result; - - try - { - await _progressEpisodeRepository.CheckProgress(progress.Name, progress.Username, progress.NameCfg); - result = await _progressEpisodeRepository.UpdateProgress(ProgressEpisode.ProgressEpisodeDTOToProgressEpisode(progress)); - } - catch (ApiNotFoundException) - { - result = await _progressEpisodeRepository.CreateProgress(ProgressEpisode.ProgressEpisodeDTOToProgressEpisode(progress)); - } - - return ProgressEpisodeDTO.ProgressEpisodeToProgressEpisodeDTO(result); - - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Cesxhin.AnimeManga.Persistence.csproj b/src/Cesxhin.AnimeManga.Persistence/Cesxhin.AnimeManga.Persistence.csproj deleted file mode 100644 index a8f81bf..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Cesxhin.AnimeManga.Persistence.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net5.0 - - - - - - - - - - - - - - - diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/AccountRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/AccountRepository.cs deleted file mode 100644 index dfb59e6..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/AccountRepository.cs +++ /dev/null @@ -1,152 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.Models; -using NLog; -using Npgsql; -using RepoDb; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class AccountRepository : IAccountRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task CreateAccount(Auth auth) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - try - { - rs = await connection.InsertAsync(auth); - } - catch (Exception ex) - { - _logger.Error($"Failed CreateAccount, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return auth; - else - throw new ApiNotFoundException("Not found CreateAccount"); - } - } - - public async Task DeleteWhiteList(WatchList whiteList) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.ExecuteQueryAsync($"DELETE FROM whitelist WHERE name = '{whiteList.Name}' AND username = '{whiteList.Username}' AND namecfg = '{whiteList.NameCfg}'"); - } - catch (Exception ex) - { - _logger.Error($"Failed DeleteWhiteList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - return whiteList; - } - } - - public async Task FindAccountByUsername(string username) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Username == username); - } - catch (Exception ex) - { - _logger.Error($"Failed findAccountByUsername, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found findAccountByUsername"); - } - } - - public async Task> GetListWatchListByUsername(string username) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Username == username); - } - catch (Exception ex) - { - _logger.Error($"Failed GetListWatchListByUsername, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetListWatchListByUsername"); - } - } - - public async Task InsertWhiteList(WatchList whiteList) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - try - { - rs = await connection.InsertAsync(whiteList); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertWhiteList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return whiteList; - else - throw new ApiNotFoundException("Not found InsertWhiteList"); - } - } - - public async Task WhiteListCheckByName(string name, string username) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Name == name && e.Username == username); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertWhiteList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return true; - else - throw new ApiNotFoundException("Not found InsertWhiteList"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterBlackListRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterBlackListRepository.cs deleted file mode 100644 index 156c9be..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterBlackListRepository.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Modules.NlogManager; -using NLog; -using Npgsql; -using RepoDb; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class ChapterBlackListRepository : IChapterBlackListRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task GetObjectBlackList(ChapterBlacklist genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Url == genericQueue.Url && e.NameCfg == genericQueue.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectBlackList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetObjectBlackList"); - } - } - - public async Task> GetObjectsBlackList() - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAllAsync(); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectsBlackList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetObjectsBlackList"); - } - } - - public async Task PutObjectBlackList(ChapterBlacklist genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - try - { - rs = await connection.InsertAsync(genericQueue); - } - catch (Exception ex) - { - _logger.Error($"Failed PutObjectBlackList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return genericQueue; - else - throw new ApiNotFoundException("Not found PutObjectBlackList"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterQueueRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterQueueRepository.cs deleted file mode 100644 index a1c7861..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterQueueRepository.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Modules.NlogManager; -using NLog; -using Npgsql; -using RepoDb; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class ChapterQueueRepository : IChapterQueueRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task DeleteObjectQueue(ChapterQueue objectGeneral) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs; - try - { - rs = await connection.DeleteAsync(e => e.Url == objectGeneral.Url && e.NameCfg == objectGeneral.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed DeleteChapterQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - - if (rs > 0) - return rs; - else - throw new ApiNotFoundException("Not found DeleteChapterQueue"); - } - } - - public async Task GetObjectQueue(ChapterQueue genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Url == genericQueue.Url && e.NameCfg == genericQueue.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed GetChapterQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetChapterQueue"); - } - } - - public async Task> GetObjectsQueue() - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAllAsync(); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectsQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetObjectsQueue"); - } - } - - public async Task PutObjectQueue(ChapterQueue genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - try - { - rs = await connection.InsertAsync(genericQueue); - } - catch (Exception ex) - { - _logger.Error($"Failed PutChapterQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return genericQueue; - else - throw new ApiNotFoundException("Not found PutChapterQueue"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRegisterRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRegisterRepository.cs deleted file mode 100644 index 6433230..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRegisterRepository.cs +++ /dev/null @@ -1,136 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.Models; -using NLog; -using Npgsql; -using RepoDb; -using RepoDb.Enumerations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class ChapterRegisterRepository : IChapterRegisterRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task GetObjectRegisterByObjectId(string id) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.ChapterId == id); - } - catch (Exception ex) - { - _logger.Error($"Failed GetChapterRegisterByChapterId, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetObjectsRegisterByObjectId"); - } - } - - public async Task> InsertObjectsRegisterAsync(List chapterRegister) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - try - { - rs = await connection.InsertAllAsync(chapterRegister); - - } - catch (Exception ex) - { - _logger.Error($"Failed InsertChapterRegisterAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return chapterRegister; - else - throw new ApiNotFoundException("Not found InsertObjectRegisterAsync"); - } - } - - public async Task InsertObjectRegisterAsync(ChapterRegister chapterRegister) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - try - { - rs = await connection.InsertAsync(chapterRegister); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertChapterRegisterAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return chapterRegister; - else - throw new ApiNotFoundException("Not found InsertObjectRegisterAsync"); - } - } - - public async Task UpdateObjectRegisterAsync(ChapterRegister chapterRegister) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - try - { - rs = await connection.UpdateAsync(chapterRegister, e => e.ChapterId == chapterRegister.ChapterId); - } - catch (Exception ex) - { - _logger.Error($"Failed UpdateEpisodeRegisterAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return chapterRegister; - else - throw new ApiNotFoundException("Not found UpdateObjectRegisterAsync"); - } - } - - public async Task> GetObjectsRegistersByListObjectId(List listChapters) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAsync(new QueryField("chapterid", Operation.In, listChapters.Select(e => e.ID))); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectsRegistersByListObjectId, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetObjectsRegistersByListObjectId"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRepository.cs deleted file mode 100644 index 6926465..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/ChapterRepository.cs +++ /dev/null @@ -1,219 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Modules.Generic; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.Models; -using NLog; -using Npgsql; -using RepoDb; -using RepoDb.Enumerations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class ChapterRepository : IChapterRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task DeleteByNameAsync(string id) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - try - { - rs = await connection.DeleteAsync(e => e.NameManga == id); - } - catch (Exception ex) - { - _logger.Error($"Failed GetChapterByIDAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return rs; - else - throw new ApiNotFoundException("Not found DeleteByNameAsync"); - } - } - - public async Task GetObjectByIDAsync(string id) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAsync(e => e.ID == id); - } - catch (Exception ex) - { - _logger.Error($"Failed GetChapterByIDAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetObjectsByIDAsync"); - } - } - - public async Task> GetObjectsByNameAsync(string nameManga) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAsync(e => e.NameManga == nameManga, orderBy: OrderField.Parse(new - { - currentchapter = Order.Ascending - })); - } - catch (Exception ex) - { - _logger.Error($"Failed GetChaptersByNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return ConvertGeneric.ConvertIEnurableToListCollection(rs); - else - throw new ApiNotFoundException("Not found GetObjectsByNameAsync"); - } - } - - public async Task InsertObjectAsync(Chapter chapter) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - - try - { - rs = await connection.InsertAsync(chapter); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertObjectAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return chapter; - else - throw new ApiNotFoundException("Not found InsertObjectAsync"); - } - } - - public async Task> InsertObjectsAsync(List chapters) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.InsertAllAsync(chapters); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertChapterAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return chapters; - else - throw new ApiNotFoundException("Not found InsertObjectsAsync"); - } - } - - public async Task ResetStatusDownloadObjectByIdAsync(Chapter chapter) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - chapter.PercentualDownload = 0; - chapter.StateDownload = null; - - try - { - rs = await connection.UpdateAsync(chapter, e => e.StateDownload != "completed" && e.ID == chapter.ID); - } - catch (Exception ex) - { - _logger.Error($"Failed ResetStatusDownloadChaptersByIdAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return chapter; - else - throw new ApiNotFoundException("Not found ResetStatusDownloadObjectByIdAsync"); - } - } - - public async Task> ResetStatusDownloadObjectsByIdAsync(List chapters) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - try - { - var chaptersUpdate = chapters.Where(e => e.StateDownload != "completed").ToList(); - chaptersUpdate.ForEach(e => - { - e.PercentualDownload = 0; - e.StateDownload = null; - }); - - rs = await connection.UpdateAllAsync(chaptersUpdate); - } - catch (Exception ex) - { - _logger.Error($"Failed ResetStatusDownloadChaptersByIdAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return chapters; - else - throw new ApiNotFoundException("Not found ResetStatusDownloadObjectsByIdAsync"); - } - } - - public async Task UpdateStateDownloadAsync(Chapter chapter) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - try - { - rs = await connection.UpdateAsync(chapter); - } - catch (Exception ex) - { - _logger.Error($"Failed UpdateStateDownloadAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return chapter; - else - throw new ApiNotFoundException("Not found UpdateStateDownloadAsync"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/DescriptionRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/DescriptionRepository.cs deleted file mode 100644 index 381b8d9..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/DescriptionRepository.cs +++ /dev/null @@ -1,187 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using MongoDB.Bson; -using MongoDB.Driver; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class DescriptionRepository : IDescriptionRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION_MONGO"); - readonly string _nameDatabase = Environment.GetEnvironmentVariable("NAME_DATABASE_MONGO"); - readonly JObject _schema = JObject.Parse(Environment.GetEnvironmentVariable("SCHEMA")); - - private static string RemoveObjectId(string result) - { - var regex = new Regex(Regex.Escape("ObjectId(")); - var partOne = regex.Replace(result, "", 1); - - - regex = new Regex(Regex.Escape(")")); - return regex.Replace(partOne, "", 1); - - } - - private string GetNameTable(string nameCfg) - { - if (_schema.ContainsKey(nameCfg)) - { - return _schema.GetValue(nameCfg).ToObject().GetValue("name").ToString(); - } - - return null; - } - - public async Task DeleteNameAsync(string nameCfg, string id) - { - var client = new MongoClient(_connectionString); - - int rs = 0; - try - { - var database = client.GetDatabase(_nameDatabase); - var collection = database.GetCollection("description_" + GetNameTable(nameCfg)); - var deleteFilter = Builders.Filter.Eq("name_id", id); - var result = await collection.DeleteOneAsync(deleteFilter); - - rs = (int)result.DeletedCount; - } - catch (Exception ex) - { - client.Cluster.Dispose(); - _logger.Error($"Failed DeleteNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return rs; - else - throw new ApiNotFoundException("Not found DeleteNameAsync"); - } - - public Task> GetMostNameByNameAsync(string nameCfg, string name) - { - throw new NotImplementedException(); - } - - public async Task> GetNameAllAsync(string nameCfg) - { - var client = new MongoClient(_connectionString); - - List list; - try - { - var database = client.GetDatabase(_nameDatabase); - var collection = database.GetCollection("description_" + GetNameTable(nameCfg)); - list = collection.Find(Builders.Filter.Empty).ToList(); - } - catch (Exception ex) - { - client.Cluster.Dispose(); - _logger.Error($"Failed DeleteNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (list != null && list.Any()) - { - var listObject = new List(); - - foreach (var item in list) - { - listObject.Add(JObject.Parse(RemoveObjectId(item.ToString()))); - } - - return listObject; - } - else - throw new ApiNotFoundException("Not found GetNameAllAsync"); - } - - public async Task GetNameByNameAsync(string nameCfg, string name) - { - var client = new MongoClient(_connectionString); - - BsonDocument result; - try - { - var database = client.GetDatabase(_nameDatabase); - var collection = database.GetCollection("description_" + GetNameTable(nameCfg)); - var findFilter = Builders.Filter.Eq("name_id", name); - result = collection.Find(findFilter).FirstOrDefault(); - } - catch (Exception ex) - { - client.Cluster.Dispose(); - _logger.Error($"Failed DeleteNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (result != null && result.Any()) - return JObject.Parse(RemoveObjectId(result.ToString())); - else - throw new ApiNotFoundException("Not found GetNameByNameAsync"); - } - - public async Task InsertNameAsync(string nameCfg, JObject description) - { - var client = new MongoClient(_connectionString); - try - { - var database = client.GetDatabase(_nameDatabase); - var collection = database.GetCollection("description_" + GetNameTable(nameCfg)); - await collection.InsertOneAsync(BsonDocument.Parse(description.ToString())); - - return description; - } - catch (Exception ex) - { - client.Cluster.Dispose(); - _logger.Error($"Failed DeleteNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - } - - public async Task UpdateNameAsync(string nameCfg, JObject description) - { - var client = new MongoClient(_connectionString); - try - { - var database = client.GetDatabase(_nameDatabase); - var collection = database.GetCollection("description_" + GetNameTable(nameCfg)); - FilterDefinition findFilter = Builders.Filter.Eq("name_id", (string)description["name_id"]); - List> update = new(); - - update.Add(Builders.Update.Set("name_id", (string)description["name_id"])); - - foreach (var field in description) - { - if (field.Key == "_id") - continue; - update.Add(Builders.Update.Set(field.Key, (string)description[field.Key])); - } - - await collection.UpdateOneAsync(findFilter, Builders.Update.Combine(update)); - - return description; - } - catch (Exception ex) - { - client.Cluster.Dispose(); - _logger.Error($"Failed DeleteNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeBlackListRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeBlackListRepository.cs deleted file mode 100644 index ebe533c..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeBlackListRepository.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Modules.NlogManager; -using NLog; -using Npgsql; -using RepoDb; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class EpisodeBlackListRepository : IEpisodeBlackListRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task GetObjectBlackList(EpisodeBlacklist genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Url == genericQueue.Url && e.NameCfg == genericQueue.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectBlackList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetObjectBlackList"); - } - } - - public async Task> GetObjectsBlackList() - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAllAsync(); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectsBlackList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetObjectsBlackList"); - } - } - - public async Task PutObjectBlackList(EpisodeBlacklist genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - try - { - rs = await connection.InsertAsync(genericQueue); - } - catch (Exception ex) - { - _logger.Error($"Failed PutObjectBlackList, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return genericQueue; - else - throw new ApiNotFoundException("Not found PutObjectBlackList"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeQueueRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeQueueRepository.cs deleted file mode 100644 index 2df7412..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeQueueRepository.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Domain.Models; -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Modules.NlogManager; -using NLog; -using Npgsql; -using RepoDb; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class EpisodeQueueRepository : IEpisodeQueueRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task DeleteObjectQueue(EpisodeQueue objectGeneral) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs; - try - { - rs = await connection.DeleteAsync(e => e.Url == objectGeneral.Url && e.NameCfg == objectGeneral.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed DeleteEpisodeQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - - if (rs > 0) - return rs; - else - throw new ApiNotFoundException("Not found DeleteEpisodeQueue"); - } - } - - public async Task GetObjectQueue(EpisodeQueue genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Url == genericQueue.Url && e.NameCfg == genericQueue.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed GetEpisodeQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetEpisodeQueue"); - } - } - - public async Task> GetObjectsQueue() - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAllAsync(); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectsQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetObjectsQueue"); - } - } - - public async Task PutObjectQueue(EpisodeQueue genericQueue) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - try - { - rs = await connection.InsertAsync(genericQueue); - } - catch (Exception ex) - { - _logger.Error($"Failed PutEpisodeQueue, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return genericQueue; - else - throw new ApiNotFoundException("Not found PutEpisodeQueue"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRegisterRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRegisterRepository.cs deleted file mode 100644 index 9a6aaa6..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRegisterRepository.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.Models; -using NLog; -using Npgsql; -using RepoDb; -using RepoDb.Enumerations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class EpisodeRegisterRepository : IEpisodeRegisterRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - //get all episodesRegisters - public async Task GetObjectRegisterByObjectId(string id) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.EpisodeId == id); - } - catch (Exception ex) - { - _logger.Error($"Failed GetEpisodeRegisterByEpisodeId, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetObjectsRegisterByObjectId"); - } - } - - //insert - public async Task> InsertObjectsRegisterAsync(List episodeRegister) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.InsertAllAsync(episodeRegister); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertEpisodeRegisterAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return episodeRegister; - else - throw new ApiNotFoundException("Not found InsertObjectRegisterAsync"); - } - } - - public async Task InsertObjectRegisterAsync(EpisodeRegister episodeRegister) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - - try - { - rs = await connection.InsertAsync(episodeRegister); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertEpisodeRegisterAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return episodeRegister; - else - throw new ApiNotFoundException("Not found InsertObjectRegisterAsync"); - } - } - - //update - public async Task UpdateObjectRegisterAsync(EpisodeRegister episodeRegister) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.UpdateAsync(episodeRegister, e => e.EpisodeId == episodeRegister.EpisodeId); - } - catch (Exception ex) - { - _logger.Error($"Failed UpdateEpisodeRegisterAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return episodeRegister; - else - throw new ApiNotFoundException("Not found UpdateObjectRegisterAsync"); - } - } - - public async Task> GetObjectsRegistersByListObjectId(List listEpisodes) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAsync(new QueryField("episodeid", Operation.In, listEpisodes.Select(e => e.ID))); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectsRegistersByListObjectId, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetObjectsRegistersByListObjectId"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRepository.cs deleted file mode 100644 index 1a6078d..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/EpisodeRepository.cs +++ /dev/null @@ -1,228 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.Models; -using NLog; -using Npgsql; -using RepoDb; -using RepoDb.Enumerations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class EpisodeRepository : IEpisodeRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task DeleteByNameAsync(string id) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.DeleteAsync(e => e.VideoId == id); - } - catch (Exception ex) - { - _logger.Error($"Failed DeleteByNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return rs; - else - throw new ApiNotFoundException("Not found DeleteByNameAsync"); - } - } - - //get episode by id - public async Task GetObjectByIDAsync(string id) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAsync(e => e.ID == id); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectByIDAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found GetObjectByIDAsync"); - } - } - - //get episodes by name - public async Task> GetObjectsByNameAsync(string name) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - - try - { - rs = await connection.QueryAsync(e => e.VideoId == name, orderBy: OrderField.Parse(new - { - numberepisodecurrent = Order.Ascending - })); - } - catch (Exception ex) - { - _logger.Error($"Failed GetObjectsByNameAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs; - else - throw new ApiNotFoundException("Not found GetObjectsByNameAsync"); - } - } - - //insert episode - public async Task InsertObjectAsync(Episode episode) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - - try - { - rs = await connection.InsertAsync(episode); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertObjectAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return episode; - else - throw new ApiNotFoundException("Not found InsertObjectAsync"); - } - } - - public async Task> InsertObjectsAsync(List episodes) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.InsertAllAsync(episodes); - } - catch (Exception ex) - { - _logger.Error($"Failed InsertObjectsAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return episodes; - else - throw new ApiNotFoundException("Not found InsertObjectsAsync"); - } - } - - //reset StatusDownlod to null - public async Task ResetStatusDownloadObjectByIdAsync(Episode episode) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - episode.PercentualDownload = 0; - episode.StateDownload = null; - - try - { - - rs = await connection.UpdateAsync(episode, e => e.StateDownload != "completed" && e.ID == episode.ID); - - } - catch (Exception ex) - { - _logger.Error($"Failed ResetStatusDownloadObjectByIdAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return episode; - else - throw new ApiNotFoundException("Not found ResetStatusDownloadObjectByIdAsync"); - } - } - - public async Task> ResetStatusDownloadObjectsByIdAsync(List episodes) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - var episodesUpdate = episodes.Where(e => e.StateDownload != "completed").ToList(); - episodesUpdate.ForEach((e) => - { - e.PercentualDownload = 0; - e.StateDownload = null; - }); - - rs = await connection.UpdateAllAsync(episodesUpdate); - } - catch (Exception ex) - { - _logger.Error($"Failed ResetStatusDownloadObjectsByIdAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return episodes; - else - throw new ApiNotFoundException("Not found ResetStatusDownloadObjectsByIdAsync"); - } - } - - //update percentualDownload - public async Task UpdateStateDownloadAsync(Episode episode) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.UpdateAsync(episode); - } - catch (Exception ex) - { - _logger.Error($"Failed UpdateStateDownloadAsync, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return episode; - else - throw new ApiNotFoundException("Not found UpdateStateDownloadAsync"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressChapterRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressChapterRepository.cs deleted file mode 100644 index ca40eaa..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressChapterRepository.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.Models; -using NLog; -using Npgsql; -using RepoDb; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class ProgressChapterRepository : IProgressChapterRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task CheckProgress(string name, string username, string nameCfg) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Name == name && e.Username == username && e.NameCfg == nameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed CheckProgress, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found CheckProgress"); - } - } - - public async Task CreateProgress(ProgressChapter progress) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - - try - { - rs = await connection.InsertAsync(progress); - } - catch (Exception ex) - { - _logger.Error($"Failed CreateProgress, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return progress; - else - throw new ApiNotFoundException("Not found CreateProgress"); - } - } - - public async Task UpdateProgress(ProgressChapter progress) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.UpdateAsync(progress, e => e.Name == progress.Name && e.Username == progress.Username && e.NameCfg == progress.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed UpdateProgress, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return progress; - else - throw new ApiNotFoundException("Not found UpdateProgress"); - } - } - } -} diff --git a/src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressEpisodeRepository.cs b/src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressEpisodeRepository.cs deleted file mode 100644 index 38bf142..0000000 --- a/src/Cesxhin.AnimeManga.Persistence/Repositories/ProgressEpisodeRepository.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Cesxhin.AnimeManga.Application.Interfaces.Repositories; -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.Models; -using NLog; -using Npgsql; -using RepoDb; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Persistence.Repositories -{ - public class ProgressEpisodeRepository : IProgressEpisodeRepository - { - //log - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //env - readonly string _connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION"); - - public async Task CheckProgress(string name, string username, string nameCfg) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - IEnumerable rs; - try - { - rs = await connection.QueryAsync(e => e.Name == name && e.Username == username && e.NameCfg == nameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed CheckProgress, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && rs.Any()) - return rs.First(); - else - throw new ApiNotFoundException("Not found CheckProgress"); - } - } - - public async Task CreateProgress(ProgressEpisode progress) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - object rs = null; - - try - { - rs = await connection.InsertAsync(progress); - } - catch (Exception ex) - { - _logger.Error($"Failed CreateProgress, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs != null && !string.IsNullOrEmpty(rs.ToString())) - return progress; - else - throw new ApiNotFoundException("Not found CreateProgress"); - } - } - - public async Task UpdateProgress(ProgressEpisode progress) - { - using (var connection = new NpgsqlConnection(_connectionString)) - { - int rs = 0; - - try - { - rs = await connection.UpdateAsync(progress, e => e.Name == progress.Name && e.Username == progress.Username && e.NameCfg == progress.NameCfg); - } - catch (Exception ex) - { - _logger.Error($"Failed UpdateProgress, details error: {ex.Message}"); - throw new ApiGenericException(ex.Message); - } - - if (rs > 0) - return progress; - else - throw new ApiNotFoundException("Not found UpdateProgress"); - } - } - } -} diff --git a/src_refactory/applications/interfaces/repositories/IAccountRepository.ts b/src/applications/interfaces/repositories/IAccountRepository.ts similarity index 100% rename from src_refactory/applications/interfaces/repositories/IAccountRepository.ts rename to src/applications/interfaces/repositories/IAccountRepository.ts diff --git a/src_refactory/applications/interfaces/repositories/IRequestRepository.ts b/src/applications/interfaces/repositories/IRequestRepository.ts similarity index 100% rename from src_refactory/applications/interfaces/repositories/IRequestRepository.ts rename to src/applications/interfaces/repositories/IRequestRepository.ts diff --git a/src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts b/src/applications/interfaces/repositories/generic/IConnectionRepository.ts similarity index 100% rename from src_refactory/applications/interfaces/repositories/generic/IConnectionRepository.ts rename to src/applications/interfaces/repositories/generic/IConnectionRepository.ts diff --git a/src_refactory/applications/interfaces/services/IAccountService.ts b/src/applications/interfaces/services/IAccountService.ts similarity index 100% rename from src_refactory/applications/interfaces/services/IAccountService.ts rename to src/applications/interfaces/services/IAccountService.ts diff --git a/src_refactory/applications/interfaces/services/IRequestService.ts b/src/applications/interfaces/services/IRequestService.ts similarity index 100% rename from src_refactory/applications/interfaces/services/IRequestService.ts rename to src/applications/interfaces/services/IRequestService.ts diff --git a/src_refactory/applications/repositories/AccountRepository.ts b/src/applications/repositories/AccountRepository.ts similarity index 100% rename from src_refactory/applications/repositories/AccountRepository.ts rename to src/applications/repositories/AccountRepository.ts diff --git a/src_refactory/applications/repositories/RequestRepository.ts b/src/applications/repositories/RequestRepository.ts similarity index 100% rename from src_refactory/applications/repositories/RequestRepository.ts rename to src/applications/repositories/RequestRepository.ts diff --git a/src_refactory/applications/services/AccountService.ts b/src/applications/services/AccountService.ts similarity index 100% rename from src_refactory/applications/services/AccountService.ts rename to src/applications/services/AccountService.ts diff --git a/src_refactory/applications/services/RequestService.ts b/src/applications/services/RequestService.ts similarity index 100% rename from src_refactory/applications/services/RequestService.ts rename to src/applications/services/RequestService.ts diff --git a/src/controllers/accountController/createRoute.ts b/src/controllers/accountController/createRoute.ts new file mode 100644 index 0000000..c263c11 --- /dev/null +++ b/src/controllers/accountController/createRoute.ts @@ -0,0 +1,21 @@ +import { PATH_BASE_CONTROLLER, schemaCreateAccount, schemaReturnAccount } from "../../schemas/accountSchema"; +import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import fastify from "../../server/fastify"; + +const accountService = new AccountService(); + +fastify.post(`${PATH_BASE_CONTROLLER}/create`, { + schema: { + tags: ["account"], + summary: "Create new account", + body: schemaCreateAccount, + response: { + 200: schemaReturnAccount, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 401: { $ref: SCHEMA_BAD_REQUEST } + } + } +}, async (request, replay) => replay.status(200).send(await accountService.createAccount(request.body))); \ No newline at end of file diff --git a/src/controllers/accountController/deleteRoute.ts b/src/controllers/accountController/deleteRoute.ts new file mode 100644 index 0000000..76107ac --- /dev/null +++ b/src/controllers/accountController/deleteRoute.ts @@ -0,0 +1,27 @@ +import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, schemaReturnVoid } from "../../schemas/generic/genericSchema"; +import { PATH_BASE_CONTROLLER, schemaQueryUsernameAccount} from "../../schemas/accountSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import fastify from "../../server/fastify"; + +const accountService = new AccountService(); + +fastify.delete(`${PATH_BASE_CONTROLLER}/delete`, { + schema: { + tags: ["account"], + summary: "Delete account", + querystring: schemaQueryUsernameAccount, + response: { + 200: schemaReturnVoid, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 404: { $ref: SCHEMA_NOT_FOUND } + } + } +}, async (request, replay) => { + const {username} = request.query; + + await accountService.deleteAccount(username); + + replay.status(200).send({ response: "ok" }); +}); \ No newline at end of file diff --git a/src/controllers/accountController/findRoute.ts b/src/controllers/accountController/findRoute.ts new file mode 100644 index 0000000..a9d29d3 --- /dev/null +++ b/src/controllers/accountController/findRoute.ts @@ -0,0 +1,25 @@ +import { PATH_BASE_CONTROLLER, schemaQueryUsernameAccount, schemaReturnAccount } from "../../schemas/accountSchema"; +import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import fastify from "../../server/fastify"; + +const accountService = new AccountService(); + +fastify.get(`${PATH_BASE_CONTROLLER}/find`, { + schema: { + tags: ["account"], + summary: "Find account", + querystring: schemaQueryUsernameAccount, + response: { + 200: schemaReturnAccount, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 404: { $ref: SCHEMA_NOT_FOUND } + } + } +}, async (request, replay) => { + const {username} = request.query; + + replay.status(200).send(await accountService.findFromUsername(username)); +}); \ No newline at end of file diff --git a/src/controllers/accountController/updateRoute.ts b/src/controllers/accountController/updateRoute.ts new file mode 100644 index 0000000..9e167e9 --- /dev/null +++ b/src/controllers/accountController/updateRoute.ts @@ -0,0 +1,27 @@ +import { PATH_BASE_CONTROLLER, schemaQueryUsernameAccount, schemaUpdateAccount, schemaReturnAccount } from "../../schemas/accountSchema"; +import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; + +import { AccountService } from "../../applications/services/AccountService"; + +import fastify from "../../server/fastify"; + +const accountService = new AccountService(); + +fastify.put(`${PATH_BASE_CONTROLLER}/update`, { + schema: { + tags: ["account"], + summary: "Update values of account", + querystring: schemaQueryUsernameAccount, + body: schemaUpdateAccount, + response: { + 200: schemaReturnAccount, + 500: { $ref: SCHEMA_INTERNAL_SERVER }, + 404: { $ref: SCHEMA_NOT_FOUND } + } + } +}, async (request, replay) => { + const {username} = request.query; + const account = request.body; + + replay.status(200).send(await accountService.updateAccount(username, account)); +}); \ No newline at end of file diff --git a/src/controllers/requestController/actionRoute.ts b/src/controllers/requestController/actionRoute.ts new file mode 100644 index 0000000..515b143 --- /dev/null +++ b/src/controllers/requestController/actionRoute.ts @@ -0,0 +1,26 @@ +import { RequestService } from "../../applications/services/RequestService"; + +import { PATH_BASE_CONTROLLER, schemaActionRequest } from "../../schemas/requestSchema"; +import { SCHEMA_INTERNAL_SERVER, schemaReturnVoid } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; + +const requestService = new RequestService(); + +fastify.post(`${PATH_BASE_CONTROLLER}/action`, { + schema: { + tags: ["request"], + summary: "Choose accept or refuse request friend", + querystring: schemaActionRequest, + response: { + 200: schemaReturnVoid, + 500: { $ref: SCHEMA_INTERNAL_SERVER } + } + } +}, async (request, replay) => { + const {accept, request_from, request_to} = request.query; + + await requestService.action(request_from, request_to, accept); + + replay.status(200).send({ response: "ok" }); +}); \ No newline at end of file diff --git a/src_refactory/controllers/requestController/createRoute.ts b/src/controllers/requestController/createRoute.ts similarity index 51% rename from src_refactory/controllers/requestController/createRoute.ts rename to src/controllers/requestController/createRoute.ts index f10511e..50ebf7e 100644 --- a/src_refactory/controllers/requestController/createRoute.ts +++ b/src/controllers/requestController/createRoute.ts @@ -1,30 +1,26 @@ -import { RouteShorthandOptions } from "fastify"; - import { RequestService } from "../../applications/services/RequestService"; -import { PATH_BASE_CONTROLLER, SCHEMA_CREATE_REQUEST, staticCreateRequest } from "../../schemas/requestSchema"; -import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; +import { PATH_BASE_CONTROLLER, schemaCreateRequest } from "../../schemas/requestSchema"; +import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, schemaReturnVoid } from "../../schemas/generic/genericSchema"; import fastify from "../../server/fastify"; const requestService = new RequestService(); -const options: RouteShorthandOptions = { +fastify.post(`${PATH_BASE_CONTROLLER}/create`, { schema: { tags: ["request"], summary: "Create request friend", - body: { $ref: SCHEMA_CREATE_REQUEST }, + body: schemaCreateRequest, response: { - 200: { $ref: SCHEMA_RETURN_VOID }, + 200: schemaReturnVoid, 401: { $ref: SCHEMA_BAD_REQUEST }, 404: { $ref: SCHEMA_NOT_FOUND }, 500: { $ref: SCHEMA_INTERNAL_SERVER } } } -}; - -fastify.post<{Body: staticCreateRequest}>(`${PATH_BASE_CONTROLLER}/create`, options, async (request) => { +}, async (request, replay) => { await requestService.create(request.body); - return { response: "ok" }; + replay.status(200).send({ response: "ok" }); }); \ No newline at end of file diff --git a/src_refactory/controllers/requestController/listRoute.ts b/src/controllers/requestController/listRoute.ts similarity index 50% rename from src_refactory/controllers/requestController/listRoute.ts rename to src/controllers/requestController/listRoute.ts index 168c3ea..d520bd5 100644 --- a/src_refactory/controllers/requestController/listRoute.ts +++ b/src/controllers/requestController/listRoute.ts @@ -2,27 +2,25 @@ import { RouteShorthandOptions } from "fastify"; import { RequestService } from "../../applications/services/RequestService"; -import { PATH_BASE_CONTROLLER, SCHEMA_QUERY_PAGINATED_REQUEST, SCHEMA_RETURN_PAGINATED_REQUEST, staticQueryPaginatedRequest } from "../../schemas/requestSchema"; +import { PATH_BASE_CONTROLLER, schemaQueryPaginatedRequest, schemaReturnPaginatedRequest } from "../../schemas/requestSchema"; import { SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; import fastify from "../../server/fastify"; const requestService = new RequestService(); -const options: RouteShorthandOptions = { +fastify.get(`${PATH_BASE_CONTROLLER}/list`, { schema: { tags: ["request"], summary: "List request for accept or reject", - querystring: { $ref: SCHEMA_QUERY_PAGINATED_REQUEST }, + querystring: schemaQueryPaginatedRequest, response: { - 200: { $ref: SCHEMA_RETURN_PAGINATED_REQUEST }, + 200: schemaReturnPaginatedRequest, 500: { $ref: SCHEMA_INTERNAL_SERVER } } } -}; - -fastify.get<{Querystring: staticQueryPaginatedRequest}>(`${PATH_BASE_CONTROLLER}/list`, options, async (request) => { +}, async (request, replay) => { const {length, request_from, skip} = request.query; - return await requestService.listPaginated(request_from, skip, length); + replay.status(200).send(await requestService.listPaginated(request_from, skip, length)); }); \ No newline at end of file diff --git a/src_refactory/domain/interfaces/DTOs/IAccountDTO.ts b/src/domain/interfaces/DTOs/IAccountDTO.ts similarity index 100% rename from src_refactory/domain/interfaces/DTOs/IAccountDTO.ts rename to src/domain/interfaces/DTOs/IAccountDTO.ts diff --git a/src_refactory/domain/interfaces/DTOs/IRequestDTO.ts b/src/domain/interfaces/DTOs/IRequestDTO.ts similarity index 100% rename from src_refactory/domain/interfaces/DTOs/IRequestDTO.ts rename to src/domain/interfaces/DTOs/IRequestDTO.ts diff --git a/src_refactory/domain/interfaces/models/IAccount.ts b/src/domain/interfaces/models/IAccount.ts similarity index 100% rename from src_refactory/domain/interfaces/models/IAccount.ts rename to src/domain/interfaces/models/IAccount.ts diff --git a/src_refactory/domain/interfaces/models/IRequest.ts b/src/domain/interfaces/models/IRequest.ts similarity index 100% rename from src_refactory/domain/interfaces/models/IRequest.ts rename to src/domain/interfaces/models/IRequest.ts diff --git a/src_refactory/domain/models/Account.ts b/src/domain/models/Account.ts similarity index 100% rename from src_refactory/domain/models/Account.ts rename to src/domain/models/Account.ts diff --git a/src_refactory/domain/models/Request.ts b/src/domain/models/Request.ts similarity index 100% rename from src_refactory/domain/models/Request.ts rename to src/domain/models/Request.ts diff --git a/src_refactory/eslint.config.js b/src/eslint.config.js similarity index 100% rename from src_refactory/eslint.config.js rename to src/eslint.config.js diff --git a/src_refactory/index.ts b/src/index.ts similarity index 100% rename from src_refactory/index.ts rename to src/index.ts diff --git a/src_refactory/modules/api.ts b/src/modules/api.ts similarity index 100% rename from src_refactory/modules/api.ts rename to src/modules/api.ts diff --git a/src/modules/logger.ts b/src/modules/logger.ts new file mode 100644 index 0000000..9a99a24 --- /dev/null +++ b/src/modules/logger.ts @@ -0,0 +1,64 @@ +import chalk from "chalk"; +import {DateTime} from "luxon"; + +class Logger { + nameService: string | null = null; + + constructor(nameService: string){ + this.nameService = nameService.toUpperCase(); + } + + debug(...args: Array){ + this.#baseLog("debug", ...args); + } + + info(...args: Array){ + this.#baseLog("info", ...args); + } + + warn(...args: Array){ + this.#baseLog("warning", ...args); + } + + error(...args: Array){ + this.#baseLog("error", ...args); + } + + fatal(...args: Array){ + this.#baseLog("fatal", ...args); + } + + #baseLog(type: "debug" | "info" | "warning" | "error" | "fatal", ...args: Array){ + let message = `[${DateTime.now().toFormat("dd-MM-yyyy hh:mm:ssZZ")}] [${type.toUpperCase()}] [${this.nameService}]`; + + args = args.map((message) => { + if (message instanceof Error){ + return message.stack; + } else { + return message; + } + }); + + switch (type){ + case "debug": + message = chalk.gray(message, ...args); + break; + case "info": + message = chalk.blue(message, ...args); + break; + case "warning": + message = chalk.yellow(message, ...args); + break; + case "error": + message = chalk.red(message, ...args); + break; + case "fatal": + message = chalk.redBright(message, ...args); + break; + } + + console.log(message); + } +} + +export default Logger; \ No newline at end of file diff --git a/src_refactory/package.json b/src/package.json similarity index 73% rename from src_refactory/package.json rename to src/package.json index 21dc396..6d2a47d 100644 --- a/src_refactory/package.json +++ b/src/package.json @@ -6,7 +6,6 @@ "scripts": { "start": "npx tsx index.ts", "clear": "rm -rf node_modules package-lock.json", - "create_link_references": "cd ../references/src_refactory && ln -s ../../src_refactory/node_modules && ln -s ../../src_refactory/package.json && ln -s ../../src_refactory/tsconfig.json", "eslint": "npx eslint .", "eslint-fix": "npx eslint --fix ." }, @@ -15,8 +14,9 @@ "license": "MIT", "description": "", "dependencies": { - "@fastify/swagger": "^8.15.0", - "@fastify/swagger-ui": "4.1.0", + "@fastify/swagger": "^9.0.0", + "@fastify/swagger-ui": "^5.0.1", + "@fastify/type-provider-typebox": "^5.0.0", "@sinclair/typebox": "^0.33.7", "@stylistic/eslint-plugin-js": "^2.8.0", "@types/async": "^3.2.24", @@ -27,16 +27,12 @@ "crypto-js": "^4.2.0", "dotenv": "^16.4.5", "eslint-plugin-check-file": "^2.8.0", - "fastify": "^4.28.1", - "joi": "^17.13.3", + "fastify": "^5.0.0", "lodash": "^4.17.21", "luxon": "^3.5.0", "pg": "^8.12.0", - "reflect-metadata": "^0.2.2", "typeorm": "^0.3.20", - "typescript": "^5.5.4" - }, - "devDependencies": { + "typescript": "^5.5.4", "@eslint/js": "^9.11.0", "@types/lodash": "^4.17.7", "@types/luxon": "^3.4.2", diff --git a/src/references/Cesxhin.AnimeManga.Domain/Cesxhin.AnimeManga.Domain.csproj b/src/references/Cesxhin.AnimeManga.Domain/Cesxhin.AnimeManga.Domain.csproj deleted file mode 100644 index 9b3a464..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Cesxhin.AnimeManga.Domain.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - net5.0 - - - - - - - - diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/AuthDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/AuthDTO.cs deleted file mode 100644 index ecfe7ea..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/AuthDTO.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class AuthDTO - { - public string Username { get; set; } - public int Role { get; set; } - - //convert Auth to AuthDTO - public static AuthDTO AuthToAuthDTO(Auth auth) - { - return new AuthDTO - { - Username = auth.Username, - Role = auth.Role - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/AuthLoginDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/AuthLoginDTO.cs deleted file mode 100644 index 1bb93a0..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/AuthLoginDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class AuthLoginDTO - { - public string Username { get; set; } - public string Password { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterDTO.cs deleted file mode 100644 index f504a50..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterDTO.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class ChapterDTO - { - public string ID { get; set; } - public string NameManga { get; set; } - public float CurrentVolume { get; set; } - public float CurrentChapter { get; set; } - public int NumberMaxImage { get; set; } - public string UrlPage { get; set; } - public string StateDownload { get; set; } - public int PercentualDownload { get; set; } - public string NameCfg { get; set; } - - //convert Chapter to ChapterDTO - public static ChapterDTO ChapterToChapterDTO(Chapter chapter) - { - return new ChapterDTO - { - ID = chapter.ID, - CurrentChapter = chapter.CurrentChapter, - UrlPage = chapter.UrlPage, - CurrentVolume = chapter.CurrentVolume, - NameManga = chapter.NameManga, - PercentualDownload = chapter.PercentualDownload, - StateDownload = chapter.StateDownload, - NumberMaxImage = chapter.NumberMaxImage, - NameCfg = chapter.NameCfg - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterRegisterDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterRegisterDTO.cs deleted file mode 100644 index 63ef493..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/ChapterRegisterDTO.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class ChapterRegisterDTO - { - public string ChapterId { get; set; } - public string[] ChapterPath { get; set; } - public string[] ChapterHash { get; set; } - - //convert ChapterRegister to ChapterRegisterDTO - public static ChapterRegisterDTO ChapterRegisterToChapterRegisterDTO(ChapterRegister chapter) - { - return new ChapterRegisterDTO - { - ChapterId = chapter.ChapterId, - ChapterPath = chapter.ChapterPath, - ChapterHash = chapter.ChapterHash - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/ConversionDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/ConversionDTO.cs deleted file mode 100644 index 9cd7481..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/ConversionDTO.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class ConversionDTO - { - public string ID { get; set; } - public List Paths { get; set; } - public string FilePath { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/DownloadDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/DownloadDTO.cs deleted file mode 100644 index a32e709..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/DownloadDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class DownloadDTO - { - public string Url { get; set; } - public string nameCfg { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeDTO.cs deleted file mode 100644 index ad7cba5..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeDTO.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class EpisodeDTO - { - public string ID { get; set; } - public string VideoId { get; set; } - public string UrlVideo { get; set; } - public int NumberEpisodeCurrent { get; set; } - public int NumberSeasonCurrent { get; set; } - public string StateDownload { get; set; } - public int PercentualDownload { get; set; } - - /* - Download playlist: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/playlist.m3u8 - Select Resolution for download source: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/360p/playlist_360p.m3u8 - Download source: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/360p/360p-000.ts - */ - - //alternative source - public string BaseUrl { get; set; } - public string Playlist { get; set; } - public string Resolution { get; set; } - public string PlaylistSources { get; set; } - public int startNumberBuffer { get; set; } = 0; - public int endNumberBuffer { get; set; } - public string nameCfg { get; set; } - - //convert Episode to EpisodeDTO - public static EpisodeDTO EpisodeToEpisodeDTO(Episode episode) - { - return new EpisodeDTO - { - ID = episode.ID, - VideoId = episode.VideoId, - UrlVideo = episode.UrlVideo, - NumberEpisodeCurrent = episode.NumberEpisodeCurrent, - NumberSeasonCurrent = episode.NumberSeasonCurrent, - StateDownload = episode.StateDownload, - PercentualDownload = episode.PercentualDownload, - BaseUrl = episode.BaseUrl, - Playlist = episode.Playlist, - Resolution = episode.Resolution, - PlaylistSources = episode.PlaylistSources, - startNumberBuffer = episode.startNumberBuffer, - endNumberBuffer = episode.endNumberBuffer, - nameCfg = episode.nameCfg - - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeRegisterDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeRegisterDTO.cs deleted file mode 100644 index f84417f..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/EpisodeRegisterDTO.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class EpisodeRegisterDTO - { - public string EpisodeId { get; set; } - public string EpisodePath { get; set; } - public string EpisodeHash { get; set; } - - //convert EpisodeRegister to EpisodeRegisterDTO - public static EpisodeRegisterDTO EpisodeRegisterToEpisodeRegisterDTO(EpisodeRegister anime) - { - return new EpisodeRegisterDTO - { - EpisodeId = anime.EpisodeId, - EpisodePath = anime.EpisodePath, - EpisodeHash = anime.EpisodeHash - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBlackListDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBlackListDTO.cs deleted file mode 100644 index 207000e..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBlackListDTO.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class GenericBlackListDTO - { - public string Name { get; set; } - public string Url { get; set; } - public string NameCfg { get; set; } - - //convert EpisodeBlackList to GenericBlackListDTO - public static GenericBlackListDTO EpisodeBlackListToGenericBlackListDTO(EpisodeBlacklist auth) - { - return new GenericBlackListDTO - { - Name = auth.Name, - Url = auth.Url, - NameCfg = auth.NameCfg, - }; - } - - //convert ChapterBlackList to GenericBlackListDTO - public static GenericBlackListDTO ChapterBlackListToGenericBlackListDTO(ChapterBlacklist auth) - { - return new GenericBlackListDTO - { - Name = auth.Name, - Url = auth.Url, - NameCfg = auth.NameCfg, - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBookDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBookDTO.cs deleted file mode 100644 index 5ec6592..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericBookDTO.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class GenericBookDTO - { - //Manga - public string Book { get; set; } - public List Chapters { get; set; } - public List ChapterRegister { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericQueueDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericQueueDTO.cs deleted file mode 100644 index c166b8e..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericQueueDTO.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; -using System; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class GenericQueueDTO - { - public string Name { get; set; } - public string Url { get; set; } - public string NameCfg { get; set; } - public long TimeRequest { get; set; } = ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeMilliseconds(); - - //convert ChapterQueue to GenericQueueDTO - public static GenericQueueDTO ChapterQueueToGenericQueueDTO(ChapterQueue queue) - { - return new GenericQueueDTO - { - Name = queue.Name, - Url = queue.Url, - NameCfg = queue.NameCfg, - TimeRequest = queue.TimeRequest - }; - } - - //convert EpisodeQueue to GenericQueueDTO - public static GenericQueueDTO EpisodeQueueToGenericQueueDTO(EpisodeQueue queue) - { - return new GenericQueueDTO - { - Name = queue.Name, - Url = queue.Url, - NameCfg = queue.NameCfg, - TimeRequest = queue.TimeRequest - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericUrlDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericUrlDTO.cs deleted file mode 100644 index c6729db..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericUrlDTO.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class GenericUrlDTO - { - public string Name { get; set; } - public string UrlPageDownload { get; set; } - public string Image { get; set; } - public string Type { get; set; } - public bool Exists { get; set; } = false; - - //convert GenericUrl to GenericUrlDTO - public static GenericUrlDTO GenericUrlToGenericUrlDTO(GenericUrl anime) - { - return new GenericUrlDTO - { - Name = anime.Name, - UrlPageDownload = anime.Url, - Image = anime.UrlImage, - Type = anime.TypeView - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericVideoDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericVideoDTO.cs deleted file mode 100644 index 62749ed..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/GenericVideoDTO.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class GenericVideoDTO - { - //Video - public string Video { get; set; } - public List Episodes { get; set; } - public List EpisodesRegister { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyAnimeDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyAnimeDTO.cs deleted file mode 100644 index 00a4e49..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyAnimeDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class NotifyAnimeDTO - { - public string Message { get; set; } - public string Image { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyMangaDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyMangaDTO.cs deleted file mode 100644 index d874b40..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyMangaDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class NotifyMangaDTO - { - public string Message { get; set; } - public string Image { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestAnimeDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestAnimeDTO.cs deleted file mode 100644 index 79129df..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestAnimeDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class NotifyRequestAnimeDTO - { - public string Message { get; set; } - public string Image { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestMangaDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestMangaDTO.cs deleted file mode 100644 index 5645da1..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/NotifyRequestMangaDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class NotifyRequestMangaDTO - { - public string Message { get; set; } - public string Image { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressChapterDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressChapterDTO.cs deleted file mode 100644 index 73c866b..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressChapterDTO.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class ProgressChapterDTO - { - public string ID { get; set; } - public string Username { get; set; } - public string Name { get; set; } - public string NameCfg { get; set; } - public string NameChapter { get; set; } - public int Page { get; set; } - - //convert ProgressEpisode to ProgressEpisodeDTO - public static ProgressChapterDTO ProgressChapterToProgressChapterDTO(ProgressChapter progress) - { - return new ProgressChapterDTO - { - ID = progress.ID, - Name = progress.Name, - Page = progress.Page, - Username = progress.Username, - NameChapter = progress.NameChapter, - NameCfg = progress.NameCfg, - }; - } - } -} \ No newline at end of file diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressEpisodeDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressEpisodeDTO.cs deleted file mode 100644 index 3137e56..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/ProgressEpisodeDTO.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class ProgressEpisodeDTO - { - public string ID { get; set; } - public string Username { get; set; } - public string Name { get; set; } - public string NameCfg { get; set; } - public string NameEpisode { get; set; } - public int Hours { get; set; } - public int Minutes { get; set; } - public int Seconds { get; set; } - - //convert ProgressChapter to ProgressChapterDTO - public static ProgressEpisodeDTO ProgressEpisodeToProgressEpisodeDTO(ProgressEpisode progress) - { - return new ProgressEpisodeDTO - { - ID = progress.ID, - Username = progress.Username, - Name = progress.Name, - Hours = progress.Hours, - Minutes = progress.Minutes, - Seconds = progress.Seconds, - NameEpisode = progress.NameEpisode, - NameCfg = progress.NameCfg, - }; - } - } -} \ No newline at end of file diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/ProxyDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/ProxyDTO.cs deleted file mode 100644 index e15bfc5..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/ProxyDTO.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class ProxyDTO - { - public string Action { get; set; } = "restart"; - public string Endpoint { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/DTO/WatchListDTO.cs b/src/references/Cesxhin.AnimeManga.Domain/DTO/WatchListDTO.cs deleted file mode 100644 index 127c33c..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/DTO/WatchListDTO.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Cesxhin.AnimeManga.Domain.Models; - -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class WatchListDTO - { - public string Name { get; set; } - public string Username { get; set; } - public string NameCfg { get; set; } - - //convert Auth to AuthDTO - public static WatchListDTO WatchListToWatchListDTO(WatchList watchList) - { - return new WatchListDTO - { - Name = watchList.Name, - Username = watchList.Username, - NameCfg = watchList.NameCfg - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/Auth.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/Auth.cs deleted file mode 100644 index 9bb9518..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/Auth.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("account")] - public class Auth - { - [Primary] - [Map("username")] - public string Username { get; set; } - - [Map("password")] - public string Password { get; set; } - - [Map("role")] - public int Role { get; set; } - - //convert AuthDTO to Auth - public static Auth AuthDTOToAuth(AuthDTO auth) - { - return new Auth - { - Username = auth.Username, - Role = auth.Role, - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/Chapter.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/Chapter.cs deleted file mode 100644 index f6e19b9..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/Chapter.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("chapter")] - public class Chapter - { - [Primary] - [Map("id")] - public string ID { get; set; } - - [Map("namemanga")] - public string NameManga { get; set; } - - [Map("currentvolume")] - public float CurrentVolume { get; set; } - - [Map("currentchapter")] - public float CurrentChapter { get; set; } - - [Map("numbermaximage")] - public int NumberMaxImage { get; set; } - - [Map("urlpage")] - public string UrlPage { get; set; } - - [Map("statedownload")] - public string StateDownload { get; set; } - - [Map("percentualdownload")] - public int PercentualDownload { get; set; } - - [Map("namecfg")] - public string NameCfg { get; set; } - - //convert ChapterDTO to Chapter - public static Chapter ChapterDTOToChapter(ChapterDTO chapter) - { - return new Chapter - { - ID = chapter.ID, - CurrentChapter = chapter.CurrentChapter, - UrlPage = chapter.UrlPage, - CurrentVolume = chapter.CurrentVolume, - NameManga = chapter.NameManga, - StateDownload = chapter.StateDownload, - PercentualDownload = chapter.PercentualDownload, - NumberMaxImage = chapter.NumberMaxImage, - NameCfg = chapter.NameCfg - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterBlacklist.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterBlacklist.cs deleted file mode 100644 index 7fc4f8b..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterBlacklist.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("chapterblacklist")] - public class ChapterBlacklist - { - [Primary] - [Map("namemanga")] - public string Name { get; set; } - - [Map("url")] - public string Url { get; set; } - - [Primary] - [Map("namecfg")] - public string NameCfg { get; set; } - - //convert GenericBlackListDTO to ChapterBlacklist - public static ChapterBlacklist GenericQueueDTOToChapterBlacklist(GenericBlackListDTO blackList) - { - return new ChapterBlacklist - { - Url = blackList.Url, - NameCfg = blackList.NameCfg, - Name = blackList.Name - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterQueue.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterQueue.cs deleted file mode 100644 index 031a34b..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterQueue.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("chapterqueue")] - public class ChapterQueue - { - [Primary] - [Map("namemanga")] - public string Name { get; set; } - - [Primary] - [Map("url")] - public string Url { get; set; } - - [Primary] - [Map("namecfg")] - public string NameCfg { get; set; } - - [Map("timerequest")] - public long TimeRequest { get; set; } - - - //convert GenericQueueDTO to ChapterQueue - public static ChapterQueue GenericQueueDTOToChapterQueue(GenericQueueDTO queue) - { - return new ChapterQueue - { - Name = queue.Name, - Url = queue.Url, - NameCfg = queue.NameCfg, - TimeRequest = queue.TimeRequest - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterRegister.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterRegister.cs deleted file mode 100644 index d54cfcf..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/ChapterRegister.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("chapterregister")] - public class ChapterRegister - { - [Primary] - [Map("chapterid")] - public string ChapterId { get; set; } - - [Map("chapterpath")] - public string[] ChapterPath { get; set; } - - [Map("chapterhash")] - public string[] ChapterHash { get; set; } - - //convert ChapterRegisterDTO to ChapterRegister - public static ChapterRegister ChapterRegisterDTOToChapterRegister(ChapterRegisterDTO anime) - { - return new ChapterRegister - { - ChapterId = anime.ChapterId, - ChapterPath = anime.ChapterPath, - ChapterHash = anime.ChapterHash - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/Episode.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/Episode.cs deleted file mode 100644 index 7733ed6..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/Episode.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("episode")] - public class Episode - { - [Primary] - [Map("id")] - public string ID { get; set; } - - [Map("videoid")] - public string VideoId { get; set; } - - [Map("urlvideo")] - public string UrlVideo { get; set; } - - [Map("numberepisodecurrent")] - public int NumberEpisodeCurrent { get; set; } - - [Map("numberseasoncurrent")] - public int NumberSeasonCurrent { get; set; } - - [Map("statedownload")] - public string StateDownload { get; set; } - - [Map("percentualdownload")] - public int PercentualDownload { get; set; } - - /* - Download playlist: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/playlist.m3u8 - Select Resolution for download source: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/360p/playlist_360p.m3u8 - Download source: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/360p/360p-000.ts - */ - - //alternative source - [Map("baseurl")] - public string BaseUrl { get; set; } - - [Map("playlist")] - public string Playlist { get; set; } - - [Map("resolution")] - public string Resolution { get; set; } - - [Map("playlistsources")] - public string PlaylistSources { get; set; } - - [Map("startnumberframe")] - public int startNumberBuffer { get; set; } = 0; - - [Map("endnumberframe")] - public int endNumberBuffer { get; set; } - - [Map("namecfg")] - public string nameCfg { get; set; } - - //convert EpisodeDTO to Episode - public static Episode EpisodeDTOToEpisode(EpisodeDTO episode) - { - return new Episode - { - ID = episode.ID, - VideoId = episode.VideoId, - UrlVideo = episode.UrlVideo, - NumberEpisodeCurrent = episode.NumberEpisodeCurrent, - NumberSeasonCurrent = episode.NumberSeasonCurrent, - StateDownload = episode.StateDownload, - PercentualDownload = episode.PercentualDownload, - startNumberBuffer = episode.startNumberBuffer, - endNumberBuffer = episode.endNumberBuffer, - Resolution = episode.Resolution, - PlaylistSources = episode.PlaylistSources, - Playlist = episode.Playlist, - BaseUrl = episode.BaseUrl, - nameCfg = episode.nameCfg - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBlacklist.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBlacklist.cs deleted file mode 100644 index 2ac5c25..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBlacklist.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("episodeblacklist")] - public class EpisodeBlacklist - { - [Primary] - [Map("videoid")] - public string Name { get; set; } - - [Map("url")] - public string Url { get; set; } - - [Primary] - [Map("namecfg")] - public string NameCfg { get; set; } - - //convert GenericBlackListDTO to EpisodeBlacklist - public static EpisodeBlacklist GenericQueueDTOToEpisodeBlacklist(GenericBlackListDTO blackList) - { - return new EpisodeBlacklist - { - Url = blackList.Url, - NameCfg = blackList.NameCfg, - Name = blackList.Name - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBuffer.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBuffer.cs deleted file mode 100644 index 4af9f9b..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeBuffer.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.Models -{ - public class EpisodeBuffer - { - public int Id { get; set; } - public byte[] Data { get; set; } - - public string Path { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeQueue.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeQueue.cs deleted file mode 100644 index 9a25425..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeQueue.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("episodequeue")] - public class EpisodeQueue - { - [Primary] - [Map("videoid")] - public string Name { get; set; } - - [Primary] - [Map("url")] - public string Url { get; set; } - - [Primary] - [Map("namecfg")] - public string NameCfg { get; set; } - - [Map("timerequest")] - public long TimeRequest { get; set; } - - //convert GenericQueueDTO to EpisodeQueue - public static EpisodeQueue GenericQueueDTOToEpisodeQueue(GenericQueueDTO queue) - { - return new EpisodeQueue - { - Name = queue.Name, - Url = queue.Url, - NameCfg = queue.NameCfg, - TimeRequest = queue.TimeRequest - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeRegister.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeRegister.cs deleted file mode 100644 index bcaebfa..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/EpisodeRegister.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("episoderegister")] - public class EpisodeRegister - { - [Primary] - [Map("episodeid")] - public string EpisodeId { get; set; } - - [Map("episodepath")] - public string EpisodePath { get; set; } - - [Map("episodehash")] - public string EpisodeHash { get; set; } - - //convert EpisodeRegister to EpisodeRegisterDTO - public static EpisodeRegister EpisodeRegisterToEpisodeRegisterDTO(EpisodeRegisterDTO anime) - { - return new EpisodeRegister - { - EpisodeId = anime.EpisodeId, - EpisodePath = anime.EpisodePath, - EpisodeHash = anime.EpisodeHash - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/GenericNotify.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/GenericNotify.cs deleted file mode 100644 index db90fb7..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/GenericNotify.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.DTO -{ - public class GenericNotify - { - public string Message { get; set; } - public string Image { get; set; } - - //convert NotifyAnimeDTO to GenericNotify - public static GenericNotify NotifyAnimeDTOToGenericNotify(NotifyAnimeDTO notify) - { - return new GenericNotify - { - Message = notify.Message, - Image = notify.Image - }; - } - - //convert NotifyMangaDTO to GenericNotify - public static GenericNotify NotifyMangaDTOToGenericNotify(NotifyMangaDTO notify) - { - return new GenericNotify - { - Message = notify.Message, - Image = notify.Image - }; - } - - //convert NotifyRequestAnimeDTO to GenericNotify - public static GenericNotify NotifyRequestAnimeDTOToGenericNotify(NotifyRequestAnimeDTO notify) - { - return new GenericNotify - { - Message = notify.Message, - Image = notify.Image - }; - } - - //convert NotifyRequestMangaDTO to GenericNotify - public static GenericNotify NotifyRequestMangaDTOToGenericNotify(NotifyRequestMangaDTO notify) - { - return new GenericNotify - { - Message = notify.Message, - Image = notify.Image - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/GenericUrl.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/GenericUrl.cs deleted file mode 100644 index 352cf34..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/GenericUrl.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.Models -{ - public class GenericUrl - { - public string Name { get; set; } - public string Url { get; set; } - public string UrlImage { get; set; } - public string TypeView { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/PlayerUrl.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/PlayerUrl.cs deleted file mode 100644 index 3ab9cd1..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/PlayerUrl.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Cesxhin.AnimeManga.Domain.Models -{ - public class PlayerUrl - { - /* - Download playlist: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/playlist.m3u8 - Select Resolution for download source: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/360p/playlist_360p.m3u8 - Download source: https://www.saturnspeed49.org/DDL/ANIME/HatarakuSaibou2/01/360p/360p-000.ts - */ - - //alternative source - public string BaseUrl { get; set; } - public string Playlist { get; set; } - public string Resolution { get; set; } - public string PlaylistSources { get; set; } - public int startNumberBuffer { get; set; } = 0; - public int endNumberBuffer { get; set; } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/ProgressChapter.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/ProgressChapter.cs deleted file mode 100644 index 9bc8892..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/ProgressChapter.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("progresschapter")] - public class ProgressChapter - { - [Primary] - [Map("id")] - public string ID { get; set; } - [Map("username")] - public string Username { get; set; } - [Map("name")] - public string Name { get; set; } - [Map("namecfg")] - public string NameCfg { get; set; } - [Map("namechapter")] - public string NameChapter { get; set; } - [Map("page")] - public int Page { get; set; } - - //convert ProgressEpisodeDTO to ProgressEpisode - public static ProgressChapter ProgressChapterDTOToProgressChapter(ProgressChapterDTO progress) - { - return new ProgressChapter - { - ID = progress.ID, - Username = progress.Username, - Name = progress.Name, - Page = progress.Page, - NameChapter = progress.NameChapter, - NameCfg = progress.NameCfg, - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/ProgressEpisode.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/ProgressEpisode.cs deleted file mode 100644 index 22af28a..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/ProgressEpisode.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("progressepisode")] - public class ProgressEpisode - { - [Identity] - [Map("id")] - public string ID { get; set; } - [Map("username")] - public string Username { get; set; } - [Map("name")] - public string Name { get; set; } - [Map("namecfg")] - public string NameCfg { get; set; } - [Map("nameepisode")] - public string NameEpisode { get; set; } - [Map("hours")] - public int Hours { get; set; } - [Map("minutes")] - public int Minutes { get; set; } - [Map("seconds")] - public int Seconds { get; set; } - - //convert ProgressChapterDTO to ProgressChapter - public static ProgressEpisode ProgressEpisodeDTOToProgressEpisode(ProgressEpisodeDTO progress) - { - return new ProgressEpisode - { - ID = progress.ID, - Username = progress.Username, - Name = progress.Name, - Hours = progress.Hours, - Minutes = progress.Minutes, - Seconds = progress.Seconds, - NameEpisode = progress.NameEpisode, - NameCfg = progress.NameCfg, - }; - } - } -} \ No newline at end of file diff --git a/src/references/Cesxhin.AnimeManga.Domain/Models/WatchList.cs b/src/references/Cesxhin.AnimeManga.Domain/Models/WatchList.cs deleted file mode 100644 index f89e4c4..0000000 --- a/src/references/Cesxhin.AnimeManga.Domain/Models/WatchList.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Cesxhin.AnimeManga.Domain.DTO; -using RepoDb.Attributes; - -namespace Cesxhin.AnimeManga.Domain.Models -{ - [Map("whitelist")] - public class WatchList - { - [Primary] - [Map("name")] - public string Name { get; set; } - - [Primary] - [Map("username")] - public string Username { get; set; } - - [Primary] - [Map("namecfg")] - public string NameCfg { get; set; } - - //convert AuthDTO to Auth - public static WatchList WatchListDTOToWatchList(WatchListDTO watchListDTO) - { - return new WatchList - { - Name = watchListDTO.Name, - Username = watchListDTO.Username, - NameCfg = watchListDTO.NameCfg, - }; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Cesxhin.AnimeManga.Modules.csproj b/src/references/Cesxhin.AnimeManga.Modules/Cesxhin.AnimeManga.Modules.csproj deleted file mode 100644 index f8acc93..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Cesxhin.AnimeManga.Modules.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net5.0 - - - - - - - - - - - - - - - - - - - - diff --git a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiConflictException.cs b/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiConflictException.cs deleted file mode 100644 index 1d9017d..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiConflictException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Cesxhin.AnimeManga.Modules.Exceptions -{ - public class ApiConflictException : Exception - { - public ApiConflictException() : base() { } - public ApiConflictException(string message) : base(message) { } - public ApiConflictException(string message, Exception inner) : base(message, inner) { } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiGenericException.cs b/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiGenericException.cs deleted file mode 100644 index b261e18..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiGenericException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Cesxhin.AnimeManga.Modules.Exceptions -{ - public class ApiGenericException : Exception - { - public ApiGenericException() : base() { } - public ApiGenericException(string message) : base(message) { } - public ApiGenericException(string message, Exception inner) : base(message, inner) { } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotAuthorizeException.cs b/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotAuthorizeException.cs deleted file mode 100644 index 202bc77..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotAuthorizeException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Cesxhin.AnimeManga.Modules.Exceptions -{ - public class ApiNotAuthorizeException : Exception - { - public ApiNotAuthorizeException() : base() { } - public ApiNotAuthorizeException(string message) : base(message) { } - public ApiNotAuthorizeException(string message, Exception inner) : base(message, inner) { } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotFoundException.cs b/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotFoundException.cs deleted file mode 100644 index 18f976a..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Exceptions/ApiNotFoundException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Cesxhin.AnimeManga.Modules.Exceptions -{ - public class ApiNotFoundException : Exception - { - public ApiNotFoundException() : base() { } - public ApiNotFoundException(string message) : base(message) { } - public ApiNotFoundException(string message, Exception inner) : base(message, inner) { } - - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Generic/Api.cs b/src/references/Cesxhin.AnimeManga.Modules/Generic/Api.cs deleted file mode 100644 index e757913..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Generic/Api.cs +++ /dev/null @@ -1,238 +0,0 @@ -using Cesxhin.AnimeManga.Modules.Exceptions; -using Microsoft.AspNetCore.WebUtilities; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Text.Json; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Modules.Generic -{ - public class Api where T : class - { - //init - readonly string _address = Environment.GetEnvironmentVariable("ADDRESS_API") ?? "localhost"; - readonly string _port = Environment.GetEnvironmentVariable("PORT_API") ?? "5000"; - readonly string _protocol = Environment.GetEnvironmentVariable("PROTOCOL_API") ?? "http"; - - //settings deserialize - readonly JsonSerializerOptions options = new() - { - PropertyNameCaseInsensitive = true, - }; - - //get one object - public async Task GetOne(string path, Dictionary query = null) - { - using (var client = new HttpClient()) - { - string url = $"{_protocol}://{_address}:{_port}{path}"; - - if (query != null) - url = QueryHelpers.AddQueryString(url, query); - - var resultHttp = await client.GetAsync(url); - if (resultHttp.IsSuccessStatusCode) - { - //string to class object - return JsonSerializer.Deserialize(await resultHttp.Content.ReadAsStringAsync(), options); - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else - { - throw new ApiConflictException(resultHttp.Content.ToString()); - } - } - } - - //get more object - public async Task> GetMore(string path, Dictionary query = null) - { - using (var client = new HttpClient()) - { - var url = QueryHelpers.AddQueryString($"{_protocol}://{_address}:{_port}{path}", query); - - var resultHttp = await client.GetAsync(url); - if (resultHttp.IsSuccessStatusCode) - { - //string to class object - return JsonSerializer.Deserialize>(await resultHttp.Content.ReadAsStringAsync(), options); - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else - { - throw new ApiConflictException(resultHttp.Content.ToString()); - } - } - } - - //put one object - public async Task PutOne(string path, T classDTO) - { - using (var client = new HttpClient()) - using (var content = new StringContent(JsonSerializer.Serialize(classDTO), System.Text.Encoding.UTF8, "application/json")) - { - var resultHttp = await client.PutAsync($"{_protocol}://{_address}:{_port}{path}", content); - if (resultHttp.IsSuccessStatusCode) - { - return JsonSerializer.Deserialize(await resultHttp.Content.ReadAsStringAsync(), options); - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else - { - throw new ApiConflictException(resultHttp.ReasonPhrase); - } - } - } - - //for JObject - public async Task PutOne(string path, JObject classDTO) - { - using (var client = new HttpClient()) - using (var content = new StringContent(JsonSerializer.Serialize(classDTO.ToString()), System.Text.Encoding.UTF8, "application/json")) - { - var resultHttp = await client.PutAsync($"{_protocol}://{_address}:{_port}{path}", content); - if (resultHttp.IsSuccessStatusCode) - { - var contentResponse = await resultHttp.Content.ReadAsStringAsync(); - return JObject.Parse(contentResponse); - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else - { - throw new ApiConflictException(resultHttp.ReasonPhrase); - } - } - } - - //put more object - public async Task> PutMore(string path, List classDTO) - { - using (var client = new HttpClient()) - using (var content = new StringContent(JsonSerializer.Serialize(classDTO), System.Text.Encoding.UTF8, "application/json")) - { - var resultHttp = await client.PutAsync($"{_protocol}://{_address}:{_port}{path}", content); - if (resultHttp.IsSuccessStatusCode) - { - return JsonSerializer.Deserialize>(await resultHttp.Content.ReadAsStringAsync(), options); - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else - { - throw new ApiConflictException(resultHttp.Content.ToString()); - } - } - } - - //post one object - public async Task PostOne(string path, T classDTO) - { - using (var client = new HttpClient()) - using (var content = new StringContent(JsonSerializer.Serialize(classDTO), System.Text.Encoding.UTF8, "application/json")) - { - var resultHttp = await client.PostAsync($"{_protocol}://{_address}:{_port}{path}", content); - if (resultHttp.IsSuccessStatusCode) - { - return JsonSerializer.Deserialize(await resultHttp.Content.ReadAsStringAsync(), options); - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else - { - throw new ApiConflictException(resultHttp.Content.ToString()); - } - } - } - - //post more object - public async Task> PostMore(string path, List classDTO) - { - using (var client = new HttpClient()) - using (var content = new StringContent(JsonSerializer.Serialize(classDTO), System.Text.Encoding.UTF8, "application/json")) - { - var resultHttp = await client.PostAsync($"{_protocol}://{_address}:{_port}{path}", content); - if (resultHttp.IsSuccessStatusCode) - { - return JsonSerializer.Deserialize>(await resultHttp.Content.ReadAsStringAsync(), options); - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else - { - throw new ApiConflictException(resultHttp.Content.ToString()); - } - } - } - - //post message to Discord - public void PostMessageDiscord(string path, T classDTO) - { - using (var client = new HttpClient()) - using (var content = new StringContent(JsonSerializer.Serialize(classDTO), System.Text.Encoding.UTF8, "application/json")) - { - var resultHttp = client.PostAsync(path, content).GetAwaiter().GetResult(); - if (resultHttp.IsSuccessStatusCode) - { - return; - } - else if (resultHttp.StatusCode == HttpStatusCode.NotFound) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - else if (resultHttp.StatusCode == HttpStatusCode.Conflict) - { - throw new ApiNotFoundException(resultHttp.Content.ToString()); - } - } - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Generic/ConvertGeneric.cs b/src/references/Cesxhin.AnimeManga.Modules/Generic/ConvertGeneric.cs deleted file mode 100644 index da15cd2..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Generic/ConvertGeneric.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; - -namespace Cesxhin.AnimeManga.Modules.Generic -{ - public static class ConvertGeneric where T : class - { - public static List ConvertIEnurableToListCollection(IEnumerable list) - { - List result = new(); - - foreach (T item in list) - { - result.Add(item); - } - return result; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Generic/Hash.cs b/src/references/Cesxhin.AnimeManga.Modules/Generic/Hash.cs deleted file mode 100644 index 8e9d8fa..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Generic/Hash.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace Cesxhin.AnimeManga.Modules.Generic -{ - public static class Hash - { - public static string GetHash(string path) - { - using (SHA256 hash = SHA256.Create()) - { - try - { - File.OpenRead(path).Close(); - - var content = File.ReadAllBytes(path); - - return BytesToStr(hash.ComputeHash(content)); - } - catch (IOException) - { - return null; - } - } - } - - private static string BytesToStr(byte[] bytes) - { - StringBuilder str = new(); - - for (int i = 0; i < bytes.Length; i++) - str.AppendFormat("{0:X2}", bytes[i]); - - return str.ToString(); - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperBookGeneric.cs b/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperBookGeneric.cs deleted file mode 100644 index 5662a8f..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperBookGeneric.cs +++ /dev/null @@ -1,223 +0,0 @@ -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Modules.Parallel; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using HtmlAgilityPack; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Net; - -namespace Cesxhin.AnimeManga.Modules.HtmlAgilityPack -{ - public static class RipperBookGeneric - { - //log - private static readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //parallel - private static readonly ParallelManager parallel = new(); - - public static JObject GetDescriptionBook(JObject schema, string urlPage, string nameCfg) - { - _logger.Info($"Start download page book: {urlPage}"); - - //get page - HtmlDocument doc = new HtmlWeb().Load(urlPage); - - //create empty for save to db - var descriptionDB = JObject.Parse("{}").ToObject(); - - //get dynamic fields - var fields = schema.GetValue("description").ToObject(); - foreach (var nameField in fields) - { - var result = RipperSchema.GetValue(fields.GetValue(nameField.Key).ToObject(), doc); - descriptionDB.Add(nameField.Key, result); - } - - descriptionDB["nameCfg"] = nameCfg; - descriptionDB["type"] = "book"; - descriptionDB["url_page"] = urlPage; - descriptionDB["name_id"] = RipperSchema.RemoveSpecialCharacters(descriptionDB.GetValue("name_id").ToString()); - - _logger.Info($"End download page book: {urlPage}"); - - return descriptionDB; - } - - public static List GetChapters(JObject schema, string urlPage, string name, string nameCfg) - { - List chaptersList = new(); - - _logger.Info($"Start download chapters manga: {urlPage}"); - - //collection - var collection = schema.GetValue("book").ToObject().GetValue("collection").ToObject(); - HtmlDocument doc = new HtmlWeb().Load(urlPage); - - var results = RipperSchema.GetValue(collection, doc); - - //procedure - var procedure = schema.GetValue("book").ToObject().GetValue("procedure").ToObject(); - var resultBooks = new List(); - - var reverseCount = schema.GetValue("book").ToObject().GetValue("collection").ToObject().GetValue("reverseCount").ToObject(); - - if (collection.GetValue("thread").ToObject() == true) - { - List> tasks = new(); - - foreach (var item in results) - { - var itemThread = item; - tasks.Add(new Func(() => { return GetChapterRecursive(procedure, procedure.Count, 0, itemThread, name, nameCfg); })); - } - - //when finish - parallel.AddTasks(tasks); - parallel.Start(); - parallel.WhenCompleted(); - resultBooks = parallel.GetResultAndClear(); - } - else - { - foreach (var item in results) - { - resultBooks.Add(GetChapterRecursive(procedure, procedure.Count, 0, item, name, nameCfg)); - } - } - - _logger.Info($"End download page episode: {urlPage}"); - - return resultBooks; - } - - private static ChapterDTO GetChapterRecursive(JObject actualProcedure, int step, int current, string urlPage, string name, string nameCfg) - { - - var stepSelect = actualProcedure[current.ToString()].ToObject(); - - var doc = new HtmlWeb().Load(urlPage); - var newUrlPage = RipperSchema.GetValue(stepSelect, doc, 0, 0, name, nameCfg); - - //set step - current += 1; - - if (current == step) - return newUrlPage; - - return GetChapterRecursive(actualProcedure, step, current, newUrlPage, name, nameCfg); - } - - public static byte[] GetImagePage(string urlPage, int page, ChapterDTO chapter) - { - JObject _schema = JObject.Parse(Environment.GetEnvironmentVariable("SCHEMA")); - var schema = _schema.GetValue(chapter.NameCfg).ToObject(); - var downloadSchema = schema.GetValue("book").ToObject().GetValue("download").ToObject(); - - if (downloadSchema.ContainsKey("startZero") && downloadSchema.GetValue("startZero").ToObject() == true) - downloadSchema["numberPage"] = page + 1; - else - downloadSchema["numberPage"] = page; - - var doc = new HtmlWeb().Load(urlPage); - - var imgUrl = RipperSchema.GetValue(downloadSchema, doc); - - using (var webClient = new WebClient()) - { - try - { - return webClient.DownloadData(imgUrl); - } - catch - { - _logger.Error($"Error download image from this url {imgUrl}"); - return null; - } - } - } - - public static List GetBookUrl(JObject schema, string name) - { - _logger.Info($"Start download list book, search: {name}"); - - List listUrlBook = new(); - - HtmlDocument doc; - - string url, prefixPage = null, prefixSearch, imageUrl = null, urlPage = null, nameBook = null; - var docBook = new HtmlDocument(); - - var page = 1; - while (true) - { - try - { - url = schema.GetValue("url_search").ToString(); - prefixSearch = schema.GetValue("prefixSearch").ToString(); - - if (schema.ContainsKey("prefixPage")) - prefixPage = schema.GetValue("prefixPage").ToString(); - - var isPage = schema.GetValue("page").ToObject(); - - if (isPage && prefixPage != null) - url = $"{url}{prefixSearch}={name}&{prefixPage}={page}"; - else - url = $"{url}{prefixSearch}={name}"; - - doc = new HtmlWeb().Load(url); - - - var collection = schema.GetValue("collection").ToObject(); - - var listBook = RipperSchema.GetValue(collection, doc); - - var description = schema.GetValue("description").ToObject(); - - foreach (var manga in listBook) - { - docBook.LoadHtml(manga.InnerHtml); - - //get image cover - var imageUrlSchema = description.GetValue("imageUrl").ToObject(); - imageUrl = RipperSchema.GetValue(imageUrlSchema, docBook); - - //url page - var urlPageSchema = description.GetValue("urlPage").ToObject(); - urlPage = RipperSchema.GetValue(urlPageSchema, docBook); - - //name - var nameBookSchema = description.GetValue("name").ToObject(); - nameBook = RipperSchema.GetValue(nameBookSchema, docBook); - - listUrlBook.Add(new GenericUrl - { - Name = RipperSchema.RemoveSpecialCharacters(nameBook), - Url = urlPage, - UrlImage = imageUrl, - TypeView = "book" - }); - } - - if (!isPage) - break; - } - catch - { - //not found other pages - break; - } - - page++; - } - - _logger.Info($"End download list book, search: {name}"); - - return listUrlBook; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperSchema.cs b/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperSchema.cs deleted file mode 100644 index 0a7a419..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperSchema.cs +++ /dev/null @@ -1,356 +0,0 @@ -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using HtmlAgilityPack; -using m3uParser; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text.RegularExpressions; - -namespace Cesxhin.AnimeManga.Modules.HtmlAgilityPack -{ - public static class RipperSchema - { - //log - private static readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - public static dynamic GetValue(JObject schema, HtmlDocument doc, int numberSeason = 0, int numberEpisode = 0, string name = null, string nameCfg = null) - { - var paths = schema.GetValue("path").ToObject>(); - int i = 0, childNodesSelect = 0; - var types = schema.GetValue("type").ToObject>().ToArray(); - - //check nodes - if (schema.ContainsKey("child_nodes")) - childNodesSelect = (int)schema.GetValue("child_nodes"); - - //array for alternative paths - foreach (var path in paths) - { - try - { - //InnerHtml - if (types[i] == "string") - { - return doc.DocumentNode - .SelectNodes(path) - .First() - .ChildNodes[childNodesSelect] - .InnerHtml.Trim(); - } - else if (types[i] == "number") - { - var result = doc.DocumentNode - .SelectNodes(path) - .First() - .ChildNodes[childNodesSelect] - .InnerHtml; - - if (schema.ContainsKey("removeWords")) - { - var words = schema.GetValue("removeWords").ToObject>(); - - foreach (var word in words) - { - result = result.ToLower().Replace(word.ToLower(), ""); - } - - result = result.Trim(); - } - dynamic resultParse; - - if (schema.ContainsKey("parse") && schema.GetValue("parse").ToString() == "number") - { - try - { - resultParse = int.Parse(result); - } - catch (FormatException ex) - { - resultParse = null; - } - } - else - { - try - { - resultParse = float.Parse(result); - } - catch (FormatException ex) - { - resultParse = null; - } - } - - if (schema.ContainsKey("startZero") && schema.GetValue("startZero").ToObject() == true) - return (resultParse + 1); - - return resultParse; - } - else if (types[i] == "link") //Attributes.Value - { - var attributes = (string)schema.GetValue("attributes"); - - if (schema.ContainsKey("numberPage")) - { - return doc.DocumentNode - .SelectNodes(path.Replace("{numberPage}", (string)schema.GetValue("numberPage"))) - .First() - .Attributes[attributes].Value; - } - - return doc.DocumentNode - .SelectNodes(path) - .First() - .Attributes[attributes].Value; - } - else if (types[i] == "image") //Attributes.Value - { - var attributes = (string)schema.GetValue("attributes"); - string result = null; - - result = doc.DocumentNode - .SelectNodes(path) - .First() - .Attributes[attributes].Value; - - if (schema.ContainsKey("download") && (bool)schema.GetValue("download") == true) - { - try - { - using (var webClient = new WebClient()) - { - return Convert.ToBase64String(webClient.DownloadData(result)); - } - } - catch - { - _logger.Error($"Error download from this url {result}"); - } - } - return result; - } - else if (types[i] == "video/mp4") - { - var url = doc.DocumentNode - .SelectNodes(path) - .First() - .Attributes["src"].Value; - - return DownloadMetadataEpisode(numberSeason, numberEpisode, url, name, true, nameCfg); - } - else if (types[i] == "video/m3u8/script") - { - var script = doc.DocumentNode - .SelectNodes(path) - .First() - .InnerText; - - var startWord = schema.GetValue("startSearch").ToString(); - var endWord = schema.GetValue("endSearch").ToString(); - - var start = script.IndexOf(startWord); - - script = script.Substring(start + startWord.Length); - - var end = script.IndexOf(endWord); - - var url = script.Substring(0, end); - - return DownloadMetadataEpisode(numberSeason, numberEpisode, url, name, false, nameCfg); - } - else if (types[i] == "array") - { - var attributes = (string)schema.GetValue("attributes"); - - if (attributes == null) - { - return doc.DocumentNode - .SelectNodes(path) - .ToList(); - } - - var resultArray = new List(); - var list = doc.DocumentNode - .SelectNodes(path) - .ToList(); - - foreach (var item in list) - { - resultArray.Add(item.Attributes[attributes].Value); - } - - return resultArray; - } - else if (types[i] == "book/link") - { - var attributes = (string)schema.GetValue("attributes"); - - var url = doc.DocumentNode - .SelectNodes(path) - .First() - .Attributes[attributes].Value; - - if (schema.ContainsKey("addUrl")) - { - var addUrl = (string)schema.GetValue("addUrl"); - if (!url.Contains(addUrl)) - { - if (url.LastIndexOf('/') == (url.Trim().Length - 1)) - url = $"{url.Substring(0, url.LastIndexOf('/'))}/{addUrl}"; - else - url += addUrl; - } - } - - return DownloadMetadataChapter(schema, url, name, nameCfg); - } - break; - } - catch (Exception e) - { - _logger.Warn(e); - - continue; - } - finally - { - if ((i + 1) < types.Length) - i++; - } - } - - _logger.Error("Error get value by schema"); - return null; - } - - - public static string RemoveSpecialCharacters(string str) - { - //remove character special - return Regex.Replace(str, "[^a-zA-Z0-9_() ]+", "", RegexOptions.Compiled); - } - - private static ChapterDTO DownloadMetadataChapter(JObject schema, string urlBook, string name, string nameCfg) - { - int attempt = 5; - - while (attempt > 0) - { - var doc = new HtmlWeb().Load(urlBook); - - //get maxImage - var maxImageSchema = schema.GetValue("numberMaxImage").ToObject(); - var maxImage = GetValue(maxImageSchema, doc); - maxImage = maxImage[maxImage.Count - 1]; - maxImage = int.Parse(maxImage); - - if (maxImageSchema.ContainsKey("startZero") && maxImageSchema.GetValue("startZero").ToObject() == true) - maxImage += 1; - - //get number volume - var numberVolumeSchema = schema.GetValue("getVolume").ToObject(); - var numberVolume = GetValue(numberVolumeSchema, doc); - - if (numberVolume == null) - numberVolume = 1; - - //get number chapter - var numberChapterSchema = schema.GetValue("getChapter").ToObject(); - var numberChapter = GetValue(numberChapterSchema, doc); - - try - { - return new ChapterDTO - { - ID = $"{name}-v{numberVolume}-c{numberChapter}", - CurrentChapter = numberChapter, - CurrentVolume = numberVolume, - NameManga = name, - UrlPage = urlBook, - NumberMaxImage = maxImage, - NameCfg = nameCfg - }; - } - catch - { - attempt--; - _logger.Warn($"Failed download url: {urlBook}, remaining attempts {attempt}"); - } - } - - _logger.Fatal($"Impossible download this chapter, details: {urlBook}"); - return null; - } - - private static EpisodeDTO DownloadMetadataEpisode(int numberSeason, int numberEpisode, string urlVideo, string name, bool mp4, string nameCfg) - { - PlayerUrl playerUrl = null; - - if (mp4 == false) - { - _logger.Debug($"Start download url with buffer: {urlVideo}"); - - playerUrl = new PlayerUrl - { - Playlist = urlVideo - }; - - playerUrl.BaseUrl = playerUrl.Playlist.Replace("/playlist.m3u8", ""); - - //download source files - WebClient client = new(); - var bytes = client.DownloadData(playerUrl.Playlist); - var sourceFiles = System.Text.Encoding.UTF8.GetString(bytes); - - var contentM3u = M3U.Parse(sourceFiles); - string file = contentM3u.Warnings.First(); - - playerUrl.PlaylistSources = file.Substring(file.LastIndexOf("./") + 1); - playerUrl.Resolution = playerUrl.PlaylistSources.Substring(1, playerUrl.PlaylistSources.IndexOf("p")); - - //get list bytes for file - bytes = client.DownloadData(playerUrl.BaseUrl + playerUrl.PlaylistSources); - sourceFiles = System.Text.Encoding.UTF8.GetString(bytes); - contentM3u = M3U.Parse(sourceFiles); - playerUrl.endNumberBuffer = contentM3u.Medias.Count() - 1; //start 0 to xx - - _logger.Debug($"Done download url with buffer: {urlVideo}"); - } - - if (playerUrl != null) - { - return new EpisodeDTO - { - ID = $"{name}-s{numberSeason}-e{numberEpisode}", - VideoId = name, - NumberEpisodeCurrent = numberEpisode, - BaseUrl = playerUrl.BaseUrl, - Playlist = playerUrl.Playlist, - PlaylistSources = playerUrl.PlaylistSources, - Resolution = playerUrl.Resolution, - NumberSeasonCurrent = numberSeason, - endNumberBuffer = playerUrl.endNumberBuffer, - nameCfg = nameCfg - }; - } - else - { - return new EpisodeDTO - { - ID = $"{name}-s{numberSeason}-e{numberEpisode}", - VideoId = name, - UrlVideo = urlVideo, - NumberEpisodeCurrent = numberEpisode, - NumberSeasonCurrent = numberSeason, - nameCfg = nameCfg - - }; - } - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperVideoGeneric.cs b/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperVideoGeneric.cs deleted file mode 100644 index e97ae6c..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/HtmlAgilityPack/RipperVideoGeneric.cs +++ /dev/null @@ -1,200 +0,0 @@ -using Cesxhin.AnimeManga.Modules.NlogManager; -using Cesxhin.AnimeManga.Modules.Parallel; -using Cesxhin.AnimeManga.Domain.DTO; -using Cesxhin.AnimeManga.Domain.Models; -using HtmlAgilityPack; -using Newtonsoft.Json.Linq; -using NLog; -using System; -using System.Collections.Generic; - -namespace Cesxhin.AnimeManga.Modules.HtmlAgilityPack -{ - public static class RipperVideoGeneric - { - //log - private static readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //parallel - private static readonly ParallelManager parallel = new(); - private static readonly ParallelManager _parallel = new(); - - public static JObject GetDescriptionVideo(JObject schema, string urlPage, string nameCfg) - { - _logger.Info($"Start download page video: {urlPage}"); - - //get page - HtmlDocument doc = new HtmlWeb().Load(urlPage); - - //create empty for save to db - var descriptionDB = JObject.Parse("{}").ToObject(); - - //get dynamic fields - var fields = schema.GetValue("description").ToObject(); - foreach (var nameField in fields) - { - var result = RipperSchema.GetValue(fields.GetValue(nameField.Key).ToObject(), doc); - descriptionDB.Add(nameField.Key, result); - } - - descriptionDB["nameCfg"] = nameCfg; - descriptionDB["type"] = "video"; - descriptionDB["url_page"] = urlPage; - descriptionDB["name_id"] = RipperSchema.RemoveSpecialCharacters(descriptionDB.GetValue("name_id").ToString()); - - _logger.Info($"End download page video: {urlPage}"); - - return descriptionDB; - } - - public static dynamic GetEpisodesRecursive(JObject actualProcedure, int step, int current, string urlPage, int numberSeason, int numberEpisode, string name, string nameCfg) - { - var stepSelect = actualProcedure[current.ToString()].ToObject(); - - //array for alternative paths - var doc = new HtmlWeb().Load(urlPage); - var newUrlPage = RipperSchema.GetValue(stepSelect, doc, numberSeason, numberEpisode, name, nameCfg); - - //set step - current += 1; - - if (current == step) - return newUrlPage; - - return GetEpisodesRecursive(actualProcedure, step, current, newUrlPage, numberSeason, numberEpisode, name, nameCfg); - } - - public static List GetEpisodes(JObject schema, string urlPage, string name, string nameCfg) - { - //set variable - List episodes = new(); - int numberSeason = 1; //default - int numberEpisode = 1; - - _logger.Info($"Start download page episode: {urlPage}"); - - //collection - var collection = schema.GetValue("video").ToObject().GetValue("collection").ToObject(); - HtmlDocument doc = new HtmlWeb().Load(urlPage); - - var resultCollection = RipperSchema.GetValue(collection, doc); - - //procedure - var procedure = schema.GetValue("video").ToObject().GetValue("procedure").ToObject(); - var resultVideos = new List(); - - if (collection.GetValue("thread").ToObject() == true) - { - List> tasks = new(); - - foreach (var item in resultCollection) - { - var itemThread = item; - var numberSeasonThread = numberSeason; - var numberEpisodeThread = numberEpisode; - - tasks.Add(new Func(() => { return GetEpisodesRecursive(procedure, procedure.Count, 0, itemThread, numberSeasonThread, numberEpisodeThread, name, nameCfg); })); - numberEpisode += 1; - } - - //when finish - parallel.AddTasks(tasks); - parallel.Start(); - parallel.WhenCompleted(); - resultVideos = parallel.GetResultAndClear(); - } - else - { - foreach (var item in resultCollection) - { - resultVideos.Add(GetEpisodesRecursive(procedure, procedure.Count, 0, item, numberSeason, numberEpisode, name, nameCfg)); - numberEpisode += 1; - } - } - - _logger.Info($"End download page episode: {urlPage}"); - - return resultVideos; - } - - //get list anime external - public static List GetVideoUrl(JObject schema, string name) - { - _logger.Info($"Start download list video, search: {name}"); - - List listUrlVideo = new(); - - HtmlDocument doc; - - string url, prefixPage = null, prefixSearch, imageUrl = null, urlPage = null, nameVideo = null; - var docBook = new HtmlDocument(); - - var page = 1; - while (true) - { - try - { - url = schema.GetValue("url_search").ToString(); - prefixSearch = schema.GetValue("prefixSearch").ToString(); - - if (schema.ContainsKey("prefixPage")) - prefixPage = schema.GetValue("prefixPage").ToString(); - - var isPage = schema.GetValue("page").ToObject(); - - if (isPage && prefixPage != null) - url = $"{url}{prefixSearch}={name}&{prefixPage}={page}"; - else - url = $"{url}{prefixSearch}={name}"; - - doc = new HtmlWeb().Load(url); - - - var collection = schema.GetValue("collection").ToObject(); - - var listBook = RipperSchema.GetValue(collection, doc); - - var description = schema.GetValue("description").ToObject(); - - foreach (var manga in listBook) - { - docBook.LoadHtml(manga.InnerHtml); - - //get image cover - var imageUrlSchema = description.GetValue("imageUrl").ToObject(); - imageUrl = RipperSchema.GetValue(imageUrlSchema, docBook); - - //url page - var urlPageSchema = description.GetValue("urlPage").ToObject(); - urlPage = RipperSchema.GetValue(urlPageSchema, docBook); - - //name - var nameBookSchema = description.GetValue("name").ToObject(); - nameVideo = RipperSchema.GetValue(nameBookSchema, docBook); - - listUrlVideo.Add(new GenericUrl - { - Name = RipperSchema.RemoveSpecialCharacters(nameVideo), - Url = urlPage, - UrlImage = imageUrl, - TypeView = "video" - }); - } - - if (!isPage) - break; - } - catch - { - //not found other pages - break; - } - - page++; - } - - _logger.Info($"End download list video, search: {name}"); - return listUrlVideo; - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogConsole.cs b/src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogConsole.cs deleted file mode 100644 index c847734..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogConsole.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Discord.Webhook; -using NLog; -using System; - -namespace Cesxhin.AnimeManga.Modules.NlogManager -{ - public class NLogConsole - { - private readonly Logger _logger; - private readonly DiscordWebhookClient discord; - - public NLogConsole(Logger logger) - { - //log - _logger = logger; - - //webhook - var webhookUrl = Environment.GetEnvironmentVariable("WEBHOOK_DISCORD_DEBUG") ?? null; - - if (webhookUrl != null) - discord = new DiscordWebhookClient(webhookUrl); - } - - private string DefaultMessage(LogLevel level, string msg) - { - string message = ""; - message += DateTime.Now.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss") + " | "; - - //set type error - switch (level.Name.ToLower()) - { - case "info": - message += "🔵 info: "; - break; - case "warn": - message += "🔶 warning: "; - break; - case "error": - message += "🔴 error: "; - break; - case "fatal": - message += "💀 fatal: "; - break; - } - message += msg; - - return message; - } - - //debug - public void Debug(object msg) - { - _logger.Debug(msg); - } - - //info - public void Info(object msg) - { - _logger.Info(msg); - - if (discord != null) - { - var _content = DefaultMessage(LogLevel.Info, msg.ToString()); - - discord.SendMessageAsync(_content).GetAwaiter().GetResult(); - } - } - - //warn - public void Warn(object msg) - { - _logger.Warn(msg); - - if (discord != null) - { - var _content = DefaultMessage(LogLevel.Warn, msg.ToString()); - - discord.SendMessageAsync(_content).GetAwaiter().GetResult(); - } - } - - //error - public void Error(object msg) - { - _logger.Error(msg); - - if (discord != null) - { - var _content = DefaultMessage(LogLevel.Error, msg.ToString()); - - discord.SendMessageAsync(_content).GetAwaiter().GetResult(); - } - } - - //fatal - public void Fatal(object msg) - { - _logger.Fatal(msg); - - if (discord != null) - { - var _content = DefaultMessage(LogLevel.Fatal, msg.ToString()); - - discord.SendMessageAsync(_content).GetAwaiter().GetResult(); - } - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogManager.cs b/src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogManager.cs deleted file mode 100644 index 0661973..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/NlogManager/NLogManager.cs +++ /dev/null @@ -1,41 +0,0 @@ -using NLog; -using NLog.Config; -using NLog.Targets; - -namespace Cesxhin.AnimeManga.Modules.Generic -{ - public class NLogManager - { - public static void Configure(LogLevel minLevel) - { - var config = new LoggingConfiguration(); - - var consoleTarget = new ConsoleTarget(); - config.AddTarget("console", consoleTarget); - - var rule = new LoggingRule("*", minLevel, consoleTarget); - config.LoggingRules.Add(rule); - - LogManager.Configuration = config; - } - - public static LogLevel GetLevel(string level) - { - switch (level) - { - case "debug": - return LogLevel.Debug; - case "info": - return LogLevel.Info; - case "warn": - return LogLevel.Warn; - case "error": - return LogLevel.Error; - case "fatal": - return LogLevel.Fatal; - default: - return LogLevel.Info; - } - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Parallel/ParallelManager.cs b/src/references/Cesxhin.AnimeManga.Modules/Parallel/ParallelManager.cs deleted file mode 100644 index 80eacca..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Parallel/ParallelManager.cs +++ /dev/null @@ -1,154 +0,0 @@ -using Cesxhin.AnimeManga.Modules.NlogManager; -using NLog; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace Cesxhin.AnimeManga.Modules.Parallel -{ - public class ParallelManager where T : class - { - //env - private readonly int NUMBER_PARALLEL_MAX = int.Parse(Environment.GetEnvironmentVariable("LIMIT_THREAD_PARALLEL") ?? "5"); - - //variable - private List> queue = new(); - private readonly List tasks = new(); - private readonly CancellationTokenSource tokenSource = new(); - - //nlog - private readonly NLogConsole _logger = new(LogManager.GetCurrentClassLogger()); - - //completed - private List list = new(); - - //task id - private Task process; - - private void Process(CancellationToken ct) - { - //thread for download parallel - int capacity = 0; - int count = 0; - - while (queue.Count != 0 || tasks.Count != 0) - { - if (ct.IsCancellationRequested) - ct.ThrowIfCancellationRequested(); - - //add task - while(capacity < NUMBER_PARALLEL_MAX && queue.Count > 0) - { - var task = queue.First(); - - if (task != null) - { - tasks.Add(Task.Run(task)); - capacity++; - queue.Remove(task); - } - else - { - _logger.Error($"Problem task null"); - } - } - - //must remove one task for continue download - do - { - List removeTask = new(); - foreach (var task in tasks) - { - if (task.IsCompleted) - { - var objectBuffer = ((Task)task).Result; - - list.Add(objectBuffer); - count++; - - capacity--; - removeTask.Add(task); - } - } - - //remove rask completed - foreach (var task in removeTask) - { - tasks.Remove(task); - } - - Thread.Sleep(1000); - } while (capacity >= NUMBER_PARALLEL_MAX); - } - } - - public void Start() - { - var token = tokenSource.Token; - process = Task.Run(() => Process(token), token); - } - - public void AddTasks(List> tasks) - { - queue = tasks; - } - - public bool CheckFinish() - { - if (tasks.Count == 0 && queue.Count == 0) - return true; - else - return false; - } - - public void WhenCompleted() - { - Task.WaitAll(process); - } - - public int PercentualCompleted() - { - if (list == null) - return 0; - return (list.Count * 100) / (list.Count + tasks.Count + queue.Count); //43 : 100 = 4 : x - } - - public List GetResult() - { - return list; - } - - public List GetResultAndClear() - { - List copy = new(list); - list.Clear(); - - return copy; - } - - public async void Kill() - { - tokenSource.Cancel(); - - while (process.IsCanceled == false) - { - Thread.Sleep(500); - } - - tasks.Clear(); - queue.Clear(); - } - - public bool checkError(T variableError) - { - return list.Contains(variableError); - } - - public void ClearList() - { - list.Clear(); - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Proxy/ProxyManagement.cs b/src/references/Cesxhin.AnimeManga.Modules/Proxy/ProxyManagement.cs deleted file mode 100644 index cb13ead..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Proxy/ProxyManagement.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Cesxhin.AnimeManga.Modules.Proxy -{ - public class ProxyManagement - { - private string blackList = ""; - private List listProxy = new(); - - public void InitProxy() - { - var enableProxy = Environment.GetEnvironmentVariable("PROXY_ENABLE") ?? "false"; - - if (enableProxy == "true") - { - listProxy = System.IO.File.ReadAllText("proxy.txt").Split(",").ToList(); - } - } - - public List GetAllIP() - { - return listProxy; - } - - public string GetIp() - { - if(EnableProxy()) - { - var listBlackProxy = blackList.Split(",").ToList(); - - foreach (var blackProxy in listBlackProxy) - { - listProxy = listProxy.Where(e => e != blackProxy).ToList(); - } - - if (listProxy.Count > 0) - { - return listProxy[new Random().Next(listProxy.Count)]; - } - } - - return null; - } - - public bool EnableProxy() - { - var enableProxy = Environment.GetEnvironmentVariable("PROXY_ENABLE") ?? "false"; - return enableProxy == "true"; - } - - public void BlackListAdd(string ip) - { - var list = blackList.Split(",").ToList(); - - if(list.Find(e => e == ip) == null) - { - list.Add(ip); - blackList = string.Join(",", list); - } - } - } -} diff --git a/src/references/Cesxhin.AnimeManga.Modules/Schema/SchemaControl.cs b/src/references/Cesxhin.AnimeManga.Modules/Schema/SchemaControl.cs deleted file mode 100644 index 6ef6011..0000000 --- a/src/references/Cesxhin.AnimeManga.Modules/Schema/SchemaControl.cs +++ /dev/null @@ -1,207 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Cesxhin.AnimeManga.Modules.Schema -{ - public static class SchemaControl - { - public static void Check() - { - //check valid schema - Console.WriteLine("[STARTUP] Check schemas"); - var schemasFile = System.IO.File.ReadAllText("schemas.json"); - var schemaTemplateFile = System.IO.File.ReadAllText("schema_template.json"); - - var schema = JObject.Parse(schemasFile); - var schemaTemplate = JObject.Parse(schemaTemplateFile); - - CheckRecursive(schema, schemaTemplate, ""); - - Environment.SetEnvironmentVariable("SCHEMA", schemasFile); - } - - private static void CheckRecursive(JObject schema, JObject schemaTemplate, string path) - { - foreach (var field in schemaTemplate.ToObject()) - { - if (field.Key == "*" && path != "") - { - foreach(var fieldSchema in schema.ToObject()) - { - CheckRules(schema.GetValue(fieldSchema.Key).ToObject(), path+"/"+fieldSchema.Key); - } - } - else - { - if (field.Key != "*" && !schema.ContainsKey(field.Key)) - { - throw new Exception($"Missing this field: {field.Key}"); - } - - if (field.Value.Type == JTokenType.Object) - { - CheckRecursive(getKeyByField(schema, field.Key), schemaTemplate.GetValue(field.Key).ToObject(), path + "/" + field.Key); - } - else - { - //check type - if ((string)field.Value == "string") - { - if (schema.GetValue(field.Key).Type != JTokenType.String) - throw new Exception($"Field {field.Key} isn't type String"); - - //check rules - if (path == "/*" && field.Key == "type") - { - if (schema.Value(field.Key) != "video" && schema.Value(field.Key) != "book") - throw new Exception($"Field Type is incorrect, please select 'video' or 'book'"); - } - } - else if ((string)field.Value == "boolean") - { - if (schema.GetValue(field.Key).Type != JTokenType.Boolean) - throw new Exception($"Field {field.Key} isn't type Boolean"); - } - else if ((string)field.Value == "*") - { - CheckRules(schema.Value(field.Key), path + "/" + field.Key); - } - else - { - throw new Exception($"Uknow type, error schema template of this field {field.Key}, path: {path}"); - } - } - } - } - } - - private static void CheckRules(JObject schema, string path) - { - if (!schema.ContainsKey("type")) - throw new Exception("Missing field type for scapring"); - - if (!schema.ContainsKey("path")) - throw new Exception("Missing field path for scapring"); - - if(schema.GetValue("type").Type != JTokenType.Array) - throw new Exception("Field type for scapring isn't array"); - - if (schema.GetValue("path").Type != JTokenType.Array) - throw new Exception("Field path for scapring isn't array"); - - var arrayType = schema.GetValue("type").ToObject>(); - var arrayPath = schema.GetValue("path").ToObject>(); - - /*if (arrayType.Count() != arrayPath.Count()) - throw new Exception("Lenght between type and path is different, they should be equal");*/ - - foreach (var type in arrayType) - { - switch (type) - { - case "string": - if (schema.ContainsKey("child_nodes")) - { - if (schema.GetValue("child_nodes").Type != JTokenType.Integer) - throw new Exception($"Field child_nodes should be Interger"); - } - break; - case "image": - if(!schema.ContainsKey("attributes")) - throw new Exception($"Field attributes missing"); - - if(schema.GetValue("attributes").Type != JTokenType.String) - throw new Exception($"Field attributes should be String"); - - if (schema.ContainsKey("download")) - { - if (schema.GetValue("download").Type != JTokenType.Boolean) - throw new Exception($"Field attributes should be Boolean"); - } - - break; - - case "array": - if (schema.ContainsKey("attributes")) - { - if (schema.GetValue("attributes").Type != JTokenType.String) - throw new Exception($"Field attributes should be String"); - } - break; - - case "video/m3u8/script": - if (!schema.ContainsKey("startSearch")) - throw new Exception($"Field startSearch missing"); - - if (schema.GetValue("startSearch").Type != JTokenType.String) - throw new Exception($"Field startSearch should be String"); - - if (!schema.ContainsKey("endSearch")) - throw new Exception($"Field endSearch missing"); - - if (schema.GetValue("endSearch").Type != JTokenType.String) - throw new Exception($"Field endSearch should be String"); - break; - case "number": - if (schema.ContainsKey("parse")) - { - if (schema.GetValue("parse").Type != JTokenType.String) - throw new Exception($"Field parse should be String"); - - if (schema.Value("parse") != "number" && schema.Value("parse") != "float") - throw new Exception($"Field parse is incorrect, please select 'number' or 'float'"); - } - - if (schema.ContainsKey("removeWords")) - { - if (schema.GetValue("removeWords").Type != JTokenType.String) - throw new Exception($"Field removeWords should be String"); - } - break; - case "book/link": - if (!schema.ContainsKey("attributes")) - throw new Exception($"Field attributes missing"); - - if (schema.GetValue("attributes").Type != JTokenType.String) - throw new Exception($"Field attributes should be String"); - - if (schema.ContainsKey("addUrl")) - { - if (schema.GetValue("addUrl").Type != JTokenType.String) - throw new Exception($"Field addUrl should be String"); - } - break; - } - } - - //collection of video or book - if(path == "/*/book/collection" || path == "/*/video/collection") - { - if (!schema.ContainsKey("thread")) - throw new Exception($"Field thread missing"); - - if (schema.GetValue("thread").Type != JTokenType.Boolean) - throw new Exception($"Field thread should be Boolean"); - - if (schema.ContainsKey("reverseCount")) - { - if (schema.GetValue("reverseCount").Type != JTokenType.Boolean) - throw new Exception($"Field reverseCount should be Boolean"); - } - } - } - - private static JObject getKeyByField(JObject schema, string field) - { - if (field == "*") - { - var name = ((JProperty)schema.First).Name.ToString(); - return schema.GetValue(name).ToObject(); - } - else - return schema.GetValue(field).ToObject(); - } - } -} diff --git a/src/schemas/accountSchema.ts b/src/schemas/accountSchema.ts new file mode 100644 index 0000000..85a4a26 --- /dev/null +++ b/src/schemas/accountSchema.ts @@ -0,0 +1,28 @@ +import { Type } from "@sinclair/typebox"; + +import { accountSchema, IAccountEnv } from "../domain/interfaces/models/IAccount"; +import { accountDTOSchema } from "../domain/interfaces/DTOs/IAccountDTO"; +import { convertToOptional } from "../utils/schemaUtils"; + +//path base +const PATH_BASE_CONTROLLER = "/account"; + +//request +const schemaCreateAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME, IAccountEnv.PASSWORD, IAccountEnv.CHANGE_PASSWORD]); +const schemaUpdateAccount = convertToOptional(accountSchema, [IAccountEnv.PROFILE, IAccountEnv.CHANGE_PASSWORD]); +const schemaQueryUsernameAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME]); + +//replay +const schemaReturnAccount = accountDTOSchema; + +export { + PATH_BASE_CONTROLLER, + + //request + schemaCreateAccount, + schemaUpdateAccount, + schemaQueryUsernameAccount, + + //replay + schemaReturnAccount +}; \ No newline at end of file diff --git a/src_refactory/schemas/generic/genericSchema.ts b/src/schemas/generic/genericSchema.ts similarity index 80% rename from src_refactory/schemas/generic/genericSchema.ts rename to src/schemas/generic/genericSchema.ts index a3d69ff..6de30ca 100644 --- a/src_refactory/schemas/generic/genericSchema.ts +++ b/src/schemas/generic/genericSchema.ts @@ -1,14 +1,13 @@ import { Type } from "@sinclair/typebox"; -const SCHEMA_RETURN_VOID = "SchemaReturnVoid"; const SCHEMA_NOT_FOUND = "SchemaNotFound"; const SCHEMA_INTERNAL_SERVER = "SchemaInternalServer"; const SCHEMA_CONFLICT = "SchemaConflict"; const SCHEMA_BAD_REQUEST = "SchemaBadRequest"; -const returnVoid = Type.Object({ +const schemaReturnVoid = Type.Object({ response: Type.String({default: "ok"}) -}, {$id: SCHEMA_RETURN_VOID}); +}); const templateErrorSchema = Type.Object({ message: Type.String({default: "Example error"}), @@ -36,14 +35,13 @@ templateErrorSchema, Type.Object({ }) ], { $id: SCHEMA_BAD_REQUEST }); -export default [returnVoid, notFound, internalServer, conflict, badRequest]; - -type staticReturnVoid = typeof returnVoid.static +export default [notFound, internalServer, conflict, badRequest]; export { - staticReturnVoid, + //replay + schemaReturnVoid, - SCHEMA_RETURN_VOID, + //replay with ID SCHEMA_NOT_FOUND, SCHEMA_BAD_REQUEST, SCHEMA_CONFLICT, diff --git a/src_refactory/schemas/generic/paginationSchema.ts b/src/schemas/generic/paginationSchema.ts similarity index 74% rename from src_refactory/schemas/generic/paginationSchema.ts rename to src/schemas/generic/paginationSchema.ts index 70d775c..79fc5b7 100644 --- a/src_refactory/schemas/generic/paginationSchema.ts +++ b/src/schemas/generic/paginationSchema.ts @@ -5,10 +5,10 @@ const queryPagination = Type.Object({ length: Type.Number({minimum: 10, default: 10}) }); -const schemaReturnPagination = (schema: T, id: string) => Type.Object({ +const schemaReturnPagination = (schema: T) => Type.Object({ max_count: Type.Number(), list: Type.Array(schema) -}, {$id: id}); +}); export { schemaReturnPagination, diff --git a/src/schemas/requestSchema.ts b/src/schemas/requestSchema.ts new file mode 100644 index 0000000..a350c18 --- /dev/null +++ b/src/schemas/requestSchema.ts @@ -0,0 +1,32 @@ +import { Type } from "@sinclair/typebox"; +import { queryPagination, schemaReturnPagination } from "./generic/paginationSchema"; +import { requestDTOSchema } from "../domain/interfaces/DTOs/IRequestDTO"; +import { IRequestEnv, requestSchema } from "../domain/interfaces/models/IRequest"; + +//path base +const PATH_BASE_CONTROLLER = "/request"; + +//request +const schemaCreateRequest = Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO]); +const schemaActionRequest = Type.Intersect([ + Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO]), + Type.Object({ + accept: Type.Boolean() + }) +]); +const schemaQueryPaginatedRequest = Type.Intersect([Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM]), queryPagination]); + +//replay +const schemaReturnPaginatedRequest = schemaReturnPagination(requestDTOSchema); + +export { + PATH_BASE_CONTROLLER, + + //request + schemaCreateRequest, + schemaActionRequest, + schemaQueryPaginatedRequest, + + //replay + schemaReturnPaginatedRequest +}; \ No newline at end of file diff --git a/src_refactory/server/fastify/index.ts b/src/server/fastify/index.ts similarity index 98% rename from src_refactory/server/fastify/index.ts rename to src/server/fastify/index.ts index ef50716..12dcfff 100644 --- a/src_refactory/server/fastify/index.ts +++ b/src/server/fastify/index.ts @@ -4,6 +4,7 @@ import path from "path"; import Fastify from "fastify"; import { DateTime } from "luxon"; import { env, exit } from "process"; +import { Type, TypeBoxTypeProvider } from "@fastify/type-provider-typebox"; import { IConfig } from "./interfaces/IConfig"; import { ApiBadRequest, ApiConflict, ApiErrorGeneric, ApiNotFound, ApiUnauthorized } from "../../modules/api"; @@ -14,7 +15,7 @@ const logger = new Logger("server-fastify"); const __dirname = path.resolve(); //settings -const fastify = Fastify(); +const fastify = Fastify().withTypeProvider(); //init async function init({pathControllers = "controllers", pathSchemas = "schemas", swagger = true}: IConfig){ diff --git a/src_refactory/server/fastify/interfaces/IConfig.ts b/src/server/fastify/interfaces/IConfig.ts similarity index 100% rename from src_refactory/server/fastify/interfaces/IConfig.ts rename to src/server/fastify/interfaces/IConfig.ts diff --git a/src_refactory/server/postgres/index.ts b/src/server/postgres/index.ts similarity index 100% rename from src_refactory/server/postgres/index.ts rename to src/server/postgres/index.ts diff --git a/src_refactory/server/postgres/interfaces/IConfigPostgres.ts b/src/server/postgres/interfaces/IConfigPostgres.ts similarity index 100% rename from src_refactory/server/postgres/interfaces/IConfigPostgres.ts rename to src/server/postgres/interfaces/IConfigPostgres.ts diff --git a/src_refactory/tsconfig.json b/src/tsconfig.json similarity index 100% rename from src_refactory/tsconfig.json rename to src/tsconfig.json diff --git a/src_refactory/utils/accountUtils.ts b/src/utils/accountUtils.ts similarity index 100% rename from src_refactory/utils/accountUtils.ts rename to src/utils/accountUtils.ts diff --git a/src_refactory/utils/genericUtils.ts b/src/utils/genericUtils.ts similarity index 100% rename from src_refactory/utils/genericUtils.ts rename to src/utils/genericUtils.ts diff --git a/src_refactory/utils/schemaUtils.ts b/src/utils/schemaUtils.ts similarity index 76% rename from src_refactory/utils/schemaUtils.ts rename to src/utils/schemaUtils.ts index 79633b8..dfee626 100644 --- a/src_refactory/utils/schemaUtils.ts +++ b/src/utils/schemaUtils.ts @@ -1,9 +1,9 @@ import { TSchema, Type } from "@sinclair/typebox"; -function convertToOptional(schema: T, keys: Array, id: string){ +function convertToOptional(schema: T, keys: Array){ const pick = Type.Pick(schema, keys); - return Type.Mapped(Type.KeyOf(pick), (K) => Type.Optional(Type.Index(pick, K)), { $id: id }); + return Type.Mapped(Type.KeyOf(pick), (K) => Type.Optional(Type.Index(pick, K))); } export { diff --git a/src_refactory/controllers/accountController/createRoute.ts b/src_refactory/controllers/accountController/createRoute.ts deleted file mode 100644 index 86925eb..0000000 --- a/src_refactory/controllers/accountController/createRoute.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { RouteShorthandOptions } from "fastify"; - -import { PATH_BASE_CONTROLLER, SCHEMA_CREATE_ACCOUNT, SCHEMA_RETURN_ACCOUNT, staticCreateAccount } from "../../schemas/accountSchema"; -import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; - -import { AccountService } from "../../applications/services/AccountService"; - -import fastify from "../../server/fastify"; - -const accountService = new AccountService(); - -const options: RouteShorthandOptions = { - schema: { - tags: ["account"], - summary: "Create new account", - body: { $ref: SCHEMA_CREATE_ACCOUNT }, - response: { - 200: { $ref: SCHEMA_RETURN_ACCOUNT }, - 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 401: { $ref: SCHEMA_BAD_REQUEST } - } - } -}; - -fastify.post<{Querystring: staticCreateAccount}>(`${PATH_BASE_CONTROLLER}/create`, options, async (request) => { - return await accountService.createAccount(request.body); -}); \ No newline at end of file diff --git a/src_refactory/controllers/accountController/deleteRoute.ts b/src_refactory/controllers/accountController/deleteRoute.ts deleted file mode 100644 index fc9cb95..0000000 --- a/src_refactory/controllers/accountController/deleteRoute.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { RouteShorthandOptions } from "fastify"; - -import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; -import { PATH_BASE_CONTROLLER, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount } from "../../schemas/accountSchema"; - -import { AccountService } from "../../applications/services/AccountService"; - -import fastify from "../../server/fastify"; - -const accountService = new AccountService(); - -const options: RouteShorthandOptions = { - schema: { - tags: ["account"], - summary: "Delete account", - querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, - response: { - 200: { $ref: SCHEMA_RETURN_VOID }, - 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 404: { $ref: SCHEMA_NOT_FOUND } - } - } -}; - -fastify.delete<{Querystring: staticQueryUsernameAccount}>(`${PATH_BASE_CONTROLLER}/delete`, options, async (request) => { - const {username} = request.query; - - await accountService.deleteAccount(username); - - return { response: "ok" }; -}); \ No newline at end of file diff --git a/src_refactory/controllers/accountController/findRoute.ts b/src_refactory/controllers/accountController/findRoute.ts deleted file mode 100644 index 459f482..0000000 --- a/src_refactory/controllers/accountController/findRoute.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { RouteShorthandOptions } from "fastify"; - -import { PATH_BASE_CONTROLLER, SCHEMA_RETURN_ACCOUNT, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount } from "../../schemas/accountSchema"; -import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; - -import { AccountService } from "../../applications/services/AccountService"; - -import fastify from "../../server/fastify"; - -const accountService = new AccountService(); - -const options: RouteShorthandOptions = { - schema: { - tags: ["account"], - summary: "Find account", - querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, - response: { - 200: { $ref: SCHEMA_RETURN_ACCOUNT }, - 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 404: { $ref: SCHEMA_NOT_FOUND } - } - } -}; - -fastify.get<{Querystring: staticQueryUsernameAccount}>(`${PATH_BASE_CONTROLLER}/find`, options, async (request) => { - const {username} = request.query; - - return await accountService.findFromUsername(username); -}); \ No newline at end of file diff --git a/src_refactory/controllers/accountController/updateRoute.ts b/src_refactory/controllers/accountController/updateRoute.ts deleted file mode 100644 index 6c73ad9..0000000 --- a/src_refactory/controllers/accountController/updateRoute.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { RouteShorthandOptions } from "fastify"; - -import { PATH_BASE_CONTROLLER, SCHEMA_RETURN_ACCOUNT, SCHEMA_UPDATE_ACCOUNT, SCHEMA_QUERY_USERNAME_ACCOUNT, staticQueryUsernameAccount, staticUpdateAccount } from "../../schemas/accountSchema"; -import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; - -import { AccountService } from "../../applications/services/AccountService"; - -import fastify from "../../server/fastify"; - -const accountService = new AccountService(); - -const options: RouteShorthandOptions = { - schema: { - tags: ["account"], - summary: "Update values of account", - querystring: { $ref: SCHEMA_QUERY_USERNAME_ACCOUNT }, - body: { $ref: SCHEMA_UPDATE_ACCOUNT }, - response: { - 200: { $ref: SCHEMA_RETURN_ACCOUNT }, - 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 404: { $ref: SCHEMA_NOT_FOUND } - } - } -}; - -fastify.put<{Querystring: staticQueryUsernameAccount, Body: staticUpdateAccount}>(`${PATH_BASE_CONTROLLER}/update`, options, async (request) => { - const {username} = request.query; - const account = request.body; - - console.log(request.body); - - return await accountService.updateAccount(username, account); -}); \ No newline at end of file diff --git a/src_refactory/controllers/requestController/actionRoute.ts b/src_refactory/controllers/requestController/actionRoute.ts deleted file mode 100644 index dc0f581..0000000 --- a/src_refactory/controllers/requestController/actionRoute.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { RouteShorthandOptions } from "fastify"; - -import { RequestService } from "../../applications/services/RequestService"; - -import { PATH_BASE_CONTROLLER, SCHEMA_ACTION_REQUEST, staticActionRequest } from "../../schemas/requestSchema"; -import { SCHEMA_INTERNAL_SERVER, SCHEMA_RETURN_VOID } from "../../schemas/generic/genericSchema"; - -import fastify from "../../server/fastify"; - -const requestService = new RequestService(); - -const options: RouteShorthandOptions = { - schema: { - tags: ["request"], - summary: "Choose accept or refuse request friend", - querystring: { $ref: SCHEMA_ACTION_REQUEST }, - response: { - 200: { $ref: SCHEMA_RETURN_VOID }, - 500: { $ref: SCHEMA_INTERNAL_SERVER } - } - } -}; - -fastify.post<{Querystring: staticActionRequest}>(`${PATH_BASE_CONTROLLER}/action`, options, async (request) => { - const {accept, request_from, request_to} = request.query; - - await requestService.action(request_from, request_to, accept); - - return { response: "ok" }; -}); \ No newline at end of file diff --git a/src_refactory/modules/logger.ts b/src_refactory/modules/logger.ts deleted file mode 120000 index 8a88647..0000000 --- a/src_refactory/modules/logger.ts +++ /dev/null @@ -1 +0,0 @@ -../../references/src_refactory/modules/logger.ts \ No newline at end of file diff --git a/src_refactory/schemas/accountSchema.ts b/src_refactory/schemas/accountSchema.ts deleted file mode 100644 index 3ac302f..0000000 --- a/src_refactory/schemas/accountSchema.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Type } from "@sinclair/typebox"; - -import { accountSchema, IAccountEnv } from "../domain/interfaces/models/IAccount"; -import { accountDTOSchema } from "../domain/interfaces/DTOs/IAccountDTO"; -import { convertToOptional } from "../utils/schemaUtils"; - -//path base -const PATH_BASE_CONTROLLER = "/account"; - -//schemas -const SCHEMA_CREATE_ACCOUNT = "SchemaCreateAccount"; -const SCHEMA_UPDATE_ACCOUNT = "SchemaUpdateAccount"; -const SCHEMA_RETURN_ACCOUNT = "SchemaReturnAccount"; -const SCHEMA_QUERY_USERNAME_ACCOUNT = "SchemaQueryUsernameAccount"; - - -//request -const createAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME, IAccountEnv.PASSWORD, IAccountEnv.CHANGE_PASSWORD], { $id: SCHEMA_CREATE_ACCOUNT }); -const updateAccount = convertToOptional(accountSchema, [IAccountEnv.PROFILE, IAccountEnv.CHANGE_PASSWORD], SCHEMA_UPDATE_ACCOUNT); -const queryUsernameAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME], { $id: SCHEMA_QUERY_USERNAME_ACCOUNT }); - -//replay -const returnAccount = Type.Intersect([accountDTOSchema], { $id: SCHEMA_RETURN_ACCOUNT }); - -//load schemas -export default [createAccount, updateAccount, returnAccount, queryUsernameAccount]; - -type staticCreateAccount = typeof createAccount.static -type staticUpdateAccount = typeof updateAccount.static -type staticReturnAccount = typeof returnAccount.static -type staticQueryUsernameAccount = typeof queryUsernameAccount.static; - -export { - PATH_BASE_CONTROLLER, - - staticCreateAccount, - staticUpdateAccount, - staticReturnAccount, - staticQueryUsernameAccount, - - SCHEMA_CREATE_ACCOUNT, - SCHEMA_RETURN_ACCOUNT, - SCHEMA_UPDATE_ACCOUNT, - SCHEMA_QUERY_USERNAME_ACCOUNT -}; \ No newline at end of file diff --git a/src_refactory/schemas/requestSchema.ts b/src_refactory/schemas/requestSchema.ts deleted file mode 100644 index 6a62dbd..0000000 --- a/src_refactory/schemas/requestSchema.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Type } from "@sinclair/typebox"; -import { queryPagination, schemaReturnPagination } from "./generic/paginationSchema"; -import { requestDTOSchema } from "../domain/interfaces/DTOs/IRequestDTO"; -import { IRequestEnv, requestSchema } from "../domain/interfaces/models/IRequest"; - -//path base -const PATH_BASE_CONTROLLER = "/request"; - -//schemas -const SCHEMA_CREATE_REQUEST = "SchemaCreateRequest"; -const SCHEMA_ACTION_REQUEST = "SchemaActionRequest"; -const SCHEMA_RETURN_PAGINATED_REQUEST = "SchemaReturnPaginatedRequest"; -const SCHEMA_QUERY_PAGINATED_REQUEST = "SchemaQueryPaginatedRequest"; - -//request -const createRequest = Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO], { $id: SCHEMA_CREATE_REQUEST }); -const actionRequest = Type.Intersect([ - Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO]), - Type.Object({ - accept: Type.Boolean() - }) -], {$id: SCHEMA_ACTION_REQUEST}); -const queryPaginatedRequest = Type.Intersect([Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM]), queryPagination], {$id: SCHEMA_QUERY_PAGINATED_REQUEST}); - -//replay -const returnPaginatedRequest = schemaReturnPagination(requestDTOSchema, SCHEMA_RETURN_PAGINATED_REQUEST); - -//load schemas -export default [createRequest, actionRequest, returnPaginatedRequest, queryPaginatedRequest]; - -type staticCreateRequest = typeof createRequest.static; -type staticActionRequest = typeof actionRequest.static; -type staticReturnPaginatedRequest = typeof returnPaginatedRequest.static; -type staticQueryPaginatedRequest = typeof queryPaginatedRequest.static; - -export { - PATH_BASE_CONTROLLER, - - staticCreateRequest, - staticActionRequest, - staticReturnPaginatedRequest, - staticQueryPaginatedRequest, - - SCHEMA_CREATE_REQUEST, - SCHEMA_ACTION_REQUEST, - SCHEMA_RETURN_PAGINATED_REQUEST, - SCHEMA_QUERY_PAGINATED_REQUEST -}; \ No newline at end of file From 2d1e342933cb6d3289bd341abde1e58785aaa110 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 15:50:02 +0200 Subject: [PATCH 12/21] Add basic unit test when launch PR --- .github/workflows/unit-test.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/unit-test.yml diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml new file mode 100644 index 0000000..1b50f47 --- /dev/null +++ b/.github/workflows/unit-test.yml @@ -0,0 +1,24 @@ +name: On Pull Request Opened + +on: + pull_request: + branches: + - main + - dev +jobs: + test: + runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Set CWD + run: cd src + + - name: Install packages + run: npm i + + - name: Check syntax code + run: npm run eslint \ No newline at end of file From 73fb3a5d8097c0dab2c3b7bc577e46fd54bd5681 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 15:57:55 +0200 Subject: [PATCH 13/21] Fix workflows unit test --- .github/workflows/unit-test.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 1b50f47..e80121f 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -2,12 +2,13 @@ name: On Pull Request Opened on: pull_request: - branches: - - main - - dev + types: [opened, synchronize, reopened] + jobs: test: - runs-on: ubuntu-latest steps: + runs-on: ubuntu-latest + + steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v4 From 02c872f3249dc4d55ab8283a905a1734b2916035 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 16:00:08 +0200 Subject: [PATCH 14/21] Fix workflows unit test --- .github/workflows/unit-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index e80121f..ca47f61 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -16,7 +16,7 @@ jobs: node-version: 22 - name: Set CWD - run: cd src + run: cd ./src - name: Install packages run: npm i From b18a8220a198b30fd3f419cae353f04821208a3a Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 16:04:22 +0200 Subject: [PATCH 15/21] test --- .github/workflows/unit-test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index ca47f61..f3b1a71 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -14,7 +14,10 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 22 - + + - name: Print working directory + run: ls -l + - name: Set CWD run: cd ./src From 60b8c585e36e56d6f5f7b8214b1f988a51845c62 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 16:07:39 +0200 Subject: [PATCH 16/21] fix set directory for workflows unit test --- .github/workflows/unit-test.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index f3b1a71..0710e97 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -8,6 +8,10 @@ jobs: test: runs-on: ubuntu-latest + defaults: + run: + working-directory: ./src + steps: - uses: actions/checkout@v3 @@ -16,10 +20,7 @@ jobs: node-version: 22 - name: Print working directory - run: ls -l - - - name: Set CWD - run: cd ./src + run: pwd - name: Install packages run: npm i From 10bf8753e7963d4b7c3017765ef8076f2fa3a009 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 16:09:12 +0200 Subject: [PATCH 17/21] Definitive unit test --- .github/workflows/unit-test.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 0710e97..50a9644 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -18,9 +18,6 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 22 - - - name: Print working directory - run: pwd - name: Install packages run: npm i From 47a64a98eae42813655b138b2d598ace99fcc35c Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 16:10:54 +0200 Subject: [PATCH 18/21] Create error for PR --- src/package.json | 2 +- src/utils/accountUtils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/package.json b/src/package.json index 6d2a47d..fd284f3 100644 --- a/src/package.json +++ b/src/package.json @@ -32,7 +32,7 @@ "luxon": "^3.5.0", "pg": "^8.12.0", "typeorm": "^0.3.20", - "typescript": "^5.5.4", + "typescript": "5.6.0", "@eslint/js": "^9.11.0", "@types/lodash": "^4.17.7", "@types/luxon": "^3.4.2", diff --git a/src/utils/accountUtils.ts b/src/utils/accountUtils.ts index 346a933..27c430e 100644 --- a/src/utils/accountUtils.ts +++ b/src/utils/accountUtils.ts @@ -1,4 +1,4 @@ -import CryptoJS from "crypto-js"; +import CryptoJS from 'crypto-js'; function hashPassword(password: string){ return CryptoJS.SHA256(password).toString(); From 31d4c63ec4eb4fcfb4f29fe666f8051b7bc107ef Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 16:13:14 +0200 Subject: [PATCH 19/21] fix package --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index fd284f3..8250356 100644 --- a/src/package.json +++ b/src/package.json @@ -32,7 +32,7 @@ "luxon": "^3.5.0", "pg": "^8.12.0", "typeorm": "^0.3.20", - "typescript": "5.6.0", + "typescript": "5.5.4", "@eslint/js": "^9.11.0", "@types/lodash": "^4.17.7", "@types/luxon": "^3.4.2", From 06a54724c1b469d22bbaf2fcf8fd4cc55f354926 Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sat, 21 Sep 2024 16:15:12 +0200 Subject: [PATCH 20/21] Correct error and PR is correct --- src/utils/accountUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/accountUtils.ts b/src/utils/accountUtils.ts index 27c430e..346a933 100644 --- a/src/utils/accountUtils.ts +++ b/src/utils/accountUtils.ts @@ -1,4 +1,4 @@ -import CryptoJS from 'crypto-js'; +import CryptoJS from "crypto-js"; function hashPassword(password: string){ return CryptoJS.SHA256(password).toString(); From 7dabb61a57d6898d62e8ea1aac323f93e39c666d Mon Sep 17 00:00:00 2001 From: cesxhin Date: Sun, 22 Sep 2024 08:25:00 +0200 Subject: [PATCH 21/21] Add controller friend, fix improvment general, improvment eslint and add typecheck for unit test --- .github/workflows/unit-test.yml | 5 +- .../repositories/IAccountRepository.ts | 2 +- .../repositories/IFriendRepository.ts | 15 +++ .../repositories/IRequestRepository.ts | 3 +- .../interfaces/services/IFriendService.ts | 9 ++ .../interfaces/services/IRequestService.ts | 16 +-- .../repositories/FriendRepository.ts | 79 ++++++++++++++ .../repositories/RequestRepository.ts | 52 +++++---- src/applications/services/FriendService.ts | 31 ++++++ src/applications/services/RequestService.ts | 100 ++++++++++++++---- .../accountController/createRoute.ts | 6 +- .../accountController/deleteRoute.ts | 9 +- .../accountController/findRoute.ts | 9 +- .../accountController/updateRoute.ts | 9 +- src/controllers/friendController/listRoute.ts | 24 +++++ .../friendController/removeRoute.ts | 26 +++++ .../requestController/actionRoute.ts | 4 +- .../requestController/createRoute.ts | 7 +- ...listRoute.ts => listRequestActionRoute.ts} | 8 +- .../requestController/listRequestWaitRoute.ts | 24 +++++ .../requestController/removeRoute.ts | 26 +++++ src/domain/interfaces/DTOs/IAccountDTO.ts | 4 +- src/domain/interfaces/DTOs/IFriendDTO.ts | 15 +++ src/domain/interfaces/models/IAccount.ts | 4 +- src/domain/interfaces/models/IFriend.ts | 15 +++ src/domain/models/Account.ts | 4 +- src/domain/models/Friends.ts | 16 +++ src/domain/models/Request.ts | 4 +- src/eslint.config.js | 2 +- src/package.json | 1 + src/schemas/accountSchema.ts | 3 +- src/schemas/friendSchema.ts | 35 ++++++ src/schemas/generic/authSchema.ts | 15 +++ src/schemas/generic/genericSchema.ts | 35 +++--- src/schemas/generic/paginationSchema.ts | 10 +- src/schemas/requestSchema.ts | 18 +++- src/server/fastify/index.ts | 2 +- 37 files changed, 541 insertions(+), 106 deletions(-) create mode 100644 src/applications/interfaces/repositories/IFriendRepository.ts create mode 100644 src/applications/interfaces/services/IFriendService.ts create mode 100644 src/applications/repositories/FriendRepository.ts create mode 100644 src/applications/services/FriendService.ts create mode 100644 src/controllers/friendController/listRoute.ts create mode 100644 src/controllers/friendController/removeRoute.ts rename src/controllers/requestController/{listRoute.ts => listRequestActionRoute.ts} (73%) create mode 100644 src/controllers/requestController/listRequestWaitRoute.ts create mode 100644 src/controllers/requestController/removeRoute.ts create mode 100644 src/domain/interfaces/DTOs/IFriendDTO.ts create mode 100644 src/domain/interfaces/models/IFriend.ts create mode 100644 src/domain/models/Friends.ts create mode 100644 src/schemas/friendSchema.ts create mode 100644 src/schemas/generic/authSchema.ts diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 50a9644..37f01a9 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -23,4 +23,7 @@ jobs: run: npm i - name: Check syntax code - run: npm run eslint \ No newline at end of file + run: npm run eslint + + - name: Check typescript + run: npm run typecheck \ No newline at end of file diff --git a/src/applications/interfaces/repositories/IAccountRepository.ts b/src/applications/interfaces/repositories/IAccountRepository.ts index 09d0a4c..1d6490c 100644 --- a/src/applications/interfaces/repositories/IAccountRepository.ts +++ b/src/applications/interfaces/repositories/IAccountRepository.ts @@ -9,5 +9,5 @@ export default interface IAccountRepository extends IConnectionRepository): Promise; //delete - deleteAccount(username: string): void; + deleteAccount(username: string): Promise; } // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src/applications/interfaces/repositories/IFriendRepository.ts b/src/applications/interfaces/repositories/IFriendRepository.ts new file mode 100644 index 0000000..191cd63 --- /dev/null +++ b/src/applications/interfaces/repositories/IFriendRepository.ts @@ -0,0 +1,15 @@ +import { IFriend } from "../../../domain/interfaces/models/IFriend"; +import IConnectionRepository from "./generic/IConnectionRepository"; + +export default interface IFriendRepository extends IConnectionRepository{ + //get + findByFriend(username: string, friend: string): Promise; + listPaginated(username: string, skip: number, length: number): Promise>; + countTotalFromUsername(username: string): Promise; + + //put + createFriend(data: Partial): Promise; + + //delete + deleteFriend(username: string, friend: string): Promise; +} // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src/applications/interfaces/repositories/IRequestRepository.ts b/src/applications/interfaces/repositories/IRequestRepository.ts index 9976dc4..7abd8a2 100644 --- a/src/applications/interfaces/repositories/IRequestRepository.ts +++ b/src/applications/interfaces/repositories/IRequestRepository.ts @@ -5,7 +5,8 @@ import IConnectionRepository from "./generic/IConnectionRepository"; export default interface IRequestRepository extends IConnectionRepository { //get findByRequest(request_from: string, request_to: string): Promise - listPaginated(request_from: string, skip: number, length: number): Promise> + listPaginatedFromRequestFrom(request_from: string, skip: number, length: number): Promise> + listPaginatedFromRequestTo(request_to: string, skip: number, length: number): Promise> countTotalFromRequestFrom(request_from: string): Promise //put diff --git a/src/applications/interfaces/services/IFriendService.ts b/src/applications/interfaces/services/IFriendService.ts new file mode 100644 index 0000000..1c9b9c4 --- /dev/null +++ b/src/applications/interfaces/services/IFriendService.ts @@ -0,0 +1,9 @@ +import { ISchemaReturnPaginatedFriend } from "../../../schemas/friendSchema"; + +export default interface IFriendService { + //get + listPaginated(username: string, skip: number, length: number): Promise; + + //delete + deleteFriend(username: string, friend: string): Promise; +} // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src/applications/interfaces/services/IRequestService.ts b/src/applications/interfaces/services/IRequestService.ts index f625564..7f6c783 100644 --- a/src/applications/interfaces/services/IRequestService.ts +++ b/src/applications/interfaces/services/IRequestService.ts @@ -1,13 +1,15 @@ -import { IRequest } from "../../../domain/interfaces/models/IRequest"; -import { staticReturnPaginatedRequest } from "../../../schemas/requestSchema"; +import { ISchemaReturnPaginatedRequest } from "../../../schemas/requestSchema"; export default interface IRequestService { //get - listPaginated(request_from: string, skip: number, length: number): Promise + listRequestWaitPaginated(request_from: string, skip: number, length: number): Promise + listRequestForActionPaginated(request_to: string, skip: number, length: number): Promise - //put - create(data: Partial): Promise - //post - action(request_from: string, request_to: string, accept: boolean): Promise + create(auth_username: string, request_to: string): Promise + action(request_from: string, auth_username: string, accept: boolean): Promise + + //delete + delete(auth_username: string, request_to: string): Promise + } // eslint-disable-line @stylistic/semi \ No newline at end of file diff --git a/src/applications/repositories/FriendRepository.ts b/src/applications/repositories/FriendRepository.ts new file mode 100644 index 0000000..d426335 --- /dev/null +++ b/src/applications/repositories/FriendRepository.ts @@ -0,0 +1,79 @@ +import { DeleteResult } from "typeorm"; + +import {pg} from "../../server/postgres"; +import { ApiErrorGeneric, ApiNotFound } from "../../modules/api"; + +import IFriendRepository from "../interfaces/repositories/IFriendRepository"; + +import { IFriend, IFriendEnv } from "../../domain/interfaces/models/IFriend"; +import { Friend } from "../../domain/models/Friends"; + +import Logger from "../../modules/logger"; +const logger = new Logger("friend-db"); + +export default class FriendRepository implements IFriendRepository { + connectionRepository = pg.getRepository(Friend); + + //get + async findByFriend(username: string, friend: string): Promise { + let rs: IFriend | null = null; + + try { + rs = await this.connectionRepository.findOneBy({[IFriendEnv.USERNAME]: username, [IFriendEnv.FRIEND]: friend }); + } catch (err){ + logger.error("Failed exec query findByFriend, details:", err); + throw new ApiErrorGeneric(err); + } + + if (rs === null){ + throw new ApiNotFound(`Not found friend: ${friend}`); + } + + return rs; + } + async listPaginated(username: string, skip: number, length: number): Promise> { + let rs: Array = []; + + try { + rs = await this.connectionRepository.find({ where: { [IFriendEnv.USERNAME]: username }, order: { [IFriendEnv.BECOME_FRIEND_TIME]: "DESC" }, skip, take: length }); + } catch (err){ + logger.error("Failed exec query listPaginated, details:", err); + throw new ApiErrorGeneric(err); + } + + return rs; + } + async countTotalFromUsername(username: string): Promise { + try { + return await this.connectionRepository.countBy({ [IFriendEnv.USERNAME]: username }); + } catch (err){ + logger.error("Failed exec query countTotal, details:", err); + throw new ApiErrorGeneric(err); + } + } + + //post + async createFriend(data: Partial): Promise { + try { + await this.connectionRepository.insert(data); + } catch (err){ + logger.error("Failed exec query createFriend, details:", err); + throw new ApiErrorGeneric(err); + } + } + + //delete + async deleteFriend(username: string, friend: string): Promise { + let rs: DeleteResult; + try { + rs = await this.connectionRepository.delete({ [IFriendEnv.FRIEND]: friend, [IFriendEnv.USERNAME]: username }); + } catch (err){ + logger.error("Failed exec query deleteFriend, details:", err); + throw new ApiErrorGeneric(err); + } + + if (rs.affected <= 0){ + throw new ApiNotFound(`Cannot delete friend ${friend}`); + } + } +} \ No newline at end of file diff --git a/src/applications/repositories/RequestRepository.ts b/src/applications/repositories/RequestRepository.ts index 861f855..b1c55a0 100644 --- a/src/applications/repositories/RequestRepository.ts +++ b/src/applications/repositories/RequestRepository.ts @@ -14,6 +14,7 @@ const logger = new Logger("request-db"); export default class RequestRepository implements IRequestRepository { connectionRepository = pg.getRepository(Request); + //get async findByRequest(request_from: string, request_to: string): Promise { let request: IRequest; try { @@ -29,33 +30,23 @@ export default class RequestRepository implements IRequestRepository { return request; } - async create(data: Partial): Promise { - try { - await this.connectionRepository.insert(data); - } catch (err){ - logger.error("Failed exec query create, details:", err); - throw new ApiErrorGeneric(err); - } - } - async delete(request_from: string, request_to: string): Promise { - let rs: DeleteResult; + async listPaginatedFromRequestFrom(request_from: string, skip: number = 0, length: number = 10): Promise> { + let rs: Array = []; try { - rs = await this.connectionRepository.delete({[IRequestEnv.REQUEST_FROM]: request_from, [IRequestEnv.REQUEST_TO]: request_to}); + rs = await this.connectionRepository.find({where: {[IRequestEnv.REQUEST_FROM]: request_from}, order: {[IRequestEnv.REQUEST_TIME]: "ASC"}, skip, take: length}); } catch (err){ - logger.error("Failed exec query delete, details:", err); + logger.error("Failed exec query listPaginatedFromRequestFrom, details:", err); throw new ApiErrorGeneric(err); } - if (rs.affected <= 0){ - throw new ApiNotFound(`Cannot delete request with request_from: "${request_from}" request_to: "${request_to}"`); - } + return rs; } - async listPaginated(request_from: string, skip: number = 0, length: number = 10): Promise> { + async listPaginatedFromRequestTo(request_to: string, skip: number = 0, length: number = 10): Promise> { let rs: Array = []; try { - rs = await this.connectionRepository.find({where: {[IRequestEnv.REQUEST_FROM]: request_from}, order: {[IRequestEnv.REQUEST_TIME]: "ASC"}, skip, take: length}); + rs = await this.connectionRepository.find({where: {[IRequestEnv.REQUEST_TO]: request_to}, order: {[IRequestEnv.REQUEST_TIME]: "ASC"}, skip, take: length}); } catch (err){ - logger.error("Failed exec query listPaginated, details:", err); + logger.error("Failed exec query listPaginatedFromRequestTo, details:", err); throw new ApiErrorGeneric(err); } @@ -69,4 +60,29 @@ export default class RequestRepository implements IRequestRepository { throw new ApiErrorGeneric(err); } } + + //put + async create(data: Partial): Promise { + try { + await this.connectionRepository.insert(data); + } catch (err){ + logger.error("Failed exec query create, details:", err); + throw new ApiErrorGeneric(err); + } + } + + //delete + async delete(request_from: string, request_to: string): Promise { + let rs: DeleteResult; + try { + rs = await this.connectionRepository.delete({[IRequestEnv.REQUEST_FROM]: request_from, [IRequestEnv.REQUEST_TO]: request_to}); + } catch (err){ + logger.error("Failed exec query delete, details:", err); + throw new ApiErrorGeneric(err); + } + + if (rs.affected <= 0){ + throw new ApiNotFound(`Cannot delete request with request_from: "${request_from}" request_to: "${request_to}"`); + } + } } \ No newline at end of file diff --git a/src/applications/services/FriendService.ts b/src/applications/services/FriendService.ts new file mode 100644 index 0000000..5ad1a62 --- /dev/null +++ b/src/applications/services/FriendService.ts @@ -0,0 +1,31 @@ +import async from "async"; + +import { objectAssign } from "../../utils/genericUtils"; + +import FriendRepository from "../repositories/FriendRepository"; +import IFriendService from "../interfaces/services/IFriendService"; + +import { ISchemaReturnPaginatedFriend } from "../../schemas/friendSchema"; +import { IFriendDTO, IFriendDTOEnv } from "../../domain/interfaces/DTOs/IFriendDTO"; + +export class FriendService implements IFriendService { + friendRepository = new FriendRepository(); + + //get + async listPaginated(username: string, skip: number, length: number): Promise { + const {count, list} = await async.parallel, count: number}>({ + list: async () => (await this.friendRepository.listPaginated(username, skip, length)).map((reqeust) => objectAssign(reqeust, IFriendDTOEnv)), + count: async () => await this.friendRepository.countTotalFromUsername(username) + }); + + return { + list, + max_count: count + }; + } + + //delete + async deleteFriend(username: string, friend: string): Promise { + this.friendRepository.deleteFriend(username, friend); + } +} \ No newline at end of file diff --git a/src/applications/services/RequestService.ts b/src/applications/services/RequestService.ts index 914bd95..3a70868 100644 --- a/src/applications/services/RequestService.ts +++ b/src/applications/services/RequestService.ts @@ -1,29 +1,62 @@ +import async from "async"; + import { ApiBadRequest, ApiConflict, ApiNotFound } from "../../modules/api"; import { objectAssign } from "../../utils/genericUtils"; -import { IRequestDTO, IRequestDTOEnv } from "../../domain/interfaces/DTOs/IRequestDTO"; import { IRequest, IRequestEnv } from "../../domain/interfaces/models/IRequest"; +import { IRequestDTO, IRequestDTOEnv } from "../../domain/interfaces/DTOs/IRequestDTO"; + +import { ISchemaReturnPaginatedRequest } from "../../schemas/requestSchema"; import IRequestService from "../interfaces/services/IRequestService"; + +import FriendRepository from "../repositories/FriendRepository"; import RequestRepository from "../repositories/RequestRepository"; -import async from "async"; -import { staticReturnPaginatedRequest } from "../../schemas/requestSchema"; import AccountRepository from "../repositories/AccountRepository"; +import { IFriend, IFriendEnv } from "../../domain/interfaces/models/IFriend"; export class RequestService implements IRequestService { requestRepository = new RequestRepository(); accountRepository = new AccountRepository(); + friendRepository = new FriendRepository(); + + //get + async listRequestWaitPaginated(request_from: string, skip: number, length: number): Promise { + const {count, list} = await async.parallel, count: number}>({ + list: async () => (await this.requestRepository.listPaginatedFromRequestFrom(request_from, skip, length)).map((reqeust) => objectAssign(reqeust, IRequestDTOEnv)), + count: async () => await this.requestRepository.countTotalFromRequestFrom(request_from) + }); + + return { + list, + max_count: count + }; + } + async listRequestForActionPaginated(request_to: string, skip: number, length: number): Promise { + const {count, list} = await async.parallel, count: number}>({ + list: async () => (await this.requestRepository.listPaginatedFromRequestTo(request_to, skip, length)).map((reqeust) => objectAssign(reqeust, IRequestDTOEnv)), + count: async () => await this.requestRepository.countTotalFromRequestFrom(request_to) + }); + + return { + list, + max_count: count + }; + } + + //post + async create(auth_username: string, request_to: string): Promise { + request_to = request_to.toLowerCase(); - async create(data: Partial): Promise { - if (data[IRequestEnv.REQUEST_FROM].toLowerCase() === data[IRequestEnv.REQUEST_TO].toLowerCase()){ + if (auth_username === request_to){ throw new ApiBadRequest(`${IRequestEnv.REQUEST_FROM} cannot be same ${IRequestEnv.REQUEST_TO}`); } - const {findRequest, findRequestTO} = await async.parallel({ + const {findRequest, findRequestTO, alreadyFriend} = await async.parallel({ findRequest: async () => { try { - await this.requestRepository.findByRequest(data[IRequestEnv.REQUEST_FROM], data[IRequestEnv.REQUEST_TO]); + await this.requestRepository.findByRequest(auth_username, request_to); } catch (err){ if (err instanceof ApiNotFound){ return false; @@ -36,7 +69,7 @@ export class RequestService implements IRequestService { }, findRequestTO: async () => { try { - await this.accountRepository.findFromUsername(data[IRequestEnv.REQUEST_TO]); + await this.accountRepository.findFromUsername(request_to); } catch (err){ if (err instanceof ApiNotFound){ return false; @@ -46,30 +79,51 @@ export class RequestService implements IRequestService { } return true; + }, + alreadyFriend: async () => { + try { + await this.friendRepository.findByFriend(auth_username, request_to); + } catch (err){ + if (err instanceof ApiNotFound){ + return false; + } else { + throw new err; + } + } + + return true; } }); - if (!findRequest && findRequestTO){ + if (!findRequest && findRequestTO && !alreadyFriend){ + const data: Partial = { + [IRequestEnv.REQUEST_FROM]: auth_username, + [IRequestEnv.REQUEST_TO]: request_to + }; return await this.requestRepository.create(data); } else if (!findRequestTO){ - throw new ApiNotFound(`The user "${data[IRequestEnv.REQUEST_TO]}" not exist!`); + throw new ApiNotFound(`The user "${request_to}" not exist!`); + } else if (alreadyFriend){ + throw new ApiConflict("He is already your friend"); } else { throw new ApiConflict("The request to become a friend has already been sent"); } } - action(request_from: string, request_to: string, accept: boolean): Promise { - //todo table friends - throw new Error("Method not implemented."); - } - async listPaginated(request_from: string, skip: number, length: number): Promise { - const {count, list} = await async.parallel, count: number}>({ - list: async () => (await this.requestRepository.listPaginated(request_from, skip, length)).map((reqeust) => objectAssign(reqeust, IRequestDTOEnv)), - count: async () => await this.requestRepository.countTotalFromRequestFrom(request_from) - }); + async action(request_from: string, auth_username: string, accept: boolean): Promise { + await this.requestRepository.findByRequest(request_from, auth_username); + + if (accept){ + const data: Partial = { + [IFriendEnv.USERNAME]: request_from, + [IFriendEnv.FRIEND]: auth_username + }; - return { - list, - max_count: count - }; + await this.friendRepository.createFriend(data); + } + + await this.requestRepository.delete(request_from, auth_username); + } + async delete(auth_username: string, request_to: string): Promise { + await this.requestRepository.delete(auth_username, request_to); } } \ No newline at end of file diff --git a/src/controllers/accountController/createRoute.ts b/src/controllers/accountController/createRoute.ts index c263c11..1f861c9 100644 --- a/src/controllers/accountController/createRoute.ts +++ b/src/controllers/accountController/createRoute.ts @@ -1,5 +1,5 @@ import { PATH_BASE_CONTROLLER, schemaCreateAccount, schemaReturnAccount } from "../../schemas/accountSchema"; -import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; +import { SCHEMA_BAD_REQUEST, SCHEMA_CONFLICT, SCHEMA_INTERNAL_SERVER, SCHEMA_UNAUTHORIZED } from "../../schemas/generic/genericSchema"; import { AccountService } from "../../applications/services/AccountService"; @@ -15,7 +15,9 @@ fastify.post(`${PATH_BASE_CONTROLLER}/create`, { response: { 200: schemaReturnAccount, 500: { $ref: SCHEMA_INTERNAL_SERVER }, - 401: { $ref: SCHEMA_BAD_REQUEST } + 400: { $ref: SCHEMA_BAD_REQUEST }, + 409: { $ref: SCHEMA_CONFLICT }, + 401: { $ref: SCHEMA_UNAUTHORIZED } } } }, async (request, replay) => replay.status(200).send(await accountService.createAccount(request.body))); \ No newline at end of file diff --git a/src/controllers/accountController/deleteRoute.ts b/src/controllers/accountController/deleteRoute.ts index 76107ac..bc59929 100644 --- a/src/controllers/accountController/deleteRoute.ts +++ b/src/controllers/accountController/deleteRoute.ts @@ -1,9 +1,10 @@ import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, schemaReturnVoid } from "../../schemas/generic/genericSchema"; -import { PATH_BASE_CONTROLLER, schemaQueryUsernameAccount} from "../../schemas/accountSchema"; +import { PATH_BASE_CONTROLLER} from "../../schemas/accountSchema"; import { AccountService } from "../../applications/services/AccountService"; import fastify from "../../server/fastify"; +import { schemaQueryUsernameAuth } from "../../schemas/generic/authSchema"; const accountService = new AccountService(); @@ -11,7 +12,7 @@ fastify.delete(`${PATH_BASE_CONTROLLER}/delete`, { schema: { tags: ["account"], summary: "Delete account", - querystring: schemaQueryUsernameAccount, + querystring: schemaQueryUsernameAuth, response: { 200: schemaReturnVoid, 500: { $ref: SCHEMA_INTERNAL_SERVER }, @@ -19,9 +20,9 @@ fastify.delete(`${PATH_BASE_CONTROLLER}/delete`, { } } }, async (request, replay) => { - const {username} = request.query; + const {auth_username} = request.query; - await accountService.deleteAccount(username); + await accountService.deleteAccount(auth_username); replay.status(200).send({ response: "ok" }); }); \ No newline at end of file diff --git a/src/controllers/accountController/findRoute.ts b/src/controllers/accountController/findRoute.ts index a9d29d3..a156bcd 100644 --- a/src/controllers/accountController/findRoute.ts +++ b/src/controllers/accountController/findRoute.ts @@ -1,9 +1,10 @@ -import { PATH_BASE_CONTROLLER, schemaQueryUsernameAccount, schemaReturnAccount } from "../../schemas/accountSchema"; +import { PATH_BASE_CONTROLLER, schemaReturnAccount } from "../../schemas/accountSchema"; import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; import { AccountService } from "../../applications/services/AccountService"; import fastify from "../../server/fastify"; +import { schemaQueryUsernameAuth } from "../../schemas/generic/authSchema"; const accountService = new AccountService(); @@ -11,7 +12,7 @@ fastify.get(`${PATH_BASE_CONTROLLER}/find`, { schema: { tags: ["account"], summary: "Find account", - querystring: schemaQueryUsernameAccount, + querystring: schemaQueryUsernameAuth, response: { 200: schemaReturnAccount, 500: { $ref: SCHEMA_INTERNAL_SERVER }, @@ -19,7 +20,7 @@ fastify.get(`${PATH_BASE_CONTROLLER}/find`, { } } }, async (request, replay) => { - const {username} = request.query; + const {auth_username} = request.query; - replay.status(200).send(await accountService.findFromUsername(username)); + replay.status(200).send(await accountService.findFromUsername(auth_username)); }); \ No newline at end of file diff --git a/src/controllers/accountController/updateRoute.ts b/src/controllers/accountController/updateRoute.ts index 9e167e9..bb4eb23 100644 --- a/src/controllers/accountController/updateRoute.ts +++ b/src/controllers/accountController/updateRoute.ts @@ -1,9 +1,10 @@ -import { PATH_BASE_CONTROLLER, schemaQueryUsernameAccount, schemaUpdateAccount, schemaReturnAccount } from "../../schemas/accountSchema"; +import { PATH_BASE_CONTROLLER, schemaUpdateAccount, schemaReturnAccount } from "../../schemas/accountSchema"; import { SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND } from "../../schemas/generic/genericSchema"; import { AccountService } from "../../applications/services/AccountService"; import fastify from "../../server/fastify"; +import { schemaQueryUsernameAuth } from "../../schemas/generic/authSchema"; const accountService = new AccountService(); @@ -11,7 +12,7 @@ fastify.put(`${PATH_BASE_CONTROLLER}/update`, { schema: { tags: ["account"], summary: "Update values of account", - querystring: schemaQueryUsernameAccount, + querystring: schemaQueryUsernameAuth, body: schemaUpdateAccount, response: { 200: schemaReturnAccount, @@ -20,8 +21,8 @@ fastify.put(`${PATH_BASE_CONTROLLER}/update`, { } } }, async (request, replay) => { - const {username} = request.query; + const {auth_username} = request.query; const account = request.body; - replay.status(200).send(await accountService.updateAccount(username, account)); + replay.status(200).send(await accountService.updateAccount(auth_username, account)); }); \ No newline at end of file diff --git a/src/controllers/friendController/listRoute.ts b/src/controllers/friendController/listRoute.ts new file mode 100644 index 0000000..a072933 --- /dev/null +++ b/src/controllers/friendController/listRoute.ts @@ -0,0 +1,24 @@ +import { FriendService } from "../../applications/services/FriendService"; + +import { PATH_BASE_CONTROLLER, schemaQueryPaginatedFriend, schemaReturnPaginatedFriend } from "../../schemas/friendSchema"; +import { SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; + +const friendService = new FriendService(); + +fastify.get(`${PATH_BASE_CONTROLLER}/list`, { + schema: { + tags: ["friend"], + summary: "List my friends", + querystring: schemaQueryPaginatedFriend, + response: { + 200: schemaReturnPaginatedFriend, + 500: { $ref: SCHEMA_INTERNAL_SERVER } + } + } +}, async (request, replay) => { + const {length, skip, auth_username} = request.query; + + replay.status(200).send(await friendService.listPaginated(auth_username, skip, length)); +}); \ No newline at end of file diff --git a/src/controllers/friendController/removeRoute.ts b/src/controllers/friendController/removeRoute.ts new file mode 100644 index 0000000..cc7eeeb --- /dev/null +++ b/src/controllers/friendController/removeRoute.ts @@ -0,0 +1,26 @@ +import { FriendService } from "../../applications/services/FriendService"; + +import { PATH_BASE_CONTROLLER, schemaQueryUsernameOfFriend } from "../../schemas/friendSchema"; +import { SCHEMA_INTERNAL_SERVER, schemaReturnVoid } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; + +const friendService = new FriendService(); + +fastify.delete(`${PATH_BASE_CONTROLLER}/remove`, { + schema: { + tags: ["friend"], + summary: "Remove my friend", + querystring: schemaQueryUsernameOfFriend, + response: { + 200: schemaReturnVoid, + 500: { $ref: SCHEMA_INTERNAL_SERVER } + } + } +}, async (request, replay) => { + const {friend, auth_username} = request.query; + + await friendService.deleteFriend(auth_username, friend); + + replay.status(200).send({ response: "ok" }); +}); \ No newline at end of file diff --git a/src/controllers/requestController/actionRoute.ts b/src/controllers/requestController/actionRoute.ts index 515b143..42bc74b 100644 --- a/src/controllers/requestController/actionRoute.ts +++ b/src/controllers/requestController/actionRoute.ts @@ -18,9 +18,9 @@ fastify.post(`${PATH_BASE_CONTROLLER}/action`, { } } }, async (request, replay) => { - const {accept, request_from, request_to} = request.query; + const {accept, request_from, auth_username} = request.query; - await requestService.action(request_from, request_to, accept); + await requestService.action(request_from, auth_username, accept); replay.status(200).send({ response: "ok" }); }); \ No newline at end of file diff --git a/src/controllers/requestController/createRoute.ts b/src/controllers/requestController/createRoute.ts index 50ebf7e..cf30f05 100644 --- a/src/controllers/requestController/createRoute.ts +++ b/src/controllers/requestController/createRoute.ts @@ -4,6 +4,7 @@ import { PATH_BASE_CONTROLLER, schemaCreateRequest } from "../../schemas/request import { SCHEMA_BAD_REQUEST, SCHEMA_INTERNAL_SERVER, SCHEMA_NOT_FOUND, schemaReturnVoid } from "../../schemas/generic/genericSchema"; import fastify from "../../server/fastify"; +import { schemaQueryUsernameAuth } from "../../schemas/generic/authSchema"; const requestService = new RequestService(); @@ -11,6 +12,7 @@ fastify.post(`${PATH_BASE_CONTROLLER}/create`, { schema: { tags: ["request"], summary: "Create request friend", + querystring: schemaQueryUsernameAuth, body: schemaCreateRequest, response: { 200: schemaReturnVoid, @@ -20,7 +22,10 @@ fastify.post(`${PATH_BASE_CONTROLLER}/create`, { } } }, async (request, replay) => { - await requestService.create(request.body); + const {auth_username} = request.query; + const {request_to} = request.body; + + await requestService.create(auth_username, request_to); replay.status(200).send({ response: "ok" }); }); \ No newline at end of file diff --git a/src/controllers/requestController/listRoute.ts b/src/controllers/requestController/listRequestActionRoute.ts similarity index 73% rename from src/controllers/requestController/listRoute.ts rename to src/controllers/requestController/listRequestActionRoute.ts index d520bd5..dc59f08 100644 --- a/src/controllers/requestController/listRoute.ts +++ b/src/controllers/requestController/listRequestActionRoute.ts @@ -1,5 +1,3 @@ -import { RouteShorthandOptions } from "fastify"; - import { RequestService } from "../../applications/services/RequestService"; import { PATH_BASE_CONTROLLER, schemaQueryPaginatedRequest, schemaReturnPaginatedRequest } from "../../schemas/requestSchema"; @@ -9,7 +7,7 @@ import fastify from "../../server/fastify"; const requestService = new RequestService(); -fastify.get(`${PATH_BASE_CONTROLLER}/list`, { +fastify.get(`${PATH_BASE_CONTROLLER}/list_request_for_action`, { schema: { tags: ["request"], summary: "List request for accept or reject", @@ -20,7 +18,7 @@ fastify.get(`${PATH_BASE_CONTROLLER}/list`, { } } }, async (request, replay) => { - const {length, request_from, skip} = request.query; + const {length, auth_username, skip} = request.query; - replay.status(200).send(await requestService.listPaginated(request_from, skip, length)); + replay.status(200).send(await requestService.listRequestForActionPaginated(auth_username, skip, length)); }); \ No newline at end of file diff --git a/src/controllers/requestController/listRequestWaitRoute.ts b/src/controllers/requestController/listRequestWaitRoute.ts new file mode 100644 index 0000000..60ae146 --- /dev/null +++ b/src/controllers/requestController/listRequestWaitRoute.ts @@ -0,0 +1,24 @@ +import { RequestService } from "../../applications/services/RequestService"; + +import { PATH_BASE_CONTROLLER, schemaQueryPaginatedRequest, schemaReturnPaginatedRequest } from "../../schemas/requestSchema"; +import { SCHEMA_INTERNAL_SERVER } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; + +const requestService = new RequestService(); + +fastify.get(`${PATH_BASE_CONTROLLER}/list_request_wait`, { + schema: { + tags: ["request"], + summary: "List your request", + querystring: schemaQueryPaginatedRequest, + response: { + 200: schemaReturnPaginatedRequest, + 500: { $ref: SCHEMA_INTERNAL_SERVER } + } + } +}, async (request, replay) => { + const {length, auth_username, skip} = request.query; + + replay.status(200).send(await requestService.listRequestWaitPaginated(auth_username, skip, length)); +}); \ No newline at end of file diff --git a/src/controllers/requestController/removeRoute.ts b/src/controllers/requestController/removeRoute.ts new file mode 100644 index 0000000..e72ee89 --- /dev/null +++ b/src/controllers/requestController/removeRoute.ts @@ -0,0 +1,26 @@ +import { RequestService } from "../../applications/services/RequestService"; + +import { PATH_BASE_CONTROLLER, schemaQueryDeleteRequest } from "../../schemas/requestSchema"; +import { SCHEMA_INTERNAL_SERVER, schemaReturnVoid } from "../../schemas/generic/genericSchema"; + +import fastify from "../../server/fastify"; + +const requestService = new RequestService(); + +fastify.delete(`${PATH_BASE_CONTROLLER}/remove`, { + schema: { + tags: ["request"], + summary: "Remove request", + querystring: schemaQueryDeleteRequest, + response: { + 200: schemaReturnVoid, + 500: { $ref: SCHEMA_INTERNAL_SERVER } + } + } +}, async (request, replay) => { + const {request_to, auth_username} = request.query; + + await requestService.delete(auth_username, request_to); + + replay.status(200).send({ response: "ok" }); +}); \ No newline at end of file diff --git a/src/domain/interfaces/DTOs/IAccountDTO.ts b/src/domain/interfaces/DTOs/IAccountDTO.ts index 35d9470..ebc1202 100644 --- a/src/domain/interfaces/DTOs/IAccountDTO.ts +++ b/src/domain/interfaces/DTOs/IAccountDTO.ts @@ -10,8 +10,8 @@ export enum IAccountDTOEnv { export const accountDTOSchema = Type.Object({ [IAccountDTOEnv.USERNAME]: Type.String({ maxLength: 250 }), - [IAccountDTOEnv.EXPIRE_PASSWORD]: Type.String({ format: "date-time" }), - [IAccountDTOEnv.LAST_ACCESS]: Type.Union([Type.Null(), Type.String({ format: "date-time" })]), + [IAccountDTOEnv.EXPIRE_PASSWORD]: Type.String({format: "date-time"}), + [IAccountDTOEnv.LAST_ACCESS]: Type.Union([Type.Null(), Type.String({format: "date-time"})]), [IAccountDTOEnv.PROFILE]: Type.Union([Type.Null(), Type.String()]), [IAccountDTOEnv.CHANGE_PASSWORD]: Type.Boolean({ default: false }) }); diff --git a/src/domain/interfaces/DTOs/IFriendDTO.ts b/src/domain/interfaces/DTOs/IFriendDTO.ts new file mode 100644 index 0000000..e29ba55 --- /dev/null +++ b/src/domain/interfaces/DTOs/IFriendDTO.ts @@ -0,0 +1,15 @@ +import { Type } from "@sinclair/typebox"; + +export enum IFriendDTOEnv { + USERNAME = "username", + FRIEND = "friend", + BECOME_FRIEND_TIME = "become_friend_time" +} + +export const friendDTOSchema = Type.Object({ + [IFriendDTOEnv.USERNAME]: Type.String({ maxLength: 250 }), + [IFriendDTOEnv.FRIEND]: Type.String({ maxLength: 250 }), + [IFriendDTOEnv.BECOME_FRIEND_TIME]: Type.String({format: "date-time"}) +}); + +export type IFriendDTO = typeof friendDTOSchema.static \ No newline at end of file diff --git a/src/domain/interfaces/models/IAccount.ts b/src/domain/interfaces/models/IAccount.ts index 983349e..8005c8a 100644 --- a/src/domain/interfaces/models/IAccount.ts +++ b/src/domain/interfaces/models/IAccount.ts @@ -12,8 +12,8 @@ export enum IAccountEnv { export const accountSchema = Type.Object({ [IAccountEnv.USERNAME]: Type.String({ maxLength: 250 }), [IAccountEnv.PASSWORD]: Type.String({ maxLength: 250 }), - [IAccountEnv.EXPIRE_PASSWORD]: Type.String({ format: "date-time" }), - [IAccountEnv.LAST_ACCESS]: Type.Union([Type.String({ format: "date-time" }), Type.Null()]), + [IAccountEnv.EXPIRE_PASSWORD]: Type.String({format: "date-time"}), + [IAccountEnv.LAST_ACCESS]: Type.Union([Type.String({format: "date-time"}), Type.Null()]), [IAccountEnv.PROFILE]: Type.Union([Type.String(), Type.Null()]), [IAccountEnv.CHANGE_PASSWORD]: Type.Boolean({ default: false }) }); diff --git a/src/domain/interfaces/models/IFriend.ts b/src/domain/interfaces/models/IFriend.ts new file mode 100644 index 0000000..ec87052 --- /dev/null +++ b/src/domain/interfaces/models/IFriend.ts @@ -0,0 +1,15 @@ +import { Type } from "@sinclair/typebox"; + +export enum IFriendEnv { + USERNAME = "username", + FRIEND = "friend", + BECOME_FRIEND_TIME = "become_friend_time" +} + +export const friendSchema = Type.Object({ + [IFriendEnv.USERNAME]: Type.String({ maxLength: 250 }), + [IFriendEnv.FRIEND]: Type.String({ maxLength: 250 }), + [IFriendEnv.BECOME_FRIEND_TIME]: Type.String({format: "date-time"}) +}); + +export type IFriend = typeof friendSchema.static \ No newline at end of file diff --git a/src/domain/models/Account.ts b/src/domain/models/Account.ts index 2e4e429..5980cae 100644 --- a/src/domain/models/Account.ts +++ b/src/domain/models/Account.ts @@ -1,9 +1,9 @@ -import { Entity, PrimaryColumn, Column } from "typeorm"; import { DateTime } from "luxon"; +import { Entity, PrimaryColumn, Column } from "typeorm"; import { IAccount, IAccountEnv } from "../interfaces/models/IAccount"; -@Entity("account") +@Entity("accounts") export class Account implements IAccount{ @PrimaryColumn({type: "varchar", length: 250}) [IAccountEnv.USERNAME]: string; diff --git a/src/domain/models/Friends.ts b/src/domain/models/Friends.ts new file mode 100644 index 0000000..c418dcf --- /dev/null +++ b/src/domain/models/Friends.ts @@ -0,0 +1,16 @@ +import { DateTime } from "luxon"; +import { Entity, PrimaryColumn, Column } from "typeorm"; + +import { IFriend, IFriendEnv } from "../interfaces/models/IFriend"; + +@Entity("friends") +export class Friend implements IFriend{ + @PrimaryColumn({type: "varchar", length: 250}) + [IFriendEnv.USERNAME]: string; + + @Column({type: "varchar", length: 250}) + [IFriendEnv.FRIEND]: string; + + @Column({type: "timestamptz", default: DateTime.now()}) + [IFriendEnv.BECOME_FRIEND_TIME]: string; +} \ No newline at end of file diff --git a/src/domain/models/Request.ts b/src/domain/models/Request.ts index b0a4c37..e18575e 100644 --- a/src/domain/models/Request.ts +++ b/src/domain/models/Request.ts @@ -1,9 +1,9 @@ -import { Entity, PrimaryColumn, Column } from "typeorm"; import { DateTime } from "luxon"; +import { Entity, PrimaryColumn, Column } from "typeorm"; import { IRequest, IRequestEnv } from "../interfaces/models/IRequest"; -@Entity("request") +@Entity("requests") export class Request implements IRequest{ @PrimaryColumn({type: "varchar", length: 250}) [IRequestEnv.REQUEST_FROM]: string; diff --git a/src/eslint.config.js b/src/eslint.config.js index c1552df..b5c503b 100644 --- a/src/eslint.config.js +++ b/src/eslint.config.js @@ -57,7 +57,7 @@ export default [ "applications/interfaces/repositories/**/*.{js,ts}": "I+([A-Z])+([a-zA-Z])Repository", "applications/services/**/*.{js,ts}": "([A-Z])+([a-zA-Z])Service", "applications/repositories/**/*.{js,ts}": "([A-Z])+([a-zA-Z])Repository", - "controllers/**/*": "*([a-z])Route", + "controllers/**/*": "*([a-zA-Z])Route", "domain/interfaces/DTOs/**/*": "I+([A-Z])+([a-zA-Z])DTO", "domain/interfaces/models/**/*": "I+([A-Z])+([a-zA-Z])", "domain/models/**/*": "PASCAL_CASE", diff --git a/src/package.json b/src/package.json index 8250356..458ad5b 100644 --- a/src/package.json +++ b/src/package.json @@ -6,6 +6,7 @@ "scripts": { "start": "npx tsx index.ts", "clear": "rm -rf node_modules package-lock.json", + "typecheck": "npx tsc --noEmit", "eslint": "npx eslint .", "eslint-fix": "npx eslint --fix ." }, diff --git a/src/schemas/accountSchema.ts b/src/schemas/accountSchema.ts index 85a4a26..18b0deb 100644 --- a/src/schemas/accountSchema.ts +++ b/src/schemas/accountSchema.ts @@ -3,6 +3,7 @@ import { Type } from "@sinclair/typebox"; import { accountSchema, IAccountEnv } from "../domain/interfaces/models/IAccount"; import { accountDTOSchema } from "../domain/interfaces/DTOs/IAccountDTO"; import { convertToOptional } from "../utils/schemaUtils"; +import { requireAuth } from "./generic/authSchema"; //path base const PATH_BASE_CONTROLLER = "/account"; @@ -10,7 +11,7 @@ const PATH_BASE_CONTROLLER = "/account"; //request const schemaCreateAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME, IAccountEnv.PASSWORD, IAccountEnv.CHANGE_PASSWORD]); const schemaUpdateAccount = convertToOptional(accountSchema, [IAccountEnv.PROFILE, IAccountEnv.CHANGE_PASSWORD]); -const schemaQueryUsernameAccount = Type.Pick(accountSchema, [IAccountEnv.USERNAME]); +const schemaQueryUsernameAccount = requireAuth(Type.Pick(accountSchema, [IAccountEnv.USERNAME])); //replay const schemaReturnAccount = accountDTOSchema; diff --git a/src/schemas/friendSchema.ts b/src/schemas/friendSchema.ts new file mode 100644 index 0000000..4acc520 --- /dev/null +++ b/src/schemas/friendSchema.ts @@ -0,0 +1,35 @@ +import { Type } from "@sinclair/typebox"; + +import { friendSchema, IFriendEnv } from "../domain/interfaces/models/IFriend"; +import { friendDTOSchema } from "../domain/interfaces/DTOs/IFriendDTO"; +import { queryPagination, schemaReturnPagination } from "./generic/paginationSchema"; +import { requireAuth } from "./generic/authSchema"; + +//path base +const PATH_BASE_CONTROLLER = "/friend"; + +//request +const schemaQueryUsernameOfFriend = requireAuth(Type.Pick(friendSchema, [IFriendEnv.FRIEND])); +const schemaQueryPaginatedFriend = requireAuth(queryPagination); + +//replay +const schemaReturnFriend = friendDTOSchema; +const schemaReturnPaginatedFriend = schemaReturnPagination(friendDTOSchema); + +//interface +type ISchemaReturnPaginatedFriend = typeof schemaReturnPaginatedFriend.static; + +export { + PATH_BASE_CONTROLLER, + + //request + schemaQueryUsernameOfFriend, + schemaQueryPaginatedFriend, + + //replay + schemaReturnFriend, + schemaReturnPaginatedFriend, + + //interface + ISchemaReturnPaginatedFriend +}; \ No newline at end of file diff --git a/src/schemas/generic/authSchema.ts b/src/schemas/generic/authSchema.ts new file mode 100644 index 0000000..4baac8c --- /dev/null +++ b/src/schemas/generic/authSchema.ts @@ -0,0 +1,15 @@ +import { Type, TObject } from "@sinclair/typebox"; + +const schemaQueryUsernameAuth = Type.Object({ + auth_username: Type.String({maxLength: 250}) +}); + +function requireAuth(query: T){ + return Type.Intersect([schemaQueryUsernameAuth, query]); +} + +export { + schemaQueryUsernameAuth, + + requireAuth +}; \ No newline at end of file diff --git a/src/schemas/generic/genericSchema.ts b/src/schemas/generic/genericSchema.ts index 6de30ca..10bfea0 100644 --- a/src/schemas/generic/genericSchema.ts +++ b/src/schemas/generic/genericSchema.ts @@ -4,6 +4,7 @@ const SCHEMA_NOT_FOUND = "SchemaNotFound"; const SCHEMA_INTERNAL_SERVER = "SchemaInternalServer"; const SCHEMA_CONFLICT = "SchemaConflict"; const SCHEMA_BAD_REQUEST = "SchemaBadRequest"; +const SCHEMA_UNAUTHORIZED = "SchemaUnauthorized"; const schemaReturnVoid = Type.Object({ response: Type.String({default: "ok"}) @@ -15,27 +16,32 @@ const templateErrorSchema = Type.Object({ }); const notFound = Type.Intersect([ -templateErrorSchema, Type.Object({ - statusCode: Type.Number({default: 404}) -}) + templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 404}) + }) ], { $id: SCHEMA_NOT_FOUND }); const internalServer = Type.Intersect([ -templateErrorSchema, Type.Object({ - statusCode: Type.Number({default: 500}) -}) + templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 500}) + }) ], { $id: SCHEMA_INTERNAL_SERVER }); const conflict = Type.Intersect([ -templateErrorSchema, Type.Object({ - statusCode: Type.Number({default: 401}) -}) + templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 409}) + }) ], { $id: SCHEMA_CONFLICT }); const badRequest = Type.Intersect([ -templateErrorSchema, Type.Object({ - statusCode: Type.Number({default: 400}) -}) + templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 400}) + }) ], { $id: SCHEMA_BAD_REQUEST }); +const unauthorized = Type.Intersect([ + templateErrorSchema, Type.Object({ + statusCode: Type.Number({default: 401}) + }) +], { $id: SCHEMA_UNAUTHORIZED }); -export default [notFound, internalServer, conflict, badRequest]; +export default [notFound, internalServer, conflict, badRequest, unauthorized]; export { //replay @@ -45,5 +51,6 @@ export { SCHEMA_NOT_FOUND, SCHEMA_BAD_REQUEST, SCHEMA_CONFLICT, - SCHEMA_INTERNAL_SERVER + SCHEMA_INTERNAL_SERVER, + SCHEMA_UNAUTHORIZED }; \ No newline at end of file diff --git a/src/schemas/generic/paginationSchema.ts b/src/schemas/generic/paginationSchema.ts index 79fc5b7..a8ec748 100644 --- a/src/schemas/generic/paginationSchema.ts +++ b/src/schemas/generic/paginationSchema.ts @@ -5,10 +5,12 @@ const queryPagination = Type.Object({ length: Type.Number({minimum: 10, default: 10}) }); -const schemaReturnPagination = (schema: T) => Type.Object({ - max_count: Type.Number(), - list: Type.Array(schema) -}); +function schemaReturnPagination(schema: T){ + return Type.Object({ + max_count: Type.Number(), + list: Type.Array(schema) + }); +} export { schemaReturnPagination, diff --git a/src/schemas/requestSchema.ts b/src/schemas/requestSchema.ts index a350c18..8646e91 100644 --- a/src/schemas/requestSchema.ts +++ b/src/schemas/requestSchema.ts @@ -2,23 +2,29 @@ import { Type } from "@sinclair/typebox"; import { queryPagination, schemaReturnPagination } from "./generic/paginationSchema"; import { requestDTOSchema } from "../domain/interfaces/DTOs/IRequestDTO"; import { IRequestEnv, requestSchema } from "../domain/interfaces/models/IRequest"; +import { schemaQueryUsernameAuth, requireAuth } from "./generic/authSchema"; //path base const PATH_BASE_CONTROLLER = "/request"; //request -const schemaCreateRequest = Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO]); +const schemaCreateRequest = Type.Pick(requestSchema, [IRequestEnv.REQUEST_TO]); const schemaActionRequest = Type.Intersect([ - Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM, IRequestEnv.REQUEST_TO]), + schemaQueryUsernameAuth, + Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM]), Type.Object({ accept: Type.Boolean() }) ]); -const schemaQueryPaginatedRequest = Type.Intersect([Type.Pick(requestSchema, [IRequestEnv.REQUEST_FROM]), queryPagination]); +const schemaQueryPaginatedRequest = requireAuth(queryPagination); +const schemaQueryDeleteRequest = requireAuth(Type.Pick(requestSchema, [IRequestEnv.REQUEST_TO])); //replay const schemaReturnPaginatedRequest = schemaReturnPagination(requestDTOSchema); +//interface +type ISchemaReturnPaginatedRequest = typeof schemaReturnPaginatedRequest.static; + export { PATH_BASE_CONTROLLER, @@ -26,7 +32,11 @@ export { schemaCreateRequest, schemaActionRequest, schemaQueryPaginatedRequest, + schemaQueryDeleteRequest, //replay - schemaReturnPaginatedRequest + schemaReturnPaginatedRequest, + + //interfaces + ISchemaReturnPaginatedRequest }; \ No newline at end of file diff --git a/src/server/fastify/index.ts b/src/server/fastify/index.ts index 12dcfff..1bbfc86 100644 --- a/src/server/fastify/index.ts +++ b/src/server/fastify/index.ts @@ -4,7 +4,7 @@ import path from "path"; import Fastify from "fastify"; import { DateTime } from "luxon"; import { env, exit } from "process"; -import { Type, TypeBoxTypeProvider } from "@fastify/type-provider-typebox"; +import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox"; import { IConfig } from "./interfaces/IConfig"; import { ApiBadRequest, ApiConflict, ApiErrorGeneric, ApiNotFound, ApiUnauthorized } from "../../modules/api";