diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2806b6a..e5d5e73 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,9 +135,6 @@ dompurify: specifier: ^3.0.9 version: 3.0.9 - formidable: - specifier: ^3.2.5 - version: 3.5.0 htmlparser2: specifier: ^9.1.0 version: 9.1.0 @@ -205,9 +202,6 @@ '@types/dompurify': specifier: ^3.0.5 version: 3.0.5 - '@types/formidable': - specifier: ^3.4.5 - version: 3.4.5 '@types/jest': specifier: ^29.5.12 version: 29.5.12 @@ -966,12 +960,6 @@ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true - /@types/formidable@3.4.5: - resolution: {integrity: sha512-s7YPsNVfnsng5L8sKnG/Gbb2tiwwJTY1conOkJzTMRvJAlLFW1nEua+ADsJQu8N1c0oTHx9+d5nqg10WuT9gHQ==} - dependencies: - '@types/node': 20.11.27 - dev: true - /@types/geojson@7946.0.10: resolution: {integrity: sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==} dev: false @@ -1374,10 +1362,6 @@ is-shared-array-buffer: 1.0.3 dev: true - /asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - dev: false - /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: true @@ -1727,13 +1711,6 @@ engines: {node: '>=8'} dev: false - /dezalgo@1.0.4: - resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} - dependencies: - asap: 2.0.6 - wrappy: 1.0.2 - dev: false - /diff-sequences@29.4.3: resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2423,14 +2400,6 @@ mime-types: 2.1.35 dev: false - /formidable@3.5.0: - resolution: {integrity: sha512-WwsMWvPmY+Kv37C3+KP3A+2Ym1aZoac4nz4ZEe5z0UPBoCg0O/wHay3eeYkZr4KJIbCzpSUeno+STMhde+KCfw==} - dependencies: - dezalgo: 1.0.4 - hexoid: 1.0.0 - once: 1.4.0 - dev: false - /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -2665,11 +2634,6 @@ function-bind: 1.1.2 dev: true - /hexoid@1.0.0: - resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} - engines: {node: '>=8'} - dev: false - /html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -3490,6 +3454,7 @@ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 + dev: true /one-time@1.0.0: resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} @@ -4707,6 +4672,7 @@ /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true /ws@8.16.0: resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} diff --git a/taehui-fe/.gitignore b/taehui-fe/.gitignore index 669ccb6..1c3f9b4 100644 --- a/taehui-fe/.gitignore +++ b/taehui-fe/.gitignore @@ -40,4 +40,3 @@ /DB /Event /System -Configure.json diff --git a/taehui-fe/package.json b/taehui-fe/package.json index f0600d2..4bf6181 100644 --- a/taehui-fe/package.json +++ b/taehui-fe/package.json @@ -17,7 +17,6 @@ "crypto-js": "^4.2.0", "dayjs": "^1.11.10", "dompurify": "^3.0.9", - "formidable": "^3.2.5", "htmlparser2": "^9.1.0", "isomorphic-dompurify": "^2.4.0", "mariadb": "^3.2.3", @@ -42,7 +41,6 @@ "devDependencies": { "@types/crypto-js": "^4.2.2", "@types/dompurify": "^3.0.5", - "@types/formidable": "^3.4.5", "@types/jest": "^29.5.12", "@types/node": "^20.11.27", "@types/react": "^18.2.65", diff --git "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx" "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx" index 2b31bbd..5785bfa 100644 --- "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx" +++ "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx" @@ -366,7 +366,7 @@ color="success" onClick={async () => { if (title && text) { - const essayID = await postEssay({ + const { essayID } = await postEssay({ forumID, title, text, diff --git "a/taehui-fe/src/app/\133language\135/forum/query/usePostEssay.ts" "b/taehui-fe/src/app/\133language\135/forum/query/usePostEssay.ts" index 35561c1..8d3a8e4 100644 --- "a/taehui-fe/src/app/\133language\135/forum/query/usePostEssay.ts" +++ "b/taehui-fe/src/app/\133language\135/forum/query/usePostEssay.ts" @@ -18,7 +18,7 @@ title: string; text: string; }) => { - const { data } = await wwwAPI.post( + const { data } = await wwwAPI.post( `/essay/${forumID}`, { title, diff --git "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts" "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts" index 2dae2ca..5642836 100644 --- "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts" +++ "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts" @@ -1,12 +1,12 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; import { doModifyAutoEssay, getAutoEssays, postAutoEssay, wipeAutoEssay, -} from "@/app/www/systems/autoEssay"; +} from "@/app/www/logic/autoEssay"; export const GET = validateMillis(async (req, { params: { forumID } }) => { const avatarID = req.headers.get("avatarID"); diff --git "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts" "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts" index 55516cc..bc491be 100644 --- "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts" +++ "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts" @@ -1,6 +1,6 @@ -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; -import { getAutoEssays, postAutoEssay } from "@/app/www/systems/autoEssay"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; +import { getAutoEssays, postAutoEssay } from "@/app/www/logic/autoEssay"; export const GET = validateMillis(async (req, { params: { forumID } }) => { const avatarID = req.headers.get("avatarID") as string; diff --git a/taehui-fe/src/app/www/avatar/avatarIntro/route.ts b/taehui-fe/src/app/www/avatar/avatarIntro/route.ts index f3c153f..4cf4c12 100644 --- a/taehui-fe/src/app/www/avatar/avatarIntro/route.ts +++ b/taehui-fe/src/app/www/avatar/avatarIntro/route.ts @@ -1,7 +1,7 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; -import { doModifyAvatarIntro } from "@/app/www/systems/avatar"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; +import { doModifyAvatarIntro } from "@/app/www/logic/avatar"; export const PUT = logIP( validateMillis( diff --git "a/taehui-fe/src/app/www/avatar/drawing/\133avatarID\135/route.ts" "b/taehui-fe/src/app/www/avatar/drawing/\133avatarID\135/route.ts" index da2bbb2..95ddad7 100644 --- "a/taehui-fe/src/app/www/avatar/drawing/\133avatarID\135/route.ts" +++ "b/taehui-fe/src/app/www/avatar/drawing/\133avatarID\135/route.ts" @@ -1,10 +1,7 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; -import { - doInvalidateDrawing, - getAvatarDrawing, -} from "@/app/www/systems/avatar"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; +import { doInvalidateDrawing, getAvatarDrawing } from "@/app/www/logic/avatar"; import { AVATAR_ENTRY_PATH, DEFAULT_AVATAR_ASSET, diff --git a/taehui-fe/src/app/www/avatar/drawing/route.ts b/taehui-fe/src/app/www/avatar/drawing/route.ts index f1b8e00..a4964a6 100644 --- a/taehui-fe/src/app/www/avatar/drawing/route.ts +++ b/taehui-fe/src/app/www/avatar/drawing/route.ts @@ -1,4 +1,4 @@ -import logIP from "@/app/www/mws/logIP"; +import logIP from "@/app/www/media/logIP"; import { DEFAULT_AVATAR_ASSET } from "@/app/www/utilities/Path"; export const GET = logIP(async () => { diff --git a/taehui-fe/src/app/www/avatar/getTotem/route.ts b/taehui-fe/src/app/www/avatar/getTotem/route.ts index 8c3a597..549998d 100644 --- a/taehui-fe/src/app/www/avatar/getTotem/route.ts +++ b/taehui-fe/src/app/www/avatar/getTotem/route.ts @@ -1,6 +1,6 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import { getTotem } from "@/app/www/systems/avatar"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import { getTotem } from "@/app/www/logic/avatar"; export const POST = logIP( validateMillis(async (req) => { diff --git a/taehui-fe/src/app/www/avatar/latest/route.ts b/taehui-fe/src/app/www/avatar/latest/route.ts index b862541..3e8e607 100644 --- a/taehui-fe/src/app/www/avatar/latest/route.ts +++ b/taehui-fe/src/app/www/avatar/latest/route.ts @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getLatestAvatars } from "@/app/www/systems/avatar"; +import logIP from "@/app/www/media/logIP"; +import { getLatestAvatars } from "@/app/www/logic/avatar"; export const GET = logIP(async () => { return Response.json(await getLatestAvatars()); diff --git a/taehui-fe/src/app/www/avatar/route.ts b/taehui-fe/src/app/www/avatar/route.ts index d38d44d..c15c523 100644 --- a/taehui-fe/src/app/www/avatar/route.ts +++ b/taehui-fe/src/app/www/avatar/route.ts @@ -1,7 +1,7 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; -import { doModifyAvatar, postAvatar } from "@/app/www/systems/avatar"; +import { doModifyAvatar, postAvatar } from "@/app/www/logic/avatar"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; export const PUT = logIP( validateMillis( diff --git a/taehui-fe/src/app/www/avatar/totem/route.ts b/taehui-fe/src/app/www/avatar/totem/route.ts index 626e2ae..6a83c38 100644 --- a/taehui-fe/src/app/www/avatar/totem/route.ts +++ b/taehui-fe/src/app/www/avatar/totem/route.ts @@ -1,18 +1,18 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; -import { wipeTotem } from "@/app/www/systems/avatar"; +import { wipeTotem } from "@/app/www/logic/avatar"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; export const PATCH = logIP( validateMillis( validateTotem(async ({ headers }) => { return Response.json( { - avatarID: headers.get("avatarID"), - avatarName: headers.get("avatarName"), - level: Number(headers.get("level")), - fax: headers.get("fax"), - avatarIntro: headers.get("avatarIntro"), + avatarID: headers.avatarID, + avatarName: headers.avatarName, + level: Number(headers.level), + fax: headers.fax, + avatarIntro: headers.avatarIntro, }, { status: 201 }, ); @@ -23,10 +23,10 @@ export const DELETE = logIP( validateMillis( validateTotem(async ({ headers }) => { - const avatarID = headers.get("avatarID") as string; + const { avatarID } = headers; return new Response(undefined, { - status: (await wipeTotem(avatarID)) ? 204 : 403, + status: (await wipeTotem(avatarID as string)) ? 204 : 403, }); }), ), diff --git "a/taehui-fe/src/app/www/comment/\133commentID\135/route.ts" "b/taehui-fe/src/app/www/comment/\133commentID\135/route.ts" index a2e51cc..19e49ac 100644 --- "a/taehui-fe/src/app/www/comment/\133commentID\135/route.ts" +++ "b/taehui-fe/src/app/www/comment/\133commentID\135/route.ts" @@ -1,12 +1,12 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; import { doModifyComment, getComments, postComment, wipeComment, -} from "@/app/www/systems/comment"; +} from "@/app/www/logic/comment"; export const GET = logIP(async (req, { params: { commentID: essayID } }) => { return Response.json(await getComments(Number(essayID))); diff --git a/taehui-fe/src/app/www/comment/latest/route.ts b/taehui-fe/src/app/www/comment/latest/route.ts index 815b729..383538f 100644 --- a/taehui-fe/src/app/www/comment/latest/route.ts +++ b/taehui-fe/src/app/www/comment/latest/route.ts @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getLatestComments } from "@/app/www/systems/comment"; +import logIP from "@/app/www/media/logIP"; +import { getLatestComments } from "@/app/www/logic/comment"; export const GET = logIP(async () => { return Response.json(await getLatestComments()); diff --git a/taehui-fe/src/app/www/commentary/route.ts b/taehui-fe/src/app/www/commentary/route.ts index d353a57..de1d8c1 100644 --- a/taehui-fe/src/app/www/commentary/route.ts +++ b/taehui-fe/src/app/www/commentary/route.ts @@ -1,11 +1,11 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; import { doModifyCommentary, getCommentary, postCommentary, wipeCommentary, -} from "@/app/www/systems/commentary"; +} from "@/app/www/logic/commentary"; export const GET = logIP(async () => { return Response.json(await getCommentary()); diff --git "a/taehui-fe/src/app/www/essay/\133essayID\135/route.ts" "b/taehui-fe/src/app/www/essay/\133essayID\135/route.ts" index a0936b9..a5a9bc8 100644 --- "a/taehui-fe/src/app/www/essay/\133essayID\135/route.ts" +++ "b/taehui-fe/src/app/www/essay/\133essayID\135/route.ts" @@ -1,12 +1,12 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; import { doModifyEssay, getEssay, postEssay, wipeEssay, -} from "@/app/www/systems/essay"; +} from "@/app/www/logic/essay"; export const GET = logIP(async (req, { params: { essayID } }) => { const language = req.nextUrl.searchParams.get("language"); @@ -78,7 +78,7 @@ const essayID = await postEssay(forumID, avatarID, level, title, text); if (essayID >= 0) { - return new Response(essayID.toString()); + return Response.json({ essayID }); } else { return new Response(undefined, { status: 403 }); } diff --git a/taehui-fe/src/app/www/essay/latest/route.ts b/taehui-fe/src/app/www/essay/latest/route.ts index c089c25..54627f0 100644 --- a/taehui-fe/src/app/www/essay/latest/route.ts +++ b/taehui-fe/src/app/www/essay/latest/route.ts @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getLatestEssays } from "@/app/www/systems/essay"; +import logIP from "@/app/www/media/logIP"; +import { getLatestEssays } from "@/app/www/logic/essay"; export const GET = logIP(async (req) => { const language = req.nextUrl.searchParams.get("language"); diff --git "a/taehui-fe/src/app/www/file/\133fileName\135/hit/route.ts" "b/taehui-fe/src/app/www/file/\133fileName\135/hit/route.ts" index bbdca30..7be34e7 100644 --- "a/taehui-fe/src/app/www/file/\133fileName\135/hit/route.ts" +++ "b/taehui-fe/src/app/www/file/\133fileName\135/hit/route.ts" @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getFileHit } from "@/app/www/systems/file"; +import logIP from "@/app/www/media/logIP"; +import { getFileHit } from "@/app/www/logic/file"; export const GET = logIP(async (req, { params: { fileName } }) => { return Response.json(await getFileHit(fileName)); diff --git "a/taehui-fe/src/app/www/file/\133fileName\135/route.ts" "b/taehui-fe/src/app/www/file/\133fileName\135/route.ts" index f2d576b..eacc631 100644 --- "a/taehui-fe/src/app/www/file/\133fileName\135/route.ts" +++ "b/taehui-fe/src/app/www/file/\133fileName\135/route.ts" @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getFile, getPostedFileName } from "@/app/www/systems/file"; +import { getFile, getPostedFileName } from "@/app/www/logic/file"; +import logIP from "@/app/www/media/logIP"; export const GET = logIP(async (req, { params: { fileName } }) => { return new Response( diff --git a/taehui-fe/src/app/www/file/route.ts b/taehui-fe/src/app/www/file/route.ts index d4b568c..5943fcb 100644 --- a/taehui-fe/src/app/www/file/route.ts +++ b/taehui-fe/src/app/www/file/route.ts @@ -1,6 +1,6 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import validateTotem from "@/app/www/mws/validateTotem"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; +import validateTotem from "@/app/www/media/validateTotem"; import { ESSAY_ENTRY_PATH } from "@/app/www/utilities/Path"; import { writeFile } from "node:fs/promises"; import { join, parse } from "path"; diff --git "a/taehui-fe/src/app/www/forum/\133forumID\135/route.ts" "b/taehui-fe/src/app/www/forum/\133forumID\135/route.ts" index 9a6effb..b0f1a34 100644 --- "a/taehui-fe/src/app/www/forum/\133forumID\135/route.ts" +++ "b/taehui-fe/src/app/www/forum/\133forumID\135/route.ts" @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getEssays } from "@/app/www/systems/forum"; +import logIP from "@/app/www/media/logIP"; +import { getEssays } from "@/app/www/logic/forum"; export const GET = logIP(async (req, { params: { forumID } }) => { const page = req.nextUrl.searchParams.get("page"); diff --git "a/taehui-fe/src/app/www/forums/\133forumGroup\135/route.ts" "b/taehui-fe/src/app/www/forums/\133forumGroup\135/route.ts" index b783862..8fdd764 100644 --- "a/taehui-fe/src/app/www/forums/\133forumGroup\135/route.ts" +++ "b/taehui-fe/src/app/www/forums/\133forumGroup\135/route.ts" @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getForums } from "@/app/www/systems/forums"; +import logIP from "@/app/www/media/logIP"; +import { getForums } from "@/app/www/logic/forums"; export const GET = logIP( async ({ nextUrl: { searchParams } }, { params: { forumGroup } }) => { diff --git a/taehui-fe/src/app/www/forums/route.ts b/taehui-fe/src/app/www/forums/route.ts index bf7d22d..9f59552 100644 --- a/taehui-fe/src/app/www/forums/route.ts +++ b/taehui-fe/src/app/www/forums/route.ts @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { getForums } from "@/app/www/systems/forums"; +import logIP from "@/app/www/media/logIP"; +import { getForums } from "@/app/www/logic/forums"; export const GET = logIP(async (req) => { const language = req.nextUrl.searchParams.get("language"); diff --git a/taehui-fe/src/app/www/hit/route.ts b/taehui-fe/src/app/www/hit/route.ts index dc050f7..18a9815 100644 --- a/taehui-fe/src/app/www/hit/route.ts +++ b/taehui-fe/src/app/www/hit/route.ts @@ -1,8 +1,8 @@ -import logIP from "@/app/www/mws/logIP"; -import validateMillis from "@/app/www/mws/validateMillis"; -import { getHit, postHit } from "@/app/www/systems/hit"; +import { getHit, postHit } from "@/app/www/logic/hit"; +import logIP from "@/app/www/media/logIP"; +import validateMillis from "@/app/www/media/validateMillis"; -export const GET = logIP(async (req) => { +export const GET = logIP(async () => { return Response.json(await getHit()); }); diff --git a/taehui-fe/src/app/www/logic/autoEssay.ts b/taehui-fe/src/app/www/logic/autoEssay.ts new file mode 100644 index 0000000..43c9750 --- /dev/null +++ b/taehui-fe/src/app/www/logic/autoEssay.ts @@ -0,0 +1,34 @@ +import DB from "@/app/www/system/DB"; +import { getDatetime } from "taehui-ts/date"; + +export const postAutoEssay = async ( + forumID: string, + avatarID: string, + title: string, + text: string, +) => { + return DB.postAutoEssay(forumID, avatarID, title, text, getDatetime()); +}; + +export const getAutoEssays = async (forumID: string, avatarID: string) => { + return DB.getAutoEssays(forumID, avatarID); +}; + +export const doModifyAutoEssay = async ( + autoEssayID: number, + avatarID: string, + title: string, + text: string, +) => { + return DB.doModifyAutoEssay( + autoEssayID, + avatarID, + title, + text, + getDatetime(), + ); +}; + +export const wipeAutoEssay = async (autoEssayID: number, avatarID: string) => { + return DB.wipeAutoEssay(autoEssayID, avatarID); +}; diff --git a/taehui-fe/src/app/www/logic/avatar.ts b/taehui-fe/src/app/www/logic/avatar.ts new file mode 100644 index 0000000..7a4f830 --- /dev/null +++ b/taehui-fe/src/app/www/logic/avatar.ts @@ -0,0 +1,175 @@ +import DB from "@/app/www/system/DB"; +import { AVATAR_ENTRY_PATH } from "@/app/www/utilities/Path"; +import { equalCipher } from "@/app/www/utilities/Utility"; +import { pbkdf2, randomBytes } from "crypto"; +import dayjs from "dayjs"; +import { PoolConnection } from "mariadb"; +import { readFile } from "node:fs/promises"; +import { join } from "path"; +import { getDatetime } from "taehui-ts/date"; +import { promisify } from "util"; + +const pw = promisify(pbkdf2); + +const putTotem = async (db: PoolConnection, avatarID: string) => { + const data = await DB.getTotem(db, avatarID); + + const datetime = getDatetime(); + if (data && dayjs(data.date).add(1, "hour").isAfter(datetime)) { + await DB.setTotemDateAsAvatarID(db, avatarID, datetime); + return data.totem; + } + + return DB.putTotem(db, avatarID, datetime); +}; + +export const getTotem = async ( + pendingAvatarID: string, + pendingAvatarCipher: string, +) => { + return DB.ta(async (db) => { + const data = await DB.getAvatarAsAvatarID(db, pendingAvatarID); + if (data) { + const { avatarID, avatarCipher, avatarName, level, fax, avatarIntro } = + data; + const isOK = await equalCipher(avatarCipher, pendingAvatarCipher); + if (isOK) { + await DB.setLastDate(db, avatarID, getDatetime()); + return { + totem: await putTotem(db, avatarID), + avatarID, + avatarName, + level, + fax, + avatarIntro, + }; + } else { + return null; + } + } + }); +}; + +const getDBCipher = async (avatarCipher: string) => { + const salt = randomBytes(24).toString("base64"); + + return `sha256:12000:${salt}:${Buffer.from( + await pw(avatarCipher, salt, 12000, 24, "sha256"), + ).toString("base64")}`; +}; + +export const doModifyAvatar = async ( + avatarID: string, + avatarCipher: string, + avatarCipherModified: string, + avatarName: string, + fax: string, + avatarIntro: string, +) => { + if ( + avatarCipher && + avatarName && + avatarName.length <= 16 && + (!fax || /^.+@.+$/.test(fax)) + ) { + return DB.ta(async (db) => { + if ( + await DB.doModifyAvatar( + db, + avatarID, + avatarCipher, + avatarCipherModified && (await getDBCipher(avatarCipherModified)), + avatarName, + fax, + avatarIntro, + ) + ) { + if (avatarCipherModified) { + await DB.wipeTotem(db, avatarID); + await fetch("http://localhost:8300/totem", { + method: "PATCH", + body: JSON.stringify({ avatarID }), + }); + } + return true; + } else { + return false; + } + }); + } else { + return false; + } +}; + +export const doModifyAvatarIntro = async ( + avatarID: string, + avatarIntro: string, +) => { + return DB.doModifyAvatarIntro(avatarID, avatarIntro); +}; + +export const postAvatar = async ( + avatarID: string, + avatarCipher: string, + avatarName: string, + avatarIP: string, + fax: string, +) => { + return ( + avatarID && + !avatarID.startsWith("@") && + !avatarID.startsWith("#") && + !avatarID.startsWith("$") && + !avatarID.startsWith("*") && + avatarCipher && + avatarName && + avatarName.length <= 16 && + (!fax || /^.+@.+$/.test(fax)) && + DB.ta(async (db) => { + if (await DB.getAvatarAsAvatarID(db, avatarID)) { + return false; + } else { + return DB.postAvatar( + avatarID, + await getDBCipher(avatarCipher), + avatarName, + avatarIP, + fax, + getDatetime(), + ); + } + }) + ); +}; + +export const wipeTotem = async (avatarID: string) => { + return DB.ta(async (db) => + Promise.all([ + DB.setLastDate(db, avatarID, getDatetime()), + DB.wipeTotem(db, avatarID), + ]), + ); +}; + +export const getAvatarDrawing = async (avatarID: string) => { + try { + return await readFile(join(AVATAR_ENTRY_PATH, avatarID + ".png")); + } catch (e: any) { + if (e.code === "ENOENT") { + return null; + } + + throw e; + } +}; + +export const getLatestAvatars = async () => { + return DB.getLatestAvatars(); +}; + +export const doInvalidateDrawing = async (avatarID: string) => { + await fetch("http://localhost:8300/drawing", { + method: "PATCH", + body: JSON.stringify({ avatarID }), + }); +}; diff --git a/taehui-fe/src/app/www/logic/comment.ts b/taehui-fe/src/app/www/logic/comment.ts new file mode 100644 index 0000000..cb9c0fc --- /dev/null +++ b/taehui-fe/src/app/www/logic/comment.ts @@ -0,0 +1,60 @@ +import DB from "@/app/www/system/DB"; +import { CommentItem } from "@/app/www/type/CommentItem"; +import { getDatetime } from "taehui-ts/date"; + +export const getComments = async (essayID: number) => { + const comments = await DB.getComments(essayID); + const data = new Map(); + const commentItems = new Map(); + + comments.forEach(({ targetCommentID, commentID, ...comment }) => { + const commentItem: CommentItem = { + commentID, + ...comment, + comments: [], + }; + if (targetCommentID !== -1) { + data.get(targetCommentID)?.comments?.push(commentItem); + } else { + commentItems.set(commentID, commentItem); + } + data.set(commentID, commentItem); + }); + + return Array.from(commentItems.values()); +}; + +export const postComment = async ( + targetCommentID: number, + essayID: number, + avatarID: string, + level: number, + text: string, +) => { + return ( + 1 <= level && + text && + DB.postComment(targetCommentID, essayID, avatarID, getDatetime(), text) + ); +}; + +export const doModifyComment = async ( + commentID: number, + avatarID: string, + text: string, + level: number, +) => { + return text && DB.doModifyComment(commentID, avatarID, text, level); +}; + +export const wipeComment = async ( + commentID: number, + avatarID: string, + level: number, +) => { + return DB.wipeComment(commentID, avatarID, level); +}; + +export const getLatestComments = async () => { + return DB.getLatestComments(); +}; diff --git a/taehui-fe/src/app/www/logic/commentary.ts b/taehui-fe/src/app/www/logic/commentary.ts new file mode 100644 index 0000000..226d5b9 --- /dev/null +++ b/taehui-fe/src/app/www/logic/commentary.ts @@ -0,0 +1,38 @@ +import DB from "@/app/www/system/DB"; +import { getDatetime } from "taehui-ts/date"; + +export const getCommentary = async () => { + return DB.getCommentary(); +}; + +export const postCommentary = async ( + avatarName: string, + avatarCipher: string, + avatarIP: string, + text: string, +) => { + return ( + text && + avatarCipher && + DB.postCommentary(avatarName, avatarCipher, avatarIP, getDatetime(), text) + ); +}; + +export const doModifyCommentary = async ( + commentaryID: number, + avatarCipher: string, + text: string, +) => { + return ( + avatarCipher && + text && + DB.doModifyCommentary(commentaryID, avatarCipher, text) + ); +}; + +export const wipeCommentary = async ( + commentaryID: number, + avatarCipher: string, +) => { + return avatarCipher && DB.wipeCommentary(commentaryID, avatarCipher); +}; diff --git a/taehui-fe/src/app/www/logic/essay.ts b/taehui-fe/src/app/www/logic/essay.ts new file mode 100644 index 0000000..fca33e6 --- /dev/null +++ b/taehui-fe/src/app/www/logic/essay.ts @@ -0,0 +1,143 @@ +import DB from "@/app/www/system/DB"; +import { ESSAY_ENTRY_PATH } from "@/app/www/utilities/Path"; +import { + getFileNames, + getTitle, + isBannedIP, +} from "@/app/www/utilities/Utility"; +import { unlink } from "fs"; +import { join } from "path"; +import { getDate, getDatetime } from "taehui-ts/date"; +import { promisify } from "util"; + +const wipeFile = promisify(unlink); + +export const getEssay = async ( + essayID: number, + language: string, + avatarIP: string, +) => { + if (!isBannedIP(avatarIP)) { + await DB.postEssayHit(essayID, avatarIP, getDate()); + } + const essay = await DB.getEssay(essayID); + if (essay) { + const { forumTitle, forumTitle1042, ...restEssay } = essay; + return { + ...restEssay, + forumTitle: getTitle(language, { + title: forumTitle, + title1042: forumTitle1042, + }), + }; + } +}; + +export const getEssayHit = async (essayID: number) => { + return DB.getEssayHit(essayID); +}; + +export const doModifyEssay = async ( + essayID: number, + avatarID: string, + title: string, + text: string, + level: number, +) => { + return ( + title && + text && + DB.ta(async (db) => { + if (await DB.doModifyEssay(db, essayID, avatarID, title, text, level)) { + const lastFileNames = await DB.getFileNames(db, essayID); + const fileNames = getFileNames(text); + const hrefs = fileNames.map(([fileName]) => fileName); + + await wipeFiles( + lastFileNames.filter((lastFileName) => !hrefs.includes(lastFileName)), + ); + + await DB.postFileNames( + avatarID, + essayID, + fileNames.filter(([fileName]) => !lastFileNames.includes(fileName)), + ); + + return true; + } else { + return false; + } + }) + ); +}; + +export const wipeEssay = async ( + essayID: number, + avatarID: string, + level: number, +) => { + return DB.ta(async (db) => { + const fileNames = await DB.getFileNames(db, essayID); + if (await DB.wipeEssay(essayID, avatarID, level)) { + await wipeFiles(fileNames); + return true; + } else { + return false; + } + }); +}; + +export const getLatestEssays = async (language: string) => { + return (await DB.getLatestEssays()).map( + ({ forumTitle, forumTitle1042, ...restLatestEssay }) => { + return { + ...restLatestEssay, + forumTitle: getTitle(language, { + title: forumTitle, + title1042: forumTitle1042, + }), + }; + }, + ); +}; + +const wipeFiles = async (fileNames: string[]) => { + await DB.wipeFileNames(fileNames); + for await (const fileName of fileNames) { + try { + await wipeFile(join(ESSAY_ENTRY_PATH, fileName)); + } catch {} + } +}; + +export const postEssay = async ( + forumID: string, + avatarID: string, + level: number, + title: string, + text: string, +) => { + return title && text + ? await DB.ta(async (db) => { + const forum = await DB.getForum(db, forumID); + if (forum) { + if (forum.level <= level) { + const fileNames = getFileNames(text); + + const essayID = await DB.postEssay( + db, + forumID, + avatarID, + getDatetime(), + title, + text, + ); + await DB.postFileNames(avatarID, essayID, fileNames); + return essayID; + } + } + + return -1; + }) + : -1; +}; diff --git a/taehui-fe/src/app/www/logic/file.ts b/taehui-fe/src/app/www/logic/file.ts new file mode 100644 index 0000000..7b5bc69 --- /dev/null +++ b/taehui-fe/src/app/www/logic/file.ts @@ -0,0 +1,30 @@ +import DB from "@/app/www/system/DB"; +import { ESSAY_ENTRY_PATH } from "@/app/www/utilities/Path"; +import { isBannedIP } from "@/app/www/utilities/Utility"; +import { readFile } from "node:fs/promises"; +import { join } from "path"; +import { getDate } from "taehui-ts/date"; + +export const getFile = async (fileName: string, avatarIP: string) => { + return ( + await Promise.all([ + isBannedIP(avatarIP) || + fileName.match(/^.*\.(bmp|gif|jpeg|jpg|png|webp)$/i) || + fileName.match( + /^.*\.(aif|aiff|asf|flac|m4a|mid|midi|mp2|mp3|ogg|opus|raw|wav|wma)$/i, + ) || + fileName.match(/^.*\.(avi|flv|m1v|mkv|mov|mp4|mpeg|mpg|webm|wmv)$/i) + ? Promise.resolve() + : DB.postFileHit(fileName, avatarIP, getDate()), + readFile(join(ESSAY_ENTRY_PATH, fileName)), + ]) + )[1]; +}; + +export const getPostedFileName = async (fileName: string) => { + return DB.getPostedFileName(fileName); +}; + +export const getFileHit = async (fileName: string) => { + return DB.getFileHit(fileName); +}; diff --git a/taehui-fe/src/app/www/logic/forum.ts b/taehui-fe/src/app/www/logic/forum.ts new file mode 100644 index 0000000..e4da5d9 --- /dev/null +++ b/taehui-fe/src/app/www/logic/forum.ts @@ -0,0 +1,21 @@ +import DB from "@/app/www/system/DB"; +import { getLanguage } from "@/app/www/utilities/Utility"; + +export const getEssays = async ( + forumID: string, + language: string, + page: number, + viewUnit: number, +) => { + return DB.ta(async (db) => { + const forum = await DB.getForum(db, forumID); + if (forum) { + return { + title: getLanguage(language, forum), + essayCount: Number(await DB.getEssayCount(forumID)), + essays: await DB.getEssays(forumID, page, viewUnit), + level: forum.level, + }; + } + }); +}; diff --git a/taehui-fe/src/app/www/logic/forums.ts b/taehui-fe/src/app/www/logic/forums.ts new file mode 100644 index 0000000..a291467 --- /dev/null +++ b/taehui-fe/src/app/www/logic/forums.ts @@ -0,0 +1,47 @@ +import DB from "@/app/www/system/DB"; +import { getTitle } from "@/app/www/utilities/Utility"; + +export const getForums = async ( + language: string, + forumGroup?: string, +): Promise< + { + forumID: string; + title: string; + essays: { + essayID: number; + avatarID: string; + date: string; + title: string; + text: string; + }[]; + }[] +> => { + const forums = (await DB.getForums(forumGroup)).map( + ({ + forumID, + title, + title1042, + }): { + forumID: string; + title: string; + essays: { + essayID: number; + avatarID: string; + date: string; + title: string; + text: string; + }[]; + } => ({ + forumID, + title: getTitle(language, { title, title1042 }), + essays: [], + }), + ); + + for await (const forum of forums) { + forum.essays = await DB.getMostEssays(forum.forumID); + } + + return forums; +}; diff --git a/taehui-fe/src/app/www/logic/hit.ts b/taehui-fe/src/app/www/logic/hit.ts new file mode 100644 index 0000000..73a74f9 --- /dev/null +++ b/taehui-fe/src/app/www/logic/hit.ts @@ -0,0 +1,16 @@ +import DB from "@/app/www/system/DB"; +import { isBannedIP } from "@/app/www/utilities/Utility"; +import dayjs from "dayjs"; +import { getDate } from "taehui-ts/date"; + +export const getHit = async () => { + return DB.getHit(getDate(), dayjs().subtract(1, "day").format("YYYY-MM-DD")); +}; + +export const postHit = async (avatarIP: string) => { + if (isBannedIP(avatarIP)) { + return false; + } else { + return DB.postHit(avatarIP, getDate()); + } +}; diff --git a/taehui-fe/src/app/www/logic/want.ts b/taehui-fe/src/app/www/logic/want.ts new file mode 100644 index 0000000..4aaf079 --- /dev/null +++ b/taehui-fe/src/app/www/logic/want.ts @@ -0,0 +1,17 @@ +import DB from "@/app/www/system/DB"; + +export const wantEssay = async ( + wantInput: string, + page: number, + viewUnit: number, +) => { + return DB.wantEssay(wantInput, page, viewUnit); +}; + +export const wantComment = async ( + wantInput: string, + page: number, + viewUnit: number, +) => { + return DB.wantComment(wantInput, page, viewUnit); +}; diff --git a/taehui-fe/src/app/www/media/logIP.ts b/taehui-fe/src/app/www/media/logIP.ts new file mode 100644 index 0000000..8943223 --- /dev/null +++ b/taehui-fe/src/app/www/media/logIP.ts @@ -0,0 +1,29 @@ +import Logger from "@/app/www/system/Logger"; +import { NextRequest } from "next/server"; + +export default function logIP( + route: ( + request: NextRequest, + params: { params: Record }, + ) => Promise, +) { + return async ( + req: NextRequest, + params: { params: Record }, + ) => { + if (!req.headers.has("X-Real-IP")) { + req.headers.set("X-Real-IP", req.ip ?? "localhost"); + } + + try { + const res = await route(req, params); + Logger.info( + `[${req.headers.get("X-Real-IP")}] ${req.method} ${req.url} ${res.status}`, + ); + return res; + } catch (e) { + Logger.error(e); + return new Response(undefined, { status: 500 }); + } + }; +} diff --git a/taehui-fe/src/app/www/media/validateMillis.ts b/taehui-fe/src/app/www/media/validateMillis.ts new file mode 100644 index 0000000..01d4d7b --- /dev/null +++ b/taehui-fe/src/app/www/media/validateMillis.ts @@ -0,0 +1,32 @@ +import dayjs from "dayjs"; +import { NextRequest } from "next/server"; +import { getMillis } from "taehui-ts/date"; + +export default function validateMillis( + route: ( + request: NextRequest, + params: { params: Record }, + ) => Promise, +) { + return async ( + req: NextRequest, + params: { params: Record }, + ) => { + const { headers } = req; + + const millis = headers.get("millis"); + if (!millis) { + return new Response(undefined, { + status: 400, + }); + } + + if (dayjs(Number(millis)).add(1, "minute").isBefore(getMillis())) { + return new Response(undefined, { + status: 401, + }); + } + + return route(req, params); + }; +} diff --git a/taehui-fe/src/app/www/media/validateTotem.ts b/taehui-fe/src/app/www/media/validateTotem.ts new file mode 100644 index 0000000..f209e98 --- /dev/null +++ b/taehui-fe/src/app/www/media/validateTotem.ts @@ -0,0 +1,46 @@ +import DB from "@/app/www/system/DB"; +import dayjs from "dayjs"; +import { NextRequest } from "next/server"; +import { getDatetime } from "taehui-ts/date"; + +export default function validateTotem( + route: ( + req: NextRequest, + params: { params: Record }, + ) => Promise, +) { + return async ( + req: NextRequest, + params: { params: Record }, + ) => { + const totem = req.headers.get("totem"); + if (!totem) { + return new Response(undefined, { status: 400 }); + } + + const data = await DB.ta(async (db) => { + const data = await DB.getAvatarAsTotem(db, totem); + + if (data) { + const datetime = getDatetime(); + if (dayjs(data.date).add(1, "hour").isAfter(datetime)) { + await DB.setTotemDate(db, totem, datetime); + return DB.getAvatarAsAvatarID(db, data.avatarID); + } else { + await DB.wipeTotem(db, totem); + } + } + }); + + if (data) { + req.headers.set("avatarID", encodeURIComponent(data.avatarID)); + req.headers.set("avatarName", encodeURIComponent(data.avatarName)); + req.headers.set("level", data.level.toString()); + req.headers.set("fax", encodeURIComponent(data.fax)); + req.headers.set("avatarIntro", encodeURIComponent(data.avatarIntro)); + return route(req, params); + } else { + return new Response(undefined, { status: 401 }); + } + }; +} diff --git a/taehui-fe/src/app/www/mws/logIP.ts b/taehui-fe/src/app/www/mws/logIP.ts deleted file mode 100644 index 8943223..0000000 --- a/taehui-fe/src/app/www/mws/logIP.ts +++ /dev/null @@ -1,29 +0,0 @@ -import Logger from "@/app/www/system/Logger"; -import { NextRequest } from "next/server"; - -export default function logIP( - route: ( - request: NextRequest, - params: { params: Record }, - ) => Promise, -) { - return async ( - req: NextRequest, - params: { params: Record }, - ) => { - if (!req.headers.has("X-Real-IP")) { - req.headers.set("X-Real-IP", req.ip ?? "localhost"); - } - - try { - const res = await route(req, params); - Logger.info( - `[${req.headers.get("X-Real-IP")}] ${req.method} ${req.url} ${res.status}`, - ); - return res; - } catch (e) { - Logger.error(e); - return new Response(undefined, { status: 500 }); - } - }; -} diff --git a/taehui-fe/src/app/www/mws/validateMillis.ts b/taehui-fe/src/app/www/mws/validateMillis.ts deleted file mode 100644 index bdb73fe..0000000 --- a/taehui-fe/src/app/www/mws/validateMillis.ts +++ /dev/null @@ -1,32 +0,0 @@ -import dayjs from "dayjs"; -import { NextRequest } from "next/server"; -import { getMillis } from "taehui-ts/date"; - -export default function validateMillis( - route: ( - request: NextRequest, - params: { params: Record }, - ) => Promise, -) { - return async ( - req: NextRequest, - params: { params: Record }, - ) => { - const { headers } = req; - - const millis = headers.get("millis"); - if (!millis) { - return new Response(undefined, { - status: 400, - }); - } - - if (dayjs(Number(millis)).add(1, "minute").isBefore(getMillis())) { - return new Response(undefined, { - status: 401, - }); - } - - return await route(req, params); - }; -} diff --git a/taehui-fe/src/app/www/mws/validateTotem.ts b/taehui-fe/src/app/www/mws/validateTotem.ts deleted file mode 100644 index 184441f..0000000 --- a/taehui-fe/src/app/www/mws/validateTotem.ts +++ /dev/null @@ -1,46 +0,0 @@ -import DB from "@/app/www/system/DB"; -import dayjs from "dayjs"; -import { NextRequest } from "next/server"; -import { getDatetime } from "taehui-ts/date"; - -export default function validateTotem( - route: ( - req: NextRequest, - params: { params: Record }, - ) => Promise, -) { - return async ( - req: NextRequest, - params: { params: Record }, - ) => { - const totem = req.headers.get("totem"); - if (!totem) { - return new Response(undefined, { status: 400 }); - } - - const data = await DB.ta(async (db) => { - const data = await DB.getAvatarAsTotem(db, totem); - - if (data) { - const datetime = getDatetime(); - if (dayjs(data.date).add(1, "hour").isAfter(datetime)) { - await DB.setTotemDate(db, totem, datetime); - return DB.getAvatarAsAvatarID(db, data.avatarID); - } else { - await DB.wipeTotem(db, totem); - } - } - }); - - if (data) { - req.headers.set("avatarID", encodeURIComponent(data.avatarID)); - req.headers.set("avatarName", encodeURIComponent(data.avatarName)); - req.headers.set("level", data.level); - req.headers.set("fax", encodeURIComponent(data.fax)); - req.headers.set("avatarIntro", encodeURIComponent(data.avatarIntro)); - return await route(req, params); - } else { - return new Response(undefined, { status: 401 }); - } - }; -} diff --git a/taehui-fe/src/app/www/system/Configure.ts b/taehui-fe/src/app/www/system/Configure.ts deleted file mode 100644 index 5a9c4cd..0000000 --- a/taehui-fe/src/app/www/system/Configure.ts +++ /dev/null @@ -1,29 +0,0 @@ -import logger from "@/app/www/system/Logger"; -import { readFileSync } from "fs"; - -const configure = new (class Configure { - db: { - auth: string; - db: string; - remote: string; - avatar: string; - }; - www: { - qwilight: string; - }; - postLength: number; - - constructor() { - const { db, www, postLength } = JSON.parse( - readFileSync("Configure.json", "utf-8"), - ); - - this.db = db; - this.www = www; - this.postLength = postLength; - - logger.info("Loaded Configure"); - } -})(); - -export default configure; diff --git a/taehui-fe/src/app/www/system/DB.ts b/taehui-fe/src/app/www/system/DB.ts index 47e205b..823d812 100644 --- a/taehui-fe/src/app/www/system/DB.ts +++ b/taehui-fe/src/app/www/system/DB.ts @@ -1,4 +1,3 @@ -import Configure from "@/app/www/system/Configure"; import Logger from "@/app/www/system/Logger"; import { ESSAY_ENTRY_PATH } from "@/app/www/utilities/Path"; import { equalCipher, isTaehui } from "@/app/www/utilities/Utility"; @@ -7,20 +6,15 @@ import { join } from "path"; import { v4 } from "uuid"; -const db = new (class DB { +class DB { pool: Pool; constructor() { - this.pool = createPool({ - host: Configure.db.remote, - user: Configure.db.avatar, - password: Configure.db.auth, - database: Configure.db.db, - }); + this.pool = createPool(process.env.DB as string); Logger.info("Loaded DB"); (async () => { - await this.getDB(async (db) => { + await this.getPool(async (db) => { await db.query(`CREATE TABLE IF NOT EXISTS tn_avatar ( Avatar_ID VARCHAR(20), Avatar_Cipher TEXT, @@ -139,7 +133,7 @@ } async isValidFile(fileName: string) { - return this.getDB( + return this.getPool( async (db) => !!( await db.query( @@ -153,7 +147,7 @@ } async ta(onHandle: (db: PoolConnection) => Promise) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { try { await db.beginTransaction(); const handled = onHandle(db); @@ -166,7 +160,7 @@ }); } - async getDB(onHandle: (db: PoolConnection) => Promise) { + async getPool(onHandle: (db: PoolConnection) => Promise) { let db; try { db = await this.pool.getConnection(); @@ -178,7 +172,16 @@ async getAvatarAsAvatarID(db: PoolConnection, avatarID: string) { const data = ( - await db.query( + await db.query< + { + Avatar_ID: string; + Avatar_Cipher: string; + Avatar_Name: string; + Level: number; + Fax: string; + Avatar_Intro: string; + }[] + >( `SELECT Avatar_ID, Avatar_Cipher, Avatar_Name, Level, Fax, Avatar_Intro FROM tn_avatar WHERE Avatar_ID = ?`, @@ -199,7 +202,7 @@ } async setLastDate(db: PoolConnection, avatarID: string, lastDate: string) { - return db.query( + await db.query( `UPDATE tn_avatar SET Last_Date = ? WHERE Avatar_ID = ?`, @@ -209,7 +212,7 @@ async getTotem(db: PoolConnection, avatarID: string) { const data = ( - await db.query( + await db.query<{ Totem: string; Date: string }[]>( `SELECT Totem, Date FROM tn_totem WHERE Avatar_ID = ?`, @@ -258,7 +261,7 @@ avatarIntro: string, ) { const defaultAvatarCipher = ( - await db.query( + await db.query<{ Avatar_Cipher: string }[]>( `SELECT Avatar_Cipher FROM tn_avatar WHERE Avatar_ID = ?`, @@ -266,7 +269,7 @@ ) )[0]?.["Avatar_Cipher"]; return ( - defaultAvatarCipher && + !!defaultAvatarCipher && (await equalCipher(defaultAvatarCipher, avatarCipher)) && ( await db.query( @@ -286,7 +289,7 @@ } async doModifyAvatarIntro(avatarID: string, avatarIntro: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return ( ( await db.query( @@ -308,7 +311,7 @@ fax: string, datetime: string, ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return ( ( await db.query( @@ -333,7 +336,7 @@ async getAvatarAsTotem(db: PoolConnection, totem: string) { const data = ( - await db.query( + await db.query<{ Avatar_ID: string; Date: string }[]>( `SELECT Avatar_ID, Date FROM tn_totem WHERE Totem = ?`, @@ -358,13 +361,12 @@ } async wipeTotem(db: PoolConnection, avatarID: string) { - const { affectedRows } = await db.query( + await db.query( `DELETE FROM tn_totem WHERE Avatar_ID = ?`, [avatarID], ); - return affectedRows; } async getForum(db: PoolConnection, forumID: string) { @@ -392,7 +394,7 @@ } async getForums(forumGroup?: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return ( forumGroup ? await db.query< @@ -432,7 +434,7 @@ } async getBeforeEssay(forumID: string, datetime: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const dataBefore = ( await db.query( `SELECT Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title @@ -459,7 +461,7 @@ } async getLaterEssay(forumID: string, datetime: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const dataLater = ( await db.query( `SELECT Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title @@ -486,8 +488,8 @@ } async getLatestEssays() { - return this.getDB(async (db) => { - const rs = await db.query( + return this.getPool(async (db) => { + const data = await db.query( `SELECT Forum_ID, Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title, tn_essay.Text FROM tn_essay, tn_avatar WHERE tn_avatar.Avatar_ID = tn_essay.Avatar_ID @@ -495,7 +497,7 @@ LIMIT 5`, ); return Promise.all( - rs.map( + data.map( async (data: { Forum_ID: string; Essay_ID: number; @@ -530,7 +532,7 @@ } async getCommentCount(essayID: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const data = ( await db.query( `SELECT COUNT(Comment_ID) AS Comment_Count @@ -546,7 +548,7 @@ } async getHitCount(essayID: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const data = ( await db.query( `SELECT COUNT(Avatar_IP) AS Hit_Count @@ -579,7 +581,7 @@ essayID: number, fileNames: [string, string][], ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { for await (const [fileName, postedFileName] of fileNames) { await db.query( `INSERT INTO tn_file @@ -609,12 +611,12 @@ title: string, text: string, ) { - const { insertId } = await db.query<{ insertId: number }>( + const { insertId } = await db.query( `INSERT INTO tn_essay(Forum_ID, Avatar_ID, Date, Title, Text) VALUES(?, ?, ?, ?, ?)`, [forumID, avatarID, datetime, title, text], ); - return insertId; + return Number(insertId); } async doModifyEssay( @@ -642,7 +644,7 @@ } async wipeEssay(essayID: number, avatarID: string, level: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { affectedRows } = isTaehui(level) ? await db.query( `DELETE @@ -661,9 +663,9 @@ } async getForumTitles(forumID: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const data = ( - await db.query( + await db.query<{ Title: string; Title_1042: string }[]>( `SELECT Title, Title_1042 FROM tn_forum WHERE Forum_ID = ?`, @@ -681,9 +683,19 @@ } async getEssay(essayID: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const data = ( - await db.query( + await db.query< + { + Forum_ID: string; + Essay_ID: number; + Avatar_ID: string; + Avatar_Name: string; + Date: string; + Title: string; + Text: string; + }[] + >( `SELECT Forum_ID, Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title, Text FROM tn_essay, tn_avatar WHERE Essay_ID = ? AND tn_avatar.Avatar_ID = tn_essay.Avatar_ID`, @@ -695,7 +707,7 @@ const forumID = data["Forum_ID"]; const forumTitles = await this.getForumTitles(forumID); if (forumTitles) { - const essayID = Number(data["Essay_ID"]); + const essayID = data["Essay_ID"]; const date = data["Date"]; return { forumTitle: forumTitles.title, @@ -716,24 +728,29 @@ } async getEssayCount(forumID: string) { - return this.getDB(async (db) => { - const data = ( - await db.query( + return this.getPool(async (db) => { + return ( + await db.query<{ Essay_Count: number }[]>( `SELECT COUNT(Essay_ID) AS Essay_Count FROM tn_essay WHERE Forum_ID = ?`, [forumID], ) - )[0]; - if (data) { - return data["Essay_Count"]; - } + )[0]?.["Essay_Count"]; }); } async getEssays(forumID: string, page: number, viewUnit: number) { - return this.getDB(async (db) => { - const rs = await db.query( + return this.getPool(async (db) => { + const data = await db.query< + { + Essay_ID: number; + Avatar_ID: string; + Avatar_Name: string; + Date: string; + Title: string; + }[] + >( `SELECT Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title FROM tn_essay, tn_avatar WHERE Forum_ID = ? AND tn_avatar.Avatar_ID = tn_essay.Avatar_ID @@ -742,35 +759,36 @@ [forumID, (page - 1) * viewUnit, viewUnit], ); return Promise.all( - rs.map( - async (data: { - Essay_ID: number; - Avatar_ID: string; - Avatar_Name: string; - Date: string; - Title: string; - }) => { - const essayID = Number(data["Essay_ID"]); - return { - essayID: essayID, - avatarID: data["Avatar_ID"], - avatarName: data["Avatar_Name"], - date: data["Date"], - title: data["Title"], - commentCount: Number(await this.getCommentCount(essayID)), - hitCount: Number(await this.getHitCount(essayID)), - }; - }, - ), + data.map(async (data) => { + const essayID = Number(data["Essay_ID"]); + return { + essayID: essayID, + avatarID: data["Avatar_ID"], + avatarName: data["Avatar_Name"], + date: data["Date"], + title: data["Title"], + commentCount: Number(await this.getCommentCount(essayID)), + hitCount: Number(await this.getHitCount(essayID)), + }; + }), ); }); } async wantEssay(wantInput: string, page: number, viewUnit: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return Promise.all( ( - await db.query( + await db.query< + { + Forum_ID: string; + Essay_ID: number; + Avatar_ID: string; + Avatar_Name: string; + Date: string; + Title: string; + }[] + >( `SELECT Forum_ID, Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title FROM tn_essay, tn_avatar WHERE tn_avatar.Avatar_ID = tn_essay.Avatar_ID AND MATCH(Text) AGAINST(? IN BOOLEAN MODE) @@ -778,37 +796,37 @@ LIMIT ?, ?`, [wantInput, (page - 1) * viewUnit, viewUnit], ) - ).map( - async (data: { - Forum_ID: string; - Essay_ID: number; - Avatar_ID: string; - Avatar_Name: string; - Date: string; - Title: string; - }) => { - const essayID = Number(data["Essay_ID"]); - return { - forumID: data["Forum_ID"], - essayID: essayID, - avatarID: data["Avatar_ID"], - avatarName: data["Avatar_Name"], - date: data["Date"], - title: data["Title"], - commentCount: Number(await this.getCommentCount(essayID)), - hitCount: Number(await this.getHitCount(essayID)), - }; - }, - ), + ).map(async (data) => { + const essayID = Number(data["Essay_ID"]); + return { + forumID: data["Forum_ID"], + essayID: essayID, + avatarID: data["Avatar_ID"], + avatarName: data["Avatar_Name"], + date: data["Date"], + title: data["Title"], + commentCount: Number(await this.getCommentCount(essayID)), + hitCount: Number(await this.getHitCount(essayID)), + }; + }), ); }); } async wantComment(wantInput: string, page: number, viewUnit: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return Promise.all( ( - await db.query( + await db.query< + { + Forum_ID: string; + Essay_ID: number; + Avatar_ID: string; + Avatar_Name: string; + Date: string; + Text: string; + }[] + >( `SELECT Forum_ID, tn_comment.Essay_ID, tn_comment.Avatar_ID, Avatar_Name, tn_comment.Date, tn_comment.Text FROM tn_essay, tn_comment, tn_avatar WHERE tn_essay.Essay_ID = tn_comment.Essay_ID AND tn_comment.Avatar_ID = tn_avatar.Avatar_ID AND MATCH(tn_comment.Text) AGAINST(? IN BOOLEAN MODE) @@ -816,31 +834,22 @@ LIMIT ?, ?`, [wantInput, (page - 1) * viewUnit, viewUnit], ) - ).map( - async (data: { - Forum_ID: string; - Essay_ID: number; - Avatar_ID: string; - Avatar_Name: string; - Date: string; - Text: string; - }) => { - return { - forumID: data["Forum_ID"], - essayID: Number(data["Essay_ID"]), - avatarID: data["Avatar_ID"], - avatarName: data["Avatar_Name"], - date: data["Date"], - text: data["Text"], - }; - }, - ), + ).map(async (data) => { + return { + forumID: data["Forum_ID"], + essayID: Number(data["Essay_ID"]), + avatarID: data["Avatar_ID"], + avatarName: data["Avatar_Name"], + date: data["Date"], + text: data["Text"], + }; + }), ); }); } async postEssayHit(essayID: number, avatarIP: string, date: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { try { await db.query( `INSERT INTO tn_essay_hit @@ -856,7 +865,7 @@ } async getEssayHit(essayID: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return Number( ( await db.query( @@ -877,7 +886,7 @@ datetime: string, text: string, ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { insertId } = await db.query( `INSERT INTO tn_comment(Target_Comment_ID, Essay_ID, Avatar_ID, Date, Text) VALUES(?, ?, ?, ?, ?)`, @@ -893,7 +902,7 @@ text: string, level: number, ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { affectedRows } = isTaehui(level) ? await db.query( `UPDATE tn_comment @@ -912,7 +921,7 @@ } async wipeComment(commentID: number, avatarID: string, level: number) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { affectedRows } = isTaehui(level) ? await db.query( `DELETE @@ -931,8 +940,8 @@ } async getComments(essayID: number) { - return this.getDB(async (db) => { - const rs = await db.query< + return this.getPool(async (db) => { + const data = await db.query< { Comment_ID: number; Target_Comment_ID: number; @@ -948,7 +957,7 @@ ORDER BY tn_comment.Date`, [essayID], ); - return rs.map((data) => ({ + return data.map((data) => ({ commentID: data["Comment_ID"], targetCommentID: data["Target_Comment_ID"], avatarID: data["Avatar_ID"], @@ -960,16 +969,9 @@ } async getLatestComments() { - return this.getDB(async (db) => { - const rs = await db.query( - `SELECT Comment_ID, Forum_ID, tn_comment.Essay_ID AS Essay_ID, tn_comment.Avatar_ID, Avatar_Name, tn_comment.Date, tn_comment.Text - FROM tn_comment, tn_essay, tn_avatar - WHERE tn_comment.Essay_ID = tn_essay.Essay_ID AND tn_avatar.Avatar_ID = tn_comment.Avatar_ID - ORDER BY tn_comment.Date DESC - LIMIT 5`, - ); - return rs.map( - (data: { + return this.getPool(async (db) => { + const data = await db.query< + { Comment_ID: number; Forum_ID: string; Essay_ID: number; @@ -977,22 +979,29 @@ Avatar_Name: string; Date: string; Text: string; - }) => ({ - commentID: data["Comment_ID"], - forumID: data["Forum_ID"], - essayID: data["Essay_ID"], - avatarID: data["Avatar_ID"], - avatarName: data["Avatar_Name"], - date: data["Date"], - text: data["Text"], - }), + }[] + >( + `SELECT Comment_ID, Forum_ID, tn_comment.Essay_ID AS Essay_ID, tn_comment.Avatar_ID, Avatar_Name, tn_comment.Date, tn_comment.Text + FROM tn_comment, tn_essay, tn_avatar + WHERE tn_comment.Essay_ID = tn_essay.Essay_ID AND tn_avatar.Avatar_ID = tn_comment.Avatar_ID + ORDER BY tn_comment.Date DESC + LIMIT 5`, ); + return data.map((data) => ({ + commentID: data["Comment_ID"], + forumID: data["Forum_ID"], + essayID: data["Essay_ID"], + avatarID: data["Avatar_ID"], + avatarName: data["Avatar_Name"], + date: data["Date"], + text: data["Text"], + })); }); } async getCommentary() { - return this.getDB(async (db) => { - const rs = await db.query< + return this.getPool(async (db) => { + const data = await db.query< { Commentary_ID: number; Avatar_Name: string; @@ -1004,7 +1013,7 @@ FROM tn_commentary ORDER BY Date DESC`, ); - return rs.map((data) => ({ + return data.map((data) => ({ commentaryID: data["Commentary_ID"], avatarName: data["Avatar_Name"], date: data["Date"], @@ -1020,7 +1029,7 @@ datetime: string, text: string, ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { insertId } = await db.query( `INSERT INTO tn_commentary(Avatar_Name, Avatar_Cipher, Avatar_IP, Date, Text) VALUES(?, ?, ?, ?, ?)`, @@ -1035,7 +1044,7 @@ avatarCipher: string, text: string, ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { affectedRows } = await db.query( `UPDATE tn_commentary SET Text = ? @@ -1047,7 +1056,7 @@ } async wipeCommentary(commentaryID: number, avatarCipher: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { affectedRows } = await db.query( `DELETE FROM tn_commentary @@ -1059,8 +1068,8 @@ } async getHit(date: string, dateBefore: string) { - return this.getDB(async (db) => { - const rs = await db.query( + return this.getPool(async (db) => { + const data = await db.query( `SELECT DATE_FORMAT(Date, "%Y-%m-%d") AS Date, COUNT(Avatar_IP) AS Count FROM tn_hit GROUP BY Date @@ -1069,18 +1078,19 @@ ); return [ Number( - rs.find(({ Date }: { Date: string }) => Date === dateBefore)?.Count ?? - 0, + data.find(({ Date }: { Date: string }) => Date === dateBefore)?.[ + "Count" + ] ?? 0, ), Number( - rs.find(({ Date }: { Date: string }) => Date === date)?.Count ?? 0, + data.find(({ Date }: { Date: string }) => Date === date)?.Count ?? 0, ), ]; }); } async postHit(avatarIP: string, date: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { try { await db.query( `INSERT INTO tn_hit @@ -1098,7 +1108,7 @@ } async postFileHit(fileName: string, avatarIP: string, date: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { try { await db.query( `INSERT INTO tn_file_hit @@ -1114,10 +1124,10 @@ } async getPostedFileName(fileName: string) { - return this.getDB( + return this.getPool( async (db) => ( - await db.query( + await db.query<{ Posted_File_Name: string }[]>( `SELECT Posted_File_Name FROM tn_file WHERE File_Name = ?`, @@ -1128,7 +1138,7 @@ } async getFileHit(fileName: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return Number( ( await db.query( @@ -1137,17 +1147,19 @@ WHERE File_Name = ?`, [fileName], ) - )[0]?.Count ?? 0, + )[0]?.["Count"] ?? 0, ); }); } async getLatestAvatars() { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return Promise.all( ["Date", "Last_Date"].map(async (date) => { return ( - await db.query( + await db.query< + { Avatar_ID: string; Avatar_Name: string; Date: string }[] + >( `SELECT Avatar_ID, Avatar_Name, ${date} AS Date FROM tn_avatar ORDER BY Date DESC @@ -1180,18 +1192,18 @@ text: string, datetime: string, ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { insertId } = await db.query( `INSERT INTO tn_auto_essay(Forum_ID, Avatar_ID, Title, Text, Date) VALUES(?, ?, ?, ?, ?)`, [forumID, avatarID, title, text, datetime], ); - return insertId; + return Number(insertId); }); } async getAutoEssays(forumID: string, avatarID: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { return ( await db.query< { @@ -1222,7 +1234,7 @@ text: string, datetime: string, ) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { affectedRows } = await db.query( `UPDATE tn_auto_essay SET Title = ?, Text = ?, Date = ? @@ -1234,7 +1246,7 @@ } async wipeAutoEssay(autoEssayID: number, avatarID: string) { - return this.getDB(async (db) => { + return this.getPool(async (db) => { const { affectedRows } = await db.query( `DELETE FROM tn_auto_essay @@ -1244,6 +1256,11 @@ return affectedRows > 0; }); } -})(); +} -export default db; +declare module globalThis { + let db: DB; +} + +if (!globalThis.db) globalThis.db = new DB(); +export default globalThis.db; diff --git a/taehui-fe/src/app/www/systems/autoEssay.ts b/taehui-fe/src/app/www/systems/autoEssay.ts deleted file mode 100644 index 43c9750..0000000 --- a/taehui-fe/src/app/www/systems/autoEssay.ts +++ /dev/null @@ -1,34 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { getDatetime } from "taehui-ts/date"; - -export const postAutoEssay = async ( - forumID: string, - avatarID: string, - title: string, - text: string, -) => { - return DB.postAutoEssay(forumID, avatarID, title, text, getDatetime()); -}; - -export const getAutoEssays = async (forumID: string, avatarID: string) => { - return DB.getAutoEssays(forumID, avatarID); -}; - -export const doModifyAutoEssay = async ( - autoEssayID: number, - avatarID: string, - title: string, - text: string, -) => { - return DB.doModifyAutoEssay( - autoEssayID, - avatarID, - title, - text, - getDatetime(), - ); -}; - -export const wipeAutoEssay = async (autoEssayID: number, avatarID: string) => { - return DB.wipeAutoEssay(autoEssayID, avatarID); -}; diff --git a/taehui-fe/src/app/www/systems/avatar.ts b/taehui-fe/src/app/www/systems/avatar.ts deleted file mode 100644 index dc2ce21..0000000 --- a/taehui-fe/src/app/www/systems/avatar.ts +++ /dev/null @@ -1,177 +0,0 @@ -import Configure from "@/app/www/system/Configure"; -import DB from "@/app/www/system/DB"; -import { AVATAR_ENTRY_PATH } from "@/app/www/utilities/Path"; -import { equalCipher } from "@/app/www/utilities/Utility"; -import { pbkdf2, randomBytes } from "crypto"; -import dayjs from "dayjs"; -import { readFile } from "fs"; -import { PoolConnection } from "mariadb"; -import { join } from "path"; -import { getDatetime } from "taehui-ts/date"; -import { promisify } from "util"; - -const pw = promisify(pbkdf2); -const rf = promisify(readFile); - -const putTotem = async (db: PoolConnection, avatarID: string) => { - const data = await DB.getTotem(db, avatarID); - - const datetime = getDatetime(); - if (data && dayjs(data.date).add(1, "hour").isAfter(datetime)) { - await DB.setTotemDateAsAvatarID(db, avatarID, datetime); - return data.totem; - } - - return DB.putTotem(db, avatarID, datetime); -}; - -export const getTotem = async ( - pendingAvatarID: string, - pendingAvatarCipher: string, -) => { - return DB.ta(async (db) => { - const data = await DB.getAvatarAsAvatarID(db, pendingAvatarID); - if (data) { - const { avatarID, avatarCipher, avatarName, level, fax, avatarIntro } = - data; - const isOK = await equalCipher(avatarCipher, pendingAvatarCipher); - if (isOK) { - await DB.setLastDate(db, avatarID, getDatetime()); - return { - totem: await putTotem(db, avatarID), - avatarID, - avatarName, - level, - fax, - avatarIntro, - }; - } else { - return null; - } - } - }); -}; - -const getDBCipher = async (avatarCipher: string) => { - const salt = randomBytes(24).toString("base64"); - - return `sha256:12000:${salt}:${Buffer.from( - await pw(avatarCipher, salt, 12000, 24, "sha256"), - ).toString("base64")}`; -}; - -export const doModifyAvatar = async ( - avatarID: string, - avatarCipher: string, - avatarCipherModified: string, - avatarName: string, - fax: string, - avatarIntro: string, -) => { - if ( - avatarCipher && - avatarName && - avatarName.length <= 16 && - (!fax || /^.+@.+$/.test(fax)) - ) { - return DB.ta(async (db) => { - if ( - await DB.doModifyAvatar( - db, - avatarID, - avatarCipher, - avatarCipherModified && (await getDBCipher(avatarCipherModified)), - avatarName, - fax, - avatarIntro, - ) - ) { - if (avatarCipherModified) { - await DB.wipeTotem(db, avatarID); - await fetch(`${Configure.www.qwilight}/totem`, { - method: "PATCH", - body: JSON.stringify({ avatarID }), - }); - } - return true; - } else { - return false; - } - }); - } else { - return false; - } -}; - -export const doModifyAvatarIntro = async ( - avatarID: string, - avatarIntro: string, -) => { - return DB.doModifyAvatarIntro(avatarID, avatarIntro); -}; - -export const postAvatar = async ( - avatarID: string, - avatarCipher: string, - avatarName: string, - avatarIP: string, - fax: string, -) => { - return ( - avatarID && - !avatarID.startsWith("@") && - !avatarID.startsWith("#") && - !avatarID.startsWith("$") && - !avatarID.startsWith("*") && - avatarCipher && - avatarName && - avatarName.length <= 16 && - (!fax || /^.+@.+$/.test(fax)) && - DB.ta(async (db) => { - if (await DB.getAvatarAsAvatarID(db, avatarID)) { - return false; - } else { - return DB.postAvatar( - avatarID, - await getDBCipher(avatarCipher), - avatarName, - avatarIP, - fax, - getDatetime(), - ); - } - }) - ); -}; - -export const wipeTotem = async (avatarID: string) => { - return DB.ta(async (db) => - Promise.all([ - DB.setLastDate(db, avatarID, getDatetime()), - DB.wipeTotem(db, avatarID), - ]), - ); -}; - -export const getAvatarDrawing = async (avatarID: string) => { - try { - return await rf(join(AVATAR_ENTRY_PATH, avatarID + ".png")); - } catch (e: any) { - if (e.code === "ENOENT") { - return null; - } - - throw e; - } -}; - -export const getLatestAvatars = async () => { - return DB.getLatestAvatars(); -}; - -export const doInvalidateDrawing = async (avatarID: string) => { - await fetch(`${Configure.www.qwilight}/drawing`, { - method: "PATCH", - body: JSON.stringify({ avatarID }), - }); -}; diff --git a/taehui-fe/src/app/www/systems/comment.ts b/taehui-fe/src/app/www/systems/comment.ts deleted file mode 100644 index cb9c0fc..0000000 --- a/taehui-fe/src/app/www/systems/comment.ts +++ /dev/null @@ -1,60 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { CommentItem } from "@/app/www/type/CommentItem"; -import { getDatetime } from "taehui-ts/date"; - -export const getComments = async (essayID: number) => { - const comments = await DB.getComments(essayID); - const data = new Map(); - const commentItems = new Map(); - - comments.forEach(({ targetCommentID, commentID, ...comment }) => { - const commentItem: CommentItem = { - commentID, - ...comment, - comments: [], - }; - if (targetCommentID !== -1) { - data.get(targetCommentID)?.comments?.push(commentItem); - } else { - commentItems.set(commentID, commentItem); - } - data.set(commentID, commentItem); - }); - - return Array.from(commentItems.values()); -}; - -export const postComment = async ( - targetCommentID: number, - essayID: number, - avatarID: string, - level: number, - text: string, -) => { - return ( - 1 <= level && - text && - DB.postComment(targetCommentID, essayID, avatarID, getDatetime(), text) - ); -}; - -export const doModifyComment = async ( - commentID: number, - avatarID: string, - text: string, - level: number, -) => { - return text && DB.doModifyComment(commentID, avatarID, text, level); -}; - -export const wipeComment = async ( - commentID: number, - avatarID: string, - level: number, -) => { - return DB.wipeComment(commentID, avatarID, level); -}; - -export const getLatestComments = async () => { - return DB.getLatestComments(); -}; diff --git a/taehui-fe/src/app/www/systems/commentary.ts b/taehui-fe/src/app/www/systems/commentary.ts deleted file mode 100644 index 226d5b9..0000000 --- a/taehui-fe/src/app/www/systems/commentary.ts +++ /dev/null @@ -1,38 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { getDatetime } from "taehui-ts/date"; - -export const getCommentary = async () => { - return DB.getCommentary(); -}; - -export const postCommentary = async ( - avatarName: string, - avatarCipher: string, - avatarIP: string, - text: string, -) => { - return ( - text && - avatarCipher && - DB.postCommentary(avatarName, avatarCipher, avatarIP, getDatetime(), text) - ); -}; - -export const doModifyCommentary = async ( - commentaryID: number, - avatarCipher: string, - text: string, -) => { - return ( - avatarCipher && - text && - DB.doModifyCommentary(commentaryID, avatarCipher, text) - ); -}; - -export const wipeCommentary = async ( - commentaryID: number, - avatarCipher: string, -) => { - return avatarCipher && DB.wipeCommentary(commentaryID, avatarCipher); -}; diff --git a/taehui-fe/src/app/www/systems/essay.ts b/taehui-fe/src/app/www/systems/essay.ts deleted file mode 100644 index fca33e6..0000000 --- a/taehui-fe/src/app/www/systems/essay.ts +++ /dev/null @@ -1,143 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { ESSAY_ENTRY_PATH } from "@/app/www/utilities/Path"; -import { - getFileNames, - getTitle, - isBannedIP, -} from "@/app/www/utilities/Utility"; -import { unlink } from "fs"; -import { join } from "path"; -import { getDate, getDatetime } from "taehui-ts/date"; -import { promisify } from "util"; - -const wipeFile = promisify(unlink); - -export const getEssay = async ( - essayID: number, - language: string, - avatarIP: string, -) => { - if (!isBannedIP(avatarIP)) { - await DB.postEssayHit(essayID, avatarIP, getDate()); - } - const essay = await DB.getEssay(essayID); - if (essay) { - const { forumTitle, forumTitle1042, ...restEssay } = essay; - return { - ...restEssay, - forumTitle: getTitle(language, { - title: forumTitle, - title1042: forumTitle1042, - }), - }; - } -}; - -export const getEssayHit = async (essayID: number) => { - return DB.getEssayHit(essayID); -}; - -export const doModifyEssay = async ( - essayID: number, - avatarID: string, - title: string, - text: string, - level: number, -) => { - return ( - title && - text && - DB.ta(async (db) => { - if (await DB.doModifyEssay(db, essayID, avatarID, title, text, level)) { - const lastFileNames = await DB.getFileNames(db, essayID); - const fileNames = getFileNames(text); - const hrefs = fileNames.map(([fileName]) => fileName); - - await wipeFiles( - lastFileNames.filter((lastFileName) => !hrefs.includes(lastFileName)), - ); - - await DB.postFileNames( - avatarID, - essayID, - fileNames.filter(([fileName]) => !lastFileNames.includes(fileName)), - ); - - return true; - } else { - return false; - } - }) - ); -}; - -export const wipeEssay = async ( - essayID: number, - avatarID: string, - level: number, -) => { - return DB.ta(async (db) => { - const fileNames = await DB.getFileNames(db, essayID); - if (await DB.wipeEssay(essayID, avatarID, level)) { - await wipeFiles(fileNames); - return true; - } else { - return false; - } - }); -}; - -export const getLatestEssays = async (language: string) => { - return (await DB.getLatestEssays()).map( - ({ forumTitle, forumTitle1042, ...restLatestEssay }) => { - return { - ...restLatestEssay, - forumTitle: getTitle(language, { - title: forumTitle, - title1042: forumTitle1042, - }), - }; - }, - ); -}; - -const wipeFiles = async (fileNames: string[]) => { - await DB.wipeFileNames(fileNames); - for await (const fileName of fileNames) { - try { - await wipeFile(join(ESSAY_ENTRY_PATH, fileName)); - } catch {} - } -}; - -export const postEssay = async ( - forumID: string, - avatarID: string, - level: number, - title: string, - text: string, -) => { - return title && text - ? await DB.ta(async (db) => { - const forum = await DB.getForum(db, forumID); - if (forum) { - if (forum.level <= level) { - const fileNames = getFileNames(text); - - const essayID = await DB.postEssay( - db, - forumID, - avatarID, - getDatetime(), - title, - text, - ); - await DB.postFileNames(avatarID, essayID, fileNames); - return essayID; - } - } - - return -1; - }) - : -1; -}; diff --git a/taehui-fe/src/app/www/systems/file.ts b/taehui-fe/src/app/www/systems/file.ts deleted file mode 100644 index 62df81a..0000000 --- a/taehui-fe/src/app/www/systems/file.ts +++ /dev/null @@ -1,30 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { ESSAY_ENTRY_PATH } from "@/app/www/utilities/Path"; -import { isBannedIP } from "@/app/www/utilities/Utility"; -import { readFile } from "node:fs/promises"; -import { join } from "path"; -import { getDate } from "taehui-ts/date"; - -export const getFile = async (fileName: string, avatarIP: string) => { - return ( - await Promise.all([ - isBannedIP(avatarIP) || - fileName.match(/^.*\.(bmp|gif|jpeg|jpg|png|webp)$/i) || - fileName.match( - /^.*\.(aif|aiff|asf|flac|m4a|mid|midi|mp2|mp3|ogg|opus|raw|wav|wma)$/i, - ) || - fileName.match(/^.*\.(avi|flv|m1v|mkv|mov|mp4|mpeg|mpg|webm|wmv)$/i) - ? Promise.resolve() - : DB.postFileHit(fileName, avatarIP, getDate()), - readFile(join(ESSAY_ENTRY_PATH, fileName)), - ]) - )[1]; -}; - -export const getPostedFileName = async (fileName: string) => { - return await DB.getPostedFileName(fileName); -}; - -export const getFileHit = async (fileName: string) => { - return await DB.getFileHit(fileName); -}; diff --git a/taehui-fe/src/app/www/systems/forum.ts b/taehui-fe/src/app/www/systems/forum.ts deleted file mode 100644 index e4da5d9..0000000 --- a/taehui-fe/src/app/www/systems/forum.ts +++ /dev/null @@ -1,21 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { getLanguage } from "@/app/www/utilities/Utility"; - -export const getEssays = async ( - forumID: string, - language: string, - page: number, - viewUnit: number, -) => { - return DB.ta(async (db) => { - const forum = await DB.getForum(db, forumID); - if (forum) { - return { - title: getLanguage(language, forum), - essayCount: Number(await DB.getEssayCount(forumID)), - essays: await DB.getEssays(forumID, page, viewUnit), - level: forum.level, - }; - } - }); -}; diff --git a/taehui-fe/src/app/www/systems/forums.ts b/taehui-fe/src/app/www/systems/forums.ts deleted file mode 100644 index a291467..0000000 --- a/taehui-fe/src/app/www/systems/forums.ts +++ /dev/null @@ -1,47 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { getTitle } from "@/app/www/utilities/Utility"; - -export const getForums = async ( - language: string, - forumGroup?: string, -): Promise< - { - forumID: string; - title: string; - essays: { - essayID: number; - avatarID: string; - date: string; - title: string; - text: string; - }[]; - }[] -> => { - const forums = (await DB.getForums(forumGroup)).map( - ({ - forumID, - title, - title1042, - }): { - forumID: string; - title: string; - essays: { - essayID: number; - avatarID: string; - date: string; - title: string; - text: string; - }[]; - } => ({ - forumID, - title: getTitle(language, { title, title1042 }), - essays: [], - }), - ); - - for await (const forum of forums) { - forum.essays = await DB.getMostEssays(forum.forumID); - } - - return forums; -}; diff --git a/taehui-fe/src/app/www/systems/hit.ts b/taehui-fe/src/app/www/systems/hit.ts deleted file mode 100644 index 73a74f9..0000000 --- a/taehui-fe/src/app/www/systems/hit.ts +++ /dev/null @@ -1,16 +0,0 @@ -import DB from "@/app/www/system/DB"; -import { isBannedIP } from "@/app/www/utilities/Utility"; -import dayjs from "dayjs"; -import { getDate } from "taehui-ts/date"; - -export const getHit = async () => { - return DB.getHit(getDate(), dayjs().subtract(1, "day").format("YYYY-MM-DD")); -}; - -export const postHit = async (avatarIP: string) => { - if (isBannedIP(avatarIP)) { - return false; - } else { - return DB.postHit(avatarIP, getDate()); - } -}; diff --git a/taehui-fe/src/app/www/systems/want.ts b/taehui-fe/src/app/www/systems/want.ts deleted file mode 100644 index 4aaf079..0000000 --- a/taehui-fe/src/app/www/systems/want.ts +++ /dev/null @@ -1,17 +0,0 @@ -import DB from "@/app/www/system/DB"; - -export const wantEssay = async ( - wantInput: string, - page: number, - viewUnit: number, -) => { - return DB.wantEssay(wantInput, page, viewUnit); -}; - -export const wantComment = async ( - wantInput: string, - page: number, - viewUnit: number, -) => { - return DB.wantComment(wantInput, page, viewUnit); -}; diff --git "a/taehui-fe/src/app/www/want/\133wantVariety\135/\133textInput\135/route.ts" "b/taehui-fe/src/app/www/want/\133wantVariety\135/\133textInput\135/route.ts" index 042a35c..47100e4 100644 --- "a/taehui-fe/src/app/www/want/\133wantVariety\135/\133textInput\135/route.ts" +++ "b/taehui-fe/src/app/www/want/\133wantVariety\135/\133textInput\135/route.ts" @@ -1,5 +1,5 @@ -import logIP from "@/app/www/mws/logIP"; -import { wantComment, wantEssay } from "@/app/www/systems/want"; +import logIP from "@/app/www/media/logIP"; +import { wantComment, wantEssay } from "@/app/www/logic/want"; export const GET = logIP( async (