From 4c69f57aaa833f3da1cbcd425d154d88e3a49512 Mon Sep 17 00:00:00 2001 From: Miao_Spring <539943419@qq.com> Date: Mon, 13 Jan 2025 17:22:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E9=89=B4=E6=9D=83=E7=9B=B8=E5=85=B3api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hooks/useFetch.ts | 27 +++ package.json | 6 + pages/posts/index.vue | 3 +- pages/user/index.vue | 83 ++++++- pnpm-lock.yaml | 339 ++++++++++++++++++++++++++++- server/api/auth/login.ts | 4 - server/api/posts/editPost.ts | 84 +++++++ server/api/posts/getPostContent.ts | 35 ++- server/api/posts/getPostList.ts | 53 +++-- server/api/posts/uploadPost.ts | 69 ++++++ server/api/test/testDir.ts | 2 +- server/api/user/login.ts | 27 +++ server/api/user/refreshToken.ts | 20 ++ server/api/user/register.ts | 34 +++ server/api/user/updatePassword.ts | 31 +++ server/middleware/auth.ts | 21 +- server/middleware/checkUserData.ts | 2 +- server/utils/cacheRes.ts | 9 + server/utils/checkUserData.ts | 22 -- server/utils/createToken.ts | 8 + server/utils/getKey.ts | 7 + server/utils/initUserData.ts | 85 ++++++++ 22 files changed, 903 insertions(+), 68 deletions(-) create mode 100644 hooks/useFetch.ts delete mode 100644 server/api/auth/login.ts create mode 100644 server/api/posts/editPost.ts create mode 100644 server/api/posts/uploadPost.ts create mode 100644 server/api/user/login.ts create mode 100644 server/api/user/refreshToken.ts create mode 100644 server/api/user/register.ts create mode 100644 server/api/user/updatePassword.ts create mode 100644 server/utils/cacheRes.ts delete mode 100644 server/utils/checkUserData.ts create mode 100644 server/utils/createToken.ts create mode 100644 server/utils/getKey.ts create mode 100644 server/utils/initUserData.ts diff --git a/hooks/useFetch.ts b/hooks/useFetch.ts new file mode 100644 index 0000000..b80be50 --- /dev/null +++ b/hooks/useFetch.ts @@ -0,0 +1,27 @@ + +export const uploadPost = (body: { + title: string, + summary: string, + type: string, + tags: string[], + url: string, + date: number, + content: string +}) => $fetch('/api/posts/uploadPost', { + method: 'POST', + body +}) + +export const updatePost = (body: { + id: number, + title: string, + summary: string, + type: string, + tags: string[], + url: string, + date: number, + content: string +}) => $fetch('/api/posts/uploadPost', { + method: 'POST', + body +}) \ No newline at end of file diff --git a/package.json b/package.json index f7dc70f..52bf516 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,10 @@ "dependencies": { "@pinia/nuxt": "^0.9.0", "@types/node": "^22.10.5", + "bcryptjs": "^2.4.3", + "better-sqlite3": "11.3.0", "dayjs": "^1.11.13", + "jsonwebtoken": "^9.0.2", "markdown-it": "^14.1.0", "node-fetch": "^3.3.2", "nuxt": "^3.15.1", @@ -24,6 +27,9 @@ }, "devDependencies": { "@element-plus/nuxt": "^1.1.1", + "@types/bcryptjs": "^2.4.6", + "@types/better-sqlite3": "^7.6.12", + "@types/jsonwebtoken": "^9.0.7", "@types/markdown-it": "^14.1.2", "element-plus": "^2.9.3", "sass": "^1.83.1" diff --git a/pages/posts/index.vue b/pages/posts/index.vue index 1b6e577..ce63430 100644 --- a/pages/posts/index.vue +++ b/pages/posts/index.vue @@ -42,7 +42,8 @@ const getData = async () => { if (cache) { return cache as postItem[] } - const res = await $fetch('/api/posts/getPostList') + const response = await $fetch('/api/posts/getPostList') + const res = response.data store.setCache('posts', res) return res } diff --git a/pages/user/index.vue b/pages/user/index.vue index 084e9ee..8c833a1 100644 --- a/pages/user/index.vue +++ b/pages/user/index.vue @@ -1,13 +1,90 @@ index + + + uploadPostTest + + + editPostTest + + + testLogin + + + testRegister + + + testRefreshToken + + - \ No newline at end of file + \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 090346c..a05c4b7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,9 +14,18 @@ importers: '@types/node': specifier: ^22.10.5 version: 22.10.5 + bcryptjs: + specifier: ^2.4.3 + version: 2.4.3 + better-sqlite3: + specifier: 11.3.0 + version: 11.3.0 dayjs: specifier: ^1.11.13 version: 1.11.13 + jsonwebtoken: + specifier: ^9.0.2 + version: 9.0.2 markdown-it: specifier: ^14.1.0 version: 14.1.0 @@ -25,7 +34,7 @@ importers: version: 3.3.2 nuxt: specifier: ^3.15.1 - version: 3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(db0@0.2.1)(ioredis@5.4.2)(magicast@0.3.5)(rollup@4.30.1)(sass@1.83.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(sass@1.83.1)(terser@5.37.0)(yaml@2.7.0))(yaml@2.7.0) + version: 3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(better-sqlite3@11.3.0)(db0@0.2.1(better-sqlite3@11.3.0))(ioredis@5.4.2)(magicast@0.3.5)(rollup@4.30.1)(sass@1.83.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(sass@1.83.1)(terser@5.37.0)(yaml@2.7.0))(yaml@2.7.0) pinia: specifier: ^2.3.0 version: 2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) @@ -45,6 +54,15 @@ importers: '@element-plus/nuxt': specifier: ^1.1.1 version: 1.1.1(@element-plus/icons-vue@2.3.1(vue@3.5.13(typescript@5.7.3)))(element-plus@2.9.3(vue@3.5.13(typescript@5.7.3)))(magicast@0.3.5)(rollup@4.30.1) + '@types/bcryptjs': + specifier: ^2.4.6 + version: 2.4.6 + '@types/better-sqlite3': + specifier: ^7.6.12 + version: 7.6.12 + '@types/jsonwebtoken': + specifier: ^9.0.7 + version: 9.0.7 '@types/markdown-it': specifier: ^14.1.2 version: 14.1.2 @@ -928,12 +946,21 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@types/bcryptjs@2.4.6': + resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} + + '@types/better-sqlite3@7.6.12': + resolution: {integrity: sha512-fnQmj8lELIj7BSrZQAdBMHEHX8OZLYIHXqAKT1O7tDfLxaINzf00PMjw22r3N/xXh0w/sGHlO6SVaCQ2mj78lg==} + '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} '@types/http-proxy@1.17.15': resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==} + '@types/jsonwebtoken@9.0.7': + resolution: {integrity: sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==} + '@types/linkify-it@5.0.0': resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} @@ -1171,6 +1198,12 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + bcryptjs@2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + + better-sqlite3@11.3.0: + resolution: {integrity: sha512-iHt9j8NPYF3oKCNOO5ZI4JwThjt3Z6J6XrcwG85VNMVzv1ByqrHWv5VILEbCMFWDsoHhXvQ7oC8vgRXFAKgl9w==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -1181,6 +1214,9 @@ packages: birpc@0.2.19: resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==} + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -1203,9 +1239,15 @@ packages: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -1246,6 +1288,9 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -1445,6 +1490,14 @@ packages: supports-color: optional: true + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -1526,6 +1579,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -1551,6 +1607,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + enhanced-resolve@5.18.0: resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==} engines: {node: '>=10.13.0'} @@ -1615,6 +1674,10 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + externality@1.0.2: resolution: {integrity: sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==} @@ -1671,6 +1734,9 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@11.2.0: resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} engines: {node: '>=14.14'} @@ -1723,6 +1789,9 @@ packages: git-url-parse@16.0.0: resolution: {integrity: sha512-Y8iAF0AmCaqXc6a5GYgPQW9ESbncNLOL+CeQAJRhmWUOmnPkKpBYeWYp4mFd3LA5j53CdGDdslzX12yEBVHQQg==} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1963,6 +2032,16 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + + jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -2012,12 +2091,33 @@ packages: lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} @@ -2090,6 +2190,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2101,6 +2205,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -2124,6 +2231,9 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -2160,6 +2270,9 @@ packages: nanotar@0.1.1: resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==} + napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + nitropack@2.10.4: resolution: {integrity: sha512-sJiG/MIQlZCVSw2cQrFG1H6mLeSqHlYfFerRjLKz69vUfdu0EL2l0WdOxlQbzJr3mMv/l4cOlCCLzVRzjzzF/g==} engines: {node: ^16.11.0 || >=17.0.0} @@ -2170,6 +2283,10 @@ packages: xml2js: optional: true + node-abi@3.71.0: + resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} + engines: {node: '>=10'} + node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -2554,6 +2671,11 @@ packages: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + pretty-bytes@6.1.1: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} @@ -2572,6 +2694,9 @@ packages: protocols@2.0.1: resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -2595,9 +2720,17 @@ packages: rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readable-stream@4.7.0: resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2733,6 +2866,12 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + simple-git@3.27.0: resolution: {integrity: sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==} @@ -2808,6 +2947,10 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-literal@2.1.1: resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} @@ -2849,6 +2992,13 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + tar-fs@2.1.2: + resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} @@ -2893,6 +3043,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -4215,12 +4368,22 @@ snapshots: '@trysound/sax@0.2.0': {} + '@types/bcryptjs@2.4.6': {} + + '@types/better-sqlite3@7.6.12': + dependencies: + '@types/node': 22.10.5 + '@types/estree@1.0.6': {} '@types/http-proxy@1.17.15': dependencies: '@types/node': 22.10.5 + '@types/jsonwebtoken@9.0.7': + dependencies: + '@types/node': 22.10.5 + '@types/linkify-it@5.0.0': {} '@types/lodash-es@4.17.12': @@ -4544,6 +4707,13 @@ snapshots: base64-js@1.5.1: {} + bcryptjs@2.4.3: {} + + better-sqlite3@11.3.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.2 + binary-extensions@2.3.0: {} bindings@1.5.0: @@ -4552,6 +4722,12 @@ snapshots: birpc@0.2.19: {} + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + boolbase@1.0.0: {} brace-expansion@1.1.11: @@ -4576,8 +4752,15 @@ snapshots: buffer-crc32@1.0.0: {} + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -4638,6 +4821,8 @@ snapshots: dependencies: readdirp: 4.1.1 + chownr@1.1.4: {} + chownr@2.0.0: {} chownr@3.0.0: {} @@ -4805,7 +4990,9 @@ snapshots: dayjs@1.11.13: {} - db0@0.2.1: {} + db0@0.2.1(better-sqlite3@11.3.0): + optionalDependencies: + better-sqlite3: 11.3.0 debug@2.6.9: dependencies: @@ -4817,6 +5004,12 @@ snapshots: optionalDependencies: supports-color: 9.4.0 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + deepmerge@4.3.1: {} default-browser-id@5.0.0: {} @@ -4876,6 +5069,10 @@ snapshots: eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + ee-first@1.1.1: {} electron-to-chromium@1.5.80: {} @@ -4909,6 +5106,10 @@ snapshots: encodeurl@2.0.0: {} + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + enhanced-resolve@5.18.0: dependencies: graceful-fs: 4.2.11 @@ -5018,6 +5219,8 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + expand-template@2.0.3: {} + externality@1.0.2: dependencies: enhanced-resolve: 5.18.0 @@ -5073,6 +5276,8 @@ snapshots: fresh@0.5.2: {} + fs-constants@1.0.0: {} + fs-extra@11.2.0: dependencies: graceful-fs: 4.2.11 @@ -5122,6 +5327,8 @@ snapshots: dependencies: git-up: 8.0.0 + github-from-package@0.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -5355,6 +5562,30 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.6.3 + + jwa@1.4.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@3.2.2: + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + kleur@3.0.3: {} klona@2.0.6: {} @@ -5414,10 +5645,24 @@ snapshots: lodash.defaults@4.2.0: {} + lodash.includes@4.3.0: {} + lodash.isarguments@3.1.0: {} + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.memoize@4.1.2: {} + lodash.once@4.1.1: {} + lodash.uniq@4.5.0: {} lodash@4.17.21: {} @@ -5480,6 +5725,8 @@ snapshots: mimic-fn@4.0.0: {} + mimic-response@3.1.0: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -5492,6 +5739,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -5512,6 +5761,8 @@ snapshots: mitt@3.0.1: {} + mkdirp-classic@0.5.3: {} + mkdirp@1.0.4: {} mkdirp@3.0.1: {} @@ -5535,7 +5786,9 @@ snapshots: nanotar@0.1.1: {} - nitropack@2.10.4(typescript@5.7.3): + napi-build-utils@1.0.2: {} + + nitropack@2.10.4(better-sqlite3@11.3.0)(typescript@5.7.3): dependencies: '@cloudflare/kv-asset-handler': 0.3.4 '@netlify/functions': 2.8.2 @@ -5559,7 +5812,7 @@ snapshots: cookie-es: 1.2.2 croner: 9.0.0 crossws: 0.3.1 - db0: 0.2.1 + db0: 0.2.1(better-sqlite3@11.3.0) defu: 6.1.4 destr: 2.0.3 dot-prop: 9.0.0 @@ -5602,7 +5855,7 @@ snapshots: unctx: 2.4.1 unenv: 1.10.0 unimport: 3.14.5(rollup@4.30.1) - unstorage: 1.14.4(db0@0.2.1)(ioredis@5.4.2) + unstorage: 1.14.4(db0@0.2.1(better-sqlite3@11.3.0))(ioredis@5.4.2) untyped: 1.5.2 unwasm: 0.3.9 transitivePeerDependencies: @@ -5632,6 +5885,10 @@ snapshots: - typescript - uploadthing + node-abi@3.71.0: + dependencies: + semver: 7.6.3 + node-addon-api@7.1.1: {} node-domexception@1.0.0: {} @@ -5678,7 +5935,7 @@ snapshots: nuxi@3.20.0: {} - nuxt@3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(db0@0.2.1)(ioredis@5.4.2)(magicast@0.3.5)(rollup@4.30.1)(sass@1.83.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(sass@1.83.1)(terser@5.37.0)(yaml@2.7.0))(yaml@2.7.0): + nuxt@3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(better-sqlite3@11.3.0)(db0@0.2.1(better-sqlite3@11.3.0))(ioredis@5.4.2)(magicast@0.3.5)(rollup@4.30.1)(sass@1.83.1)(terser@5.37.0)(typescript@5.7.3)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(sass@1.83.1)(terser@5.37.0)(yaml@2.7.0))(yaml@2.7.0): dependencies: '@nuxt/devalue': 2.0.2 '@nuxt/devtools': 1.7.0(rollup@4.30.1)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(sass@1.83.1)(terser@5.37.0)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) @@ -5715,7 +5972,7 @@ snapshots: magic-string: 0.30.17 mlly: 1.7.4 nanotar: 0.1.1 - nitropack: 2.10.4(typescript@5.7.3) + nitropack: 2.10.4(better-sqlite3@11.3.0)(typescript@5.7.3) nuxi: 3.20.0 nypm: 0.4.1 ofetch: 1.4.1 @@ -5738,7 +5995,7 @@ snapshots: unimport: 3.14.5(rollup@4.30.1) unplugin: 2.1.2 unplugin-vue-router: 0.10.9(rollup@4.30.1)(vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) - unstorage: 1.14.4(db0@0.2.1)(ioredis@5.4.2) + unstorage: 1.14.4(db0@0.2.1(better-sqlite3@11.3.0))(ioredis@5.4.2) untyped: 1.5.2 vue: 3.5.13(typescript@5.7.3) vue-bundle-renderer: 2.1.1 @@ -6102,6 +6359,21 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prebuild-install@7.1.2: + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.71.0 + pump: 3.0.2 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.2 + tunnel-agent: 0.6.0 + pretty-bytes@6.1.1: {} process-nextick-args@2.0.1: {} @@ -6115,6 +6387,11 @@ snapshots: protocols@2.0.1: {} + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + punycode.js@2.3.1: {} queue-microtask@1.2.3: {} @@ -6134,6 +6411,13 @@ snapshots: defu: 6.1.4 destr: 2.0.3 + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -6144,6 +6428,12 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readable-stream@4.7.0: dependencies: abort-controller: 3.0.0 @@ -6295,6 +6585,14 @@ snapshots: signal-exit@4.1.0: {} + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + simple-git@3.27.0: dependencies: '@kwsites/file-exists': 1.1.1 @@ -6372,6 +6670,8 @@ snapshots: strip-final-newline@3.0.0: {} + strip-json-comments@2.0.1: {} + strip-literal@2.1.1: dependencies: js-tokens: 9.0.1 @@ -6410,6 +6710,21 @@ snapshots: tapable@2.2.1: {} + tar-fs@2.1.2: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.2 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + tar-stream@3.1.7: dependencies: b4a: 1.6.7 @@ -6464,6 +6779,10 @@ snapshots: tr46@0.0.3: {} + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + type-fest@0.21.3: {} type-fest@4.32.0: {} @@ -6597,7 +6916,7 @@ snapshots: acorn: 8.14.0 webpack-virtual-modules: 0.6.2 - unstorage@1.14.4(db0@0.2.1)(ioredis@5.4.2): + unstorage@1.14.4(db0@0.2.1(better-sqlite3@11.3.0))(ioredis@5.4.2): dependencies: anymatch: 3.1.3 chokidar: 3.6.0 @@ -6608,7 +6927,7 @@ snapshots: ofetch: 1.4.1 ufo: 1.5.4 optionalDependencies: - db0: 0.2.1 + db0: 0.2.1(better-sqlite3@11.3.0) ioredis: 5.4.2 untun@0.1.3: diff --git a/server/api/auth/login.ts b/server/api/auth/login.ts deleted file mode 100644 index d2b6824..0000000 --- a/server/api/auth/login.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default defineEventHandler(async (event) => { - const body = await readBody(event) - return -}) \ No newline at end of file diff --git a/server/api/posts/editPost.ts b/server/api/posts/editPost.ts new file mode 100644 index 0000000..0d7f0bc --- /dev/null +++ b/server/api/posts/editPost.ts @@ -0,0 +1,84 @@ +// editPost.ts +import DB from 'better-sqlite3'; +import cacheResult from '~/server/utils/cacheRes'; +function prepareDB() { + const db = new DB('./userData/db/posts.db'); + + const updatePostStmt = db.prepare(` + UPDATE posts + SET title = ?, summary = ?, type = ?, url = ?, date = ?, tag_id = ? + WHERE id = ? + `); + + const updateContentStmt = db.prepare(` + UPDATE postContent + SET content = ? + WHERE id = ? + `); + + const updateTagsStmt = db.prepare(` + UPDATE tags + SET tag1 = ?, tag2 = ?, tag3 = ?, tag4 = ?, tag5 = ?, + tag6 = ?, tag7 = ?, tag8 = ?, tag9 = ?, tag10 = ?, + tag11 = ?, tag12 = ?, tag13 = ?, tag14 = ?, tag15 = ? + WHERE id = ? + `); + + const insertTagsStmt = db.prepare(` + INSERT INTO tags (tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10, tag11, tag12, tag13, tag14, tag15) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `); + return { updatePostStmt, updateContentStmt, updateTagsStmt, insertTagsStmt, db }; +} + +export default defineEventHandler(async (event) => { + const { updatePostStmt, updateContentStmt, updateTagsStmt, insertTagsStmt, db } = cacheResult(prepareDB)(); + + const body = await readBody(event); + const { id, title, summary, tags: _tags, type, url, date, content } = body; + + if ([id, title, summary, _tags, type, url, date, content].some(item => item === undefined)) { + return { + code: 400, + msg: '参数错误', + body + } + } + + const tagsArray = Array.isArray(_tags) ? _tags : [_tags]; + const tags = tagsArray.slice(0, 15).concat(new Array(15 - tagsArray.length).fill(null)); + + try { + db.transaction(() => { + // 检查是否存在tag_id,如果不存在则插入新标签 + const tagRow: any = db.prepare(`SELECT tag_id FROM posts WHERE id = ?`).get(id); + if (tagRow.tag_id) { + // 更新现有标签 + updateTagsStmt.run(...tags, tagRow.tag_id); + } else { + // 插入新标签并获取tag_id + const tagResult = insertTagsStmt.run(...tags); + const tagId = tagResult.lastInsertRowid; + // 更新posts表中的tag_id + updatePostStmt.run(title, summary, type, url, date, tagId, id); + } + + // 更新posts表 + updatePostStmt.run(title, summary, type, url, date, tagRow.tag_id, id); + + // 更新postContent表 + updateContentStmt.run(content, id); + })(); + + return { + code: 200, + msg: '更新成功' + }; + } catch (error) { + console.error('更新数据时出错:', error); + return { + code: 500, + msg: '服务器内部错误' + }; + } +}); \ No newline at end of file diff --git a/server/api/posts/getPostContent.ts b/server/api/posts/getPostContent.ts index 0668d6f..3a3092f 100644 --- a/server/api/posts/getPostContent.ts +++ b/server/api/posts/getPostContent.ts @@ -1,8 +1,39 @@ // @ts-ignore import testData from "~/public/testData/test.md" +import DB from 'better-sqlite3'; export default defineEventHandler(async (event) => { const body = await readBody(event) - const data = testData - return { data, title: `测试标题::{${body.id}}` } + const id = body.id; + if (!id || isNaN(Number(id))) { + return { + code: 400, + msg: '无效的id' + }; + } + + const db = new DB('./userData/db/posts.db'); + const post: any = db.prepare('SELECT * FROM posts WHERE id = ?').get(Number(id)); + const content: any = db.prepare('SELECT content FROM postContent WHERE id = ?').get(Number(id)); + db.close(); + + if (!post) { + return { + code: 404, + msg: '文章不存在' + }; + } + + if (!content) { + return { + code: 404, + msg: '文章内容不存在' + }; + } + + return { + code: 200, + data: content.content, + title: post.title + }; }) \ No newline at end of file diff --git a/server/api/posts/getPostList.ts b/server/api/posts/getPostList.ts index e484058..b22c79d 100644 --- a/server/api/posts/getPostList.ts +++ b/server/api/posts/getPostList.ts @@ -1,22 +1,35 @@ -import type { postItem } from "~/types/post"; +import { defineEventHandler } from 'h3'; +import DB from 'better-sqlite3'; -function generateFakeData(length: number) { - const data: postItem[] = []; - for (let i = 0; i < length; i++) { - data.push({ - id: i, - title: `测试标题`, - summary: `测试摘要测试摘要测试摘要测试摘要测试摘要测试摘要测试摘要测试摘要测试摘要测试摘要测试摘要`, - type: 'markdown', - tags: ['test', 'test1'], - url: '', - date: parseInt(new Date().getTime().toFixed()), - }); - } - return data; -} +export default defineEventHandler(async (event) => { + const db = new DB('./userData/db/posts.db'); -export default defineEventHandler((event) => { - const data = generateFakeData(50) - return data -}) \ No newline at end of file + // 获取所有标签 + const tagsMap = new Map(); + const tagsRows = db.prepare('SELECT id, tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10, tag11, tag12, tag13, tag14, tag15 FROM tags').all(); + tagsRows.forEach((row: any) => { + const tags = []; + for (let i = 1; i <= 15; i++) { + const tag = row[`tag${i}`]; + if (tag) { + tags.push(tag); + } + } + tagsMap.set(row.id, tags); + }); + + // 获取所有文章 + const posts = db.prepare('SELECT id, title, summary, type, tag_id, url, date FROM posts').all(); + + // 替换tag_id为标签数组 + posts.forEach((post: any) => { + post.tags = tagsMap.get(post.tag_id) || []; + }); + + db.close(); + + return { + code: 200, + data: posts + }; +}); \ No newline at end of file diff --git a/server/api/posts/uploadPost.ts b/server/api/posts/uploadPost.ts new file mode 100644 index 0000000..05077f5 --- /dev/null +++ b/server/api/posts/uploadPost.ts @@ -0,0 +1,69 @@ +import DB from 'better-sqlite3'; +import cacheResult from '~/server/utils/cacheRes'; + +function prepareDB() { + const db = new DB('./userData/db/posts.db'); + + const insertPostStmt = db.prepare(` + INSERT INTO posts (title, summary, type, url, date, tag_id) + VALUES (?, ?, ?, ?, ?, ?) + `); + + const insertContentStmt = db.prepare(` + INSERT INTO postContent (id, content) + VALUES (?, ?) + `); + + const insertTagsStmt = db.prepare(` + INSERT INTO tags (tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10, tag11, tag12, tag13, tag14, tag15) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `); + + return { db, insertPostStmt, insertContentStmt, insertTagsStmt }; +} + +export default defineEventHandler(async (event) => { + const { db, insertPostStmt, insertContentStmt, insertTagsStmt } = cacheResult(prepareDB)(); + + const body = await readBody(event); + const { title, summary, tags: _tags, type, url, date, content } = body; + + if([title, summary, _tags, type, url, date, content].some(item => item === undefined)){ + return { + code: 400, + msg: '参数错误', + body + } + } + + // 确保_tags是一个数组 + const tagsArray = Array.isArray(_tags) ? _tags : [_tags]; + // 填充或截取前15个标签 + const tags = tagsArray.slice(0, 15).concat(new Array(15 - tagsArray.length).fill(null)); + + try { + db.transaction(() => { + // 插入tags表 + const tagResult = insertTagsStmt.run(...tags); + const tagId = tagResult.lastInsertRowid; + + // 插入posts表 + const postResult = insertPostStmt.run(title, summary, type, url, date, tagId); + const postId = postResult.lastInsertRowid; + + // 插入postContent表 + insertContentStmt.run(postId, content); + })(); + + return { + code: 200, + msg: '插入成功' + }; + } catch (error) { + console.error('插入数据时出错:', error); + return { + code: 500, + msg: '服务器内部错误' + }; + } +}); \ No newline at end of file diff --git a/server/api/test/testDir.ts b/server/api/test/testDir.ts index 2addf65..3741304 100644 --- a/server/api/test/testDir.ts +++ b/server/api/test/testDir.ts @@ -1,5 +1,5 @@ import fs from 'fs'; -import checkUserData from '~/server/utils/checkUserData'; +import checkUserData from '~/server/utils/initUserData'; export default defineEventHandler((event) => { checkUserData() diff --git a/server/api/user/login.ts b/server/api/user/login.ts new file mode 100644 index 0000000..3c26926 --- /dev/null +++ b/server/api/user/login.ts @@ -0,0 +1,27 @@ +// import { defineEventHandler, readBody, createError } from 'h3'; +import bcrypt from 'bcryptjs'; +import BetterSqlite3 from 'better-sqlite3'; + + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + const { username, password } = body; + + // 查询用户 + const userDB = BetterSqlite3('./userData/db/user.db'); + const user: any = userDB.prepare('SELECT * FROM user WHERE username = ?').get(username); + if (!user || password !== user.password) { + userDB.close(); + throw createError({ statusCode: 401, statusMessage: 'Invalid username or password' }); + } + + // 更新最后登录时间 + userDB.prepare('UPDATE user SET lastLoginTime = ? WHERE id = ?').run(Date.now(), user.id); + + // 生成 JWT + const token = createToken(user.id); + + userDB.close(); + + return { token , expiresIn: Date.now() + 168 * 60 * 60 * 1000 }; +}); \ No newline at end of file diff --git a/server/api/user/refreshToken.ts b/server/api/user/refreshToken.ts new file mode 100644 index 0000000..0f3f183 --- /dev/null +++ b/server/api/user/refreshToken.ts @@ -0,0 +1,20 @@ +import { defineEventHandler, readBody, createError } from 'h3'; +import jwt from 'jsonwebtoken'; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + const { token } = body; + + const jwtSecret = getKey(); + + try { + // 验证旧的 Token + const decoded = jwt.verify(token, jwtSecret) as { userId: number }; + // 生成新的 Token + const newToken = jwt.sign({ userId: decoded.userId }, jwtSecret, { expiresIn: '168h' }); + + return { token: newToken, expiresIn: Date.now() + 168 * 60 * 60 * 1000 }; + } catch (err) { + throw createError({ statusCode: 401, statusMessage: 'Token invalid or expired', data: { err, token } }); + } +}); \ No newline at end of file diff --git a/server/api/user/register.ts b/server/api/user/register.ts new file mode 100644 index 0000000..8cee05e --- /dev/null +++ b/server/api/user/register.ts @@ -0,0 +1,34 @@ +import bcrypt from 'bcryptjs'; +import BetterSqlite3 from 'better-sqlite3'; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + const { username, password } = body; + + // 检查用户名是否已存在 + const userDB = BetterSqlite3('./userData/db/user.db'); + const existingUser = userDB.prepare('SELECT * FROM user WHERE username = ?').get(username); + if (existingUser) { + userDB.close(); + throw createError({ statusCode: 400, statusMessage: 'Username already exists' }); + } + + // 哈希密码 + // const salt = getKey().substring(0, 10); + // const hashedPassword = bcrypt.hashSync(password, salt); + const hashedPassword = password + + // 插入新用户 + const createTime = Date.now(); + const lastLoginTime = createTime; + const stmt = userDB.prepare('INSERT INTO user (username, password, createTime, lastLoginTime) VALUES (?, ?, ?, ?)'); + const result = stmt.run(username, hashedPassword, createTime, lastLoginTime); + + // 生成 JWT + const userId = result.lastInsertRowid as number; + const token = createToken(userId); + + userDB.close(); + + return { token, expiresIn: Date.now() + 168 * 60 * 60 * 1000 }; +}); \ No newline at end of file diff --git a/server/api/user/updatePassword.ts b/server/api/user/updatePassword.ts new file mode 100644 index 0000000..58adc2f --- /dev/null +++ b/server/api/user/updatePassword.ts @@ -0,0 +1,31 @@ +// import { defineEventHandler, readBody, createError } from 'h3'; +import bcrypt from 'bcryptjs'; +import BetterSqlite3 from 'better-sqlite3'; + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + const { oldPassword, newPassword } = body; + const userId = event.context.user.id; + + // 查询用户 + const userDB = new BetterSqlite3('./userData/db/user.db'); + const user: any = userDB.prepare('SELECT * FROM user WHERE id = ?').get(userId); + if (!user || !bcrypt.compareSync(oldPassword, user.password)) { + userDB.close(); + throw createError({ statusCode: 401, statusMessage: 'Invalid old password' }); + } + + // 哈希新密码 + const salt = bcrypt.genSaltSync(10); + const hashedPassword = bcrypt.hashSync(newPassword, salt); + + // 更新密码 + userDB.prepare('UPDATE user SET password = ? WHERE id = ?').run(hashedPassword, userId); + + // 生成新的 JWT + const token = createToken(userId); + + userDB.close(); + + return { token , expiresIn: Date.now() + 168 * 60 * 60 * 1000 }; +}); \ No newline at end of file diff --git a/server/middleware/auth.ts b/server/middleware/auth.ts index d08006a..b4d31e1 100644 --- a/server/middleware/auth.ts +++ b/server/middleware/auth.ts @@ -1,12 +1,25 @@ import serverConfig from "../server.config" +// import { verify } from 'jsonwebtoken' +import jwt from 'jsonwebtoken' +import getKey from "../utils/getKey" const pathNeedAuth = serverConfig.auth.api export default defineEventHandler((event) => { - // console.log('New request: ' + getRequestURL(event)) + const key = getKey() const path = getRequestURL(event).pathname - if(pathNeedAuth.has(path)){ - // console.log('Auth needed') - return true + if (pathNeedAuth.has(path)) { + const authHeader = event.node.req.headers.authorization + if (!authHeader || !authHeader.startsWith('Bearer ')) { + throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) + } + const token = authHeader.split('Bearer ')[1].trim() + try { + const decoded = jwt.verify(token, key) + // 将用户ID挂载到事件对象,供后续使用 + // event.context.userId = decoded.userId + } catch (err) { + throw createError({ statusCode: 401, statusMessage: 'Token invalid or expired' }) + } } }) \ No newline at end of file diff --git a/server/middleware/checkUserData.ts b/server/middleware/checkUserData.ts index 8ab2106..69601e9 100644 --- a/server/middleware/checkUserData.ts +++ b/server/middleware/checkUserData.ts @@ -1,4 +1,4 @@ export default defineEventHandler((event) => { - checkUserData() + initUserData() // console.log('New request: ' + getRequestURL(event)) }) \ No newline at end of file diff --git a/server/utils/cacheRes.ts b/server/utils/cacheRes.ts new file mode 100644 index 0000000..e802694 --- /dev/null +++ b/server/utils/cacheRes.ts @@ -0,0 +1,9 @@ +export default function cacheResult(func: () => T): () => T { + let result: any; + return () => { + if (result === undefined) { + result = func(); + } + return result; + }; +} \ No newline at end of file diff --git a/server/utils/checkUserData.ts b/server/utils/checkUserData.ts deleted file mode 100644 index b537779..0000000 --- a/server/utils/checkUserData.ts +++ /dev/null @@ -1,22 +0,0 @@ -import mkfileIfNotExist from "./mkfileIfNotExist" - -let checked = false - -/** - * 检查并完善userData的目录结构,若不存在密钥则生成随机的密钥 - * @returns {void} - */ -const checkUserData = () => { - if (checked) return - checked = true - // console.log('check userData') - const dirList = [ - './userData/', - './userData/db/', - './userData/md/', - ] - dirList.forEach(mkdirIfNotExist) - mkfileIfNotExist('./userData/key.txt', new Array(2048).fill(0).map(() => Math.floor(Math.random() * 16).toString(16)).join('')) -} - -export default checkUserData \ No newline at end of file diff --git a/server/utils/createToken.ts b/server/utils/createToken.ts new file mode 100644 index 0000000..6367e5f --- /dev/null +++ b/server/utils/createToken.ts @@ -0,0 +1,8 @@ +import jwt from "jsonwebtoken" +import getKey from "./getKey" + + +export default function createToken(userId: number): string { + const key = getKey() + return jwt.sign({ userId }, key, { expiresIn: '168h' }) +} \ No newline at end of file diff --git a/server/utils/getKey.ts b/server/utils/getKey.ts new file mode 100644 index 0000000..5bdbfec --- /dev/null +++ b/server/utils/getKey.ts @@ -0,0 +1,7 @@ +import { sign } from 'jsonwebtoken' +import fs from 'fs' +import path from 'path' + +const getKey = cacheRes(() => fs.readFileSync(path.join(process.cwd(), 'userData/key.txt'), 'utf-8') as string) + +export default getKey \ No newline at end of file diff --git a/server/utils/initUserData.ts b/server/utils/initUserData.ts new file mode 100644 index 0000000..0b59e65 --- /dev/null +++ b/server/utils/initUserData.ts @@ -0,0 +1,85 @@ +import mkfileIfNotExist from "./mkfileIfNotExist" +import db from 'better-sqlite3' + +let checked = false + +/** + * 检查并完善userData的目录结构,若不存在密钥则生成随机的密钥,初始化数据库 + * @returns {void} + */ +function checkUserData() { + if (checked) return + checked = true + // console.log('check userData') + const dirList = [ + './userData/', + './userData/db/', + ] + dirList.forEach(mkdirIfNotExist) + + mkfileIfNotExist('./userData/key.txt', new Array(2048).fill(0).map(() => Math.floor(Math.random() * 16).toString(16)).join('')) + + createDB() + +} + +function createDB() { + const userDB = new db('./userData/db/user.db'); + const postsDB = new db('./userData/db/posts.db'); + + userDB.exec(` + CREATE TABLE IF NOT EXISTS user ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL UNIQUE, + password TEXT NOT NULL, + createTime INTEGER NOT NULL, + lastLoginTime INTEGER NOT NULL + ); + `); + + postsDB.exec(` + CREATE TABLE IF NOT EXISTS posts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + date INTEGER NOT NULL, + summary TEXT NOT NULL, + type TEXT NOT NULL, + url TEXT NOT NULL, + tag_id INTEGER NOT NULL, + FOREIGN KEY(tag_id) REFERENCES tags(id) + ); + `); + + postsDB.exec(` + CREATE TABLE IF NOT EXISTS postContent ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + content TEXT NOT NULL + ); + `); + + postsDB.exec(` + CREATE TABLE IF NOT EXISTS tags ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + tag1 TEXT, + tag2 TEXT, + tag3 TEXT, + tag4 TEXT, + tag5 TEXT, + tag6 TEXT, + tag7 TEXT, + tag8 TEXT, + tag9 TEXT, + tag10 TEXT, + tag11 TEXT, + tag12 TEXT, + tag13 TEXT, + tag14 TEXT, + tag15 TEXT + ); + `); + + postsDB.close(); + userDB.close(); +} + +export default checkUserData \ No newline at end of file