Replace mysql2 with prisma
also I updated packages, and properly typed api input a lot of time was spent, I don't remeber what really I did x3 but everything was related to replacing mysql2 with prisma
This commit is contained in:
parent
be1e3909b6
commit
eebf25198d
39 changed files with 1081 additions and 1292 deletions
|
@ -14,10 +14,6 @@ Project uses Oracle MySQL as a database store. It uses environment variables for
|
||||||
|
|
||||||
| Environment variable | Description |
|
| Environment variable | Description |
|
||||||
|----------------------|-------------------|
|
|----------------------|-------------------|
|
||||||
| `DB_HOST` | Database host |
|
| `DB_URL` | Database url, see [this](https://www.prisma.io/docs/concepts/database-connectors/mysql#connection-url) |
|
||||||
| `DB_PORT` | Database port |
|
|
||||||
| `DB_USER` | Database user |
|
|
||||||
| `DB_PASSWORD` | Database password |
|
|
||||||
| `DB_SCHEMA` | Database schema |
|
|
||||||
|
|
||||||
After setting variables, you can run the project using `npx nuxi dev` or `npx nuxi preview`.
|
After setting variables, you can run the project using `npx nuxi dev` or `npx nuxi preview`.
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type order as orderType } from '~/utils/types/database';
|
import type { useFetch } from '#imports';
|
||||||
|
|
||||||
|
type Order = Awaited<ReturnType<typeof useFetch<void, any, "/api/orders/:id", "get">>>["data"]["value"];
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
order?: orderType
|
order?: Order | undefined
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -24,7 +26,7 @@ const props = defineProps<{
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="i in props.order.work" :key="i.id">
|
<tr v-for="i in props.order.work" :key="i.id">
|
||||||
<td>{{ i.is_fulfilled }}</td>
|
<td>{{ i.fulfilled }}</td>
|
||||||
<td>
|
<td>
|
||||||
{{ i.offer.name }}
|
{{ i.offer.name }}
|
||||||
</td>
|
</td>
|
||||||
|
|
576
package-lock.json
generated
576
package-lock.json
generated
|
@ -6,6 +6,7 @@
|
||||||
"": {
|
"": {
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@prisma/client": "5.5.2",
|
||||||
"mysql2": "^3.2.3"
|
"mysql2": "^3.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -14,7 +15,8 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
||||||
"@typescript-eslint/parser": "^6.9.1",
|
"@typescript-eslint/parser": "^6.9.1",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.39.0",
|
||||||
"nuxt": "3.8.0",
|
"nuxt": "3.8.1",
|
||||||
|
"prisma": "5.5.2",
|
||||||
"sass": "^1.62.0",
|
"sass": "^1.62.0",
|
||||||
"vite-plugin-vuetify": "^1.0.2",
|
"vite-plugin-vuetify": "^1.0.2",
|
||||||
"vuetify": "^3.1.15"
|
"vuetify": "^3.1.15"
|
||||||
|
@ -1822,19 +1824,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nuxt/kit": {
|
"node_modules/@nuxt/kit": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.8.1.tgz",
|
||||||
"integrity": "sha512-oIthQxeMIVs4ESVP5FqLYn8tj0S1sLd+eYreh+dNYgnJ2pTi7+THR12ONBNHjk668jqEe7ErUJ8UlGwqBzgezg==",
|
"integrity": "sha512-DrhG1Z85iH68QOTkgfb0HVfM2g7+CfcMWrFWMDwck9ofyM2RXQUZyfmvMedwBnui1AjjpgpLO9078yZM+RqNUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/schema": "3.8.0",
|
"@nuxt/schema": "3.8.1",
|
||||||
"c12": "^1.5.1",
|
"c12": "^1.5.1",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"defu": "^6.1.2",
|
"defu": "^6.1.3",
|
||||||
"globby": "^13.2.2",
|
"globby": "^13.2.2",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"ignore": "^5.2.4",
|
"ignore": "^5.2.4",
|
||||||
"jiti": "^1.20.0",
|
"jiti": "^1.21.0",
|
||||||
"knitwork": "^1.0.0",
|
"knitwork": "^1.0.0",
|
||||||
"mlly": "^1.4.2",
|
"mlly": "^1.4.2",
|
||||||
"pathe": "^1.1.1",
|
"pathe": "^1.1.1",
|
||||||
|
@ -1882,18 +1884,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nuxt/schema": {
|
"node_modules/@nuxt/schema": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.8.1.tgz",
|
||||||
"integrity": "sha512-VEDVeCjdVowhoY5vIBSz94+SSwmM204jN6TNe/ShBJ2d/vZiy9EtLbhOwqaPNFHwnN1fl/XFHThwJiexdB9D1w==",
|
"integrity": "sha512-fSaWRcI/2mUskfTZTGSnH6Ny0x05CRzylbVn6WFV0d6UEKIVy42Qd6n+h7yoFfp4cq4nji6u16PT4SqS1DEhsw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/ui-templates": "^1.3.1",
|
"@nuxt/ui-templates": "^1.3.1",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"defu": "^6.1.2",
|
"defu": "^6.1.3",
|
||||||
"hookable": "^5.5.3",
|
"hookable": "^5.5.3",
|
||||||
"pathe": "^1.1.1",
|
"pathe": "^1.1.1",
|
||||||
"pkg-types": "^1.0.3",
|
"pkg-types": "^1.0.3",
|
||||||
"postcss-import-resolver": "^2.0.0",
|
|
||||||
"std-env": "^3.4.3",
|
"std-env": "^3.4.3",
|
||||||
"ufo": "^1.3.1",
|
"ufo": "^1.3.1",
|
||||||
"unimport": "^3.4.0",
|
"unimport": "^3.4.0",
|
||||||
|
@ -1938,20 +1939,20 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@nuxt/vite-builder": {
|
"node_modules/@nuxt/vite-builder": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-3.8.1.tgz",
|
||||||
"integrity": "sha512-F9BfH+c/Idp6sBGVHR4QJSuoO42evtE4D0OelD45NgkqVvmBmOawlj0Oz5fDKoV64LDPI2+yE+xnBdQtsNv/VA==",
|
"integrity": "sha512-Ot/twGONxj22T9U4bxp771ibKVFlZxIiYDHY/e6mZsE4Blc0efKo6MzPPPo0W4/tXQbtKKEq41uINN3dMI3mag==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/kit": "3.8.0",
|
"@nuxt/kit": "3.8.1",
|
||||||
"@rollup/plugin-replace": "^5.0.4",
|
"@rollup/plugin-replace": "^5.0.5",
|
||||||
"@vitejs/plugin-vue": "^4.4.0",
|
"@vitejs/plugin-vue": "^4.4.0",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"clear": "^0.1.0",
|
"clear": "^0.1.0",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"cssnano": "^6.0.1",
|
"cssnano": "^6.0.1",
|
||||||
"defu": "^6.1.2",
|
"defu": "^6.1.3",
|
||||||
"esbuild": "^0.19.5",
|
"esbuild": "^0.19.5",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
"estree-walker": "^3.0.3",
|
"estree-walker": "^3.0.3",
|
||||||
|
@ -1967,8 +1968,6 @@
|
||||||
"perfect-debounce": "^1.0.0",
|
"perfect-debounce": "^1.0.0",
|
||||||
"pkg-types": "^1.0.3",
|
"pkg-types": "^1.0.3",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"postcss-import": "^15.1.0",
|
|
||||||
"postcss-url": "^10.1.3",
|
|
||||||
"rollup-plugin-visualizer": "^5.9.2",
|
"rollup-plugin-visualizer": "^5.9.2",
|
||||||
"std-env": "^3.4.3",
|
"std-env": "^3.4.3",
|
||||||
"strip-literal": "^1.3.0",
|
"strip-literal": "^1.3.0",
|
||||||
|
@ -2363,6 +2362,38 @@
|
||||||
"integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==",
|
"integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@prisma/client": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.5.2.tgz",
|
||||||
|
"integrity": "sha512-54XkqR8M+fxbzYqe+bIXimYnkkcGqgOh0dn0yWtIk6CQT4IUCAvNFNcQZwk2KqaLU+/1PHTSWrcHtx4XjluR5w==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/engines-version": "5.5.1-1.aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.13"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prisma": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"prisma": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/engines": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.5.2.tgz",
|
||||||
|
"integrity": "sha512-Be5hoNF8k+lkB3uEMiCHbhbfF6aj1GnrTBnn5iYFT7GEr3TsOEp1soviEcBR0tYCgHbxjcIxJMhdbvxALJhAqg==",
|
||||||
|
"devOptional": true,
|
||||||
|
"hasInstallScript": true
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/engines-version": {
|
||||||
|
"version": "5.5.1-1.aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.5.1-1.aebc046ce8b88ebbcb45efe31cbe7d06fd6abc0a.tgz",
|
||||||
|
"integrity": "sha512-O+qHFnZvAyOFk1tUco2/VdiqS0ym42a3+6CYLScllmnpbyiTplgyLt2rK/B9BTjYkSHjrgMhkG47S0oqzdIckA=="
|
||||||
|
},
|
||||||
"node_modules/@rollup/plugin-alias": {
|
"node_modules/@rollup/plugin-alias": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.0.1.tgz",
|
||||||
|
@ -2694,24 +2725,24 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
"integrity": "sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==",
|
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/http-proxy": {
|
"node_modules/@types/http-proxy": {
|
||||||
"version": "1.17.13",
|
"version": "1.17.14",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz",
|
||||||
"integrity": "sha512-GkhdWcMNiR5QSQRYnJ+/oXzu0+7JJEPC8vkWXK351BkhjraZF+1W13CUYARUvX9+NqIU2n6YHA4iwywsc/M6Sw==",
|
"integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.14",
|
"version": "7.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||||
"integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/json5": {
|
"node_modules/@types/json5": {
|
||||||
|
@ -2721,18 +2752,18 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.8.10",
|
"version": "20.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
|
||||||
"integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==",
|
"integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/normalize-package-data": {
|
"node_modules/@types/normalize-package-data": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
|
||||||
"integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==",
|
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
|
@ -2742,22 +2773,22 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/semver": {
|
"node_modules/@types/semver": {
|
||||||
"version": "7.5.4",
|
"version": "7.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz",
|
||||||
"integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==",
|
"integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz",
|
||||||
"integrity": "sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==",
|
"integrity": "sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.5.1",
|
"@eslint-community/regexpp": "^4.5.1",
|
||||||
"@typescript-eslint/scope-manager": "6.9.1",
|
"@typescript-eslint/scope-manager": "6.10.0",
|
||||||
"@typescript-eslint/type-utils": "6.9.1",
|
"@typescript-eslint/type-utils": "6.10.0",
|
||||||
"@typescript-eslint/utils": "6.9.1",
|
"@typescript-eslint/utils": "6.10.0",
|
||||||
"@typescript-eslint/visitor-keys": "6.9.1",
|
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.2.4",
|
"ignore": "^5.2.4",
|
||||||
|
@ -2783,15 +2814,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz",
|
||||||
"integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==",
|
"integrity": "sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "6.9.1",
|
"@typescript-eslint/scope-manager": "6.10.0",
|
||||||
"@typescript-eslint/types": "6.9.1",
|
"@typescript-eslint/types": "6.10.0",
|
||||||
"@typescript-eslint/typescript-estree": "6.9.1",
|
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||||
"@typescript-eslint/visitor-keys": "6.9.1",
|
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2811,13 +2842,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz",
|
||||||
"integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==",
|
"integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "6.9.1",
|
"@typescript-eslint/types": "6.10.0",
|
||||||
"@typescript-eslint/visitor-keys": "6.9.1"
|
"@typescript-eslint/visitor-keys": "6.10.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
@ -2828,13 +2859,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz",
|
||||||
"integrity": "sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==",
|
"integrity": "sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "6.9.1",
|
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||||
"@typescript-eslint/utils": "6.9.1",
|
"@typescript-eslint/utils": "6.10.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^1.0.1"
|
"ts-api-utils": "^1.0.1"
|
||||||
},
|
},
|
||||||
|
@ -2855,9 +2886,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz",
|
||||||
"integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==",
|
"integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
@ -2868,13 +2899,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz",
|
||||||
"integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==",
|
"integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "6.9.1",
|
"@typescript-eslint/types": "6.10.0",
|
||||||
"@typescript-eslint/visitor-keys": "6.9.1",
|
"@typescript-eslint/visitor-keys": "6.10.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.1.0",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
|
@ -2895,17 +2926,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.10.0.tgz",
|
||||||
"integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==",
|
"integrity": "sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@types/json-schema": "^7.0.12",
|
"@types/json-schema": "^7.0.12",
|
||||||
"@types/semver": "^7.5.0",
|
"@types/semver": "^7.5.0",
|
||||||
"@typescript-eslint/scope-manager": "6.9.1",
|
"@typescript-eslint/scope-manager": "6.10.0",
|
||||||
"@typescript-eslint/types": "6.9.1",
|
"@typescript-eslint/types": "6.10.0",
|
||||||
"@typescript-eslint/typescript-estree": "6.9.1",
|
"@typescript-eslint/typescript-estree": "6.10.0",
|
||||||
"semver": "^7.5.4"
|
"semver": "^7.5.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2920,12 +2951,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "6.9.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz",
|
||||||
"integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==",
|
"integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "6.9.1",
|
"@typescript-eslint/types": "6.10.0",
|
||||||
"eslint-visitor-keys": "^3.4.1"
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3167,13 +3198,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-core": {
|
"node_modules/@vue/compiler-core": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.8.tgz",
|
||||||
"integrity": "sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==",
|
"integrity": "sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.23.0",
|
||||||
"@vue/shared": "3.3.7",
|
"@vue/shared": "3.3.8",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
|
@ -3185,27 +3216,27 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-dom": {
|
"node_modules/@vue/compiler-dom": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.8.tgz",
|
||||||
"integrity": "sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==",
|
"integrity": "sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-core": "3.3.7",
|
"@vue/compiler-core": "3.3.8",
|
||||||
"@vue/shared": "3.3.7"
|
"@vue/shared": "3.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc": {
|
"node_modules/@vue/compiler-sfc": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.8.tgz",
|
||||||
"integrity": "sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==",
|
"integrity": "sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.23.0",
|
||||||
"@vue/compiler-core": "3.3.7",
|
"@vue/compiler-core": "3.3.8",
|
||||||
"@vue/compiler-dom": "3.3.7",
|
"@vue/compiler-dom": "3.3.8",
|
||||||
"@vue/compiler-ssr": "3.3.7",
|
"@vue/compiler-ssr": "3.3.8",
|
||||||
"@vue/reactivity-transform": "3.3.7",
|
"@vue/reactivity-transform": "3.3.8",
|
||||||
"@vue/shared": "3.3.7",
|
"@vue/shared": "3.3.8",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.5",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
|
@ -3219,13 +3250,13 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-ssr": {
|
"node_modules/@vue/compiler-ssr": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.8.tgz",
|
||||||
"integrity": "sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==",
|
"integrity": "sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.3.7",
|
"@vue/compiler-dom": "3.3.8",
|
||||||
"@vue/shared": "3.3.7"
|
"@vue/shared": "3.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/devtools-api": {
|
"node_modules/@vue/devtools-api": {
|
||||||
|
@ -3235,23 +3266,23 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity": {
|
"node_modules/@vue/reactivity": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.8.tgz",
|
||||||
"integrity": "sha512-cZNVjWiw00708WqT0zRpyAgduG79dScKEPYJXq2xj/aMtk3SKvL3FBt2QKUlh6EHBJ1m8RhBY+ikBUzwc7/khg==",
|
"integrity": "sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/shared": "3.3.7"
|
"@vue/shared": "3.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity-transform": {
|
"node_modules/@vue/reactivity-transform": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.8.tgz",
|
||||||
"integrity": "sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==",
|
"integrity": "sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.23.0",
|
||||||
"@vue/compiler-core": "3.3.7",
|
"@vue/compiler-core": "3.3.8",
|
||||||
"@vue/shared": "3.3.7",
|
"@vue/shared": "3.3.8",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"magic-string": "^0.30.5"
|
"magic-string": "^0.30.5"
|
||||||
}
|
}
|
||||||
|
@ -3263,43 +3294,43 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core": {
|
"node_modules/@vue/runtime-core": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.8.tgz",
|
||||||
"integrity": "sha512-LHq9du3ubLZFdK/BP0Ysy3zhHqRfBn80Uc+T5Hz3maFJBGhci1MafccnL3rpd5/3wVfRHAe6c+PnlO2PAavPTQ==",
|
"integrity": "sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/reactivity": "3.3.7",
|
"@vue/reactivity": "3.3.8",
|
||||||
"@vue/shared": "3.3.7"
|
"@vue/shared": "3.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-dom": {
|
"node_modules/@vue/runtime-dom": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.8.tgz",
|
||||||
"integrity": "sha512-PFQU1oeJxikdDmrfoNQay5nD4tcPNYixUBruZzVX/l0eyZvFKElZUjW4KctCcs52nnpMGO6UDK+jF5oV4GT5Lw==",
|
"integrity": "sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/runtime-core": "3.3.7",
|
"@vue/runtime-core": "3.3.8",
|
||||||
"@vue/shared": "3.3.7",
|
"@vue/shared": "3.3.8",
|
||||||
"csstype": "^3.1.2"
|
"csstype": "^3.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/server-renderer": {
|
"node_modules/@vue/server-renderer": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.8.tgz",
|
||||||
"integrity": "sha512-UlpKDInd1hIZiNuVVVvLgxpfnSouxKQOSE2bOfQpBuGwxRV/JqqTCyyjXUWiwtVMyeRaZhOYYqntxElk8FhBhw==",
|
"integrity": "sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-ssr": "3.3.7",
|
"@vue/compiler-ssr": "3.3.8",
|
||||||
"@vue/shared": "3.3.7"
|
"@vue/shared": "3.3.8"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "3.3.7"
|
"vue": "3.3.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/shared": {
|
"node_modules/@vue/shared": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
||||||
"integrity": "sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==",
|
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@vuetify/loader-shared": {
|
"node_modules/@vuetify/loader-shared": {
|
||||||
|
@ -4688,12 +4719,6 @@
|
||||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/cuint": {
|
|
||||||
"version": "0.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
|
|
||||||
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
@ -5006,9 +5031,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.576",
|
"version": "1.4.578",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.578.tgz",
|
||||||
"integrity": "sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA==",
|
"integrity": "sha512-V0ZhSu1BQZKfG0yNEL6Dadzik8E1vAzfpVOapdSiT9F6yapEJ3Bk+4tZ4SMPdWiUchCgnM/ByYtBzp5ntzDMIA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
|
@ -5076,18 +5101,6 @@
|
||||||
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
|
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/errno": {
|
|
||||||
"version": "0.1.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
|
||||||
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"prr": "~1.0.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"errno": "cli.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/error-ex": {
|
"node_modules/error-ex": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||||
|
@ -5869,9 +5882,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||||
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
|
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodelib/fs.stat": "^2.0.2",
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
|
@ -7739,55 +7752,6 @@
|
||||||
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
|
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/memory-fs": {
|
|
||||||
"version": "0.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
|
|
||||||
"integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"errno": "^0.1.3",
|
|
||||||
"readable-stream": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.3.0 <5.0.0 || >=5.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/memory-fs/node_modules/isarray": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/memory-fs/node_modules/readable-stream": {
|
|
||||||
"version": "2.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
|
||||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"core-util-is": "~1.0.0",
|
|
||||||
"inherits": "~2.0.3",
|
|
||||||
"isarray": "~1.0.0",
|
|
||||||
"process-nextick-args": "~2.0.0",
|
|
||||||
"safe-buffer": "~5.1.1",
|
|
||||||
"string_decoder": "~1.1.1",
|
|
||||||
"util-deprecate": "~1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/memory-fs/node_modules/safe-buffer": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/memory-fs/node_modules/string_decoder": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"safe-buffer": "~5.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/merge-stream": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
|
@ -8685,28 +8649,28 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nuxt": {
|
"node_modules/nuxt": {
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/nuxt/-/nuxt-3.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/nuxt/-/nuxt-3.8.1.tgz",
|
||||||
"integrity": "sha512-ZnisJYx5AcUl7xlw18m6zfINBpNhld+ZF+jdTLRZxkLjKSFZeFMGqKxOR1jNVSmxfIXM/guK0uV9GPm6HK/z7g==",
|
"integrity": "sha512-RSGO56Gv0x2f6AXWw4o4GoBaVdsD0qkPCjrX7Ud/jzH3cRJoyYMPuq/9AOLvf2o1ecZWl39j5elqJ4QHmggyOA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/devalue": "^2.0.2",
|
"@nuxt/devalue": "^2.0.2",
|
||||||
"@nuxt/devtools": "^1.0.0",
|
"@nuxt/devtools": "^1.0.0",
|
||||||
"@nuxt/kit": "3.8.0",
|
"@nuxt/kit": "3.8.1",
|
||||||
"@nuxt/schema": "3.8.0",
|
"@nuxt/schema": "3.8.1",
|
||||||
"@nuxt/telemetry": "^2.5.2",
|
"@nuxt/telemetry": "^2.5.2",
|
||||||
"@nuxt/ui-templates": "^1.3.1",
|
"@nuxt/ui-templates": "^1.3.1",
|
||||||
"@nuxt/vite-builder": "3.8.0",
|
"@nuxt/vite-builder": "3.8.1",
|
||||||
"@unhead/dom": "^1.7.4",
|
"@unhead/dom": "^1.8.3",
|
||||||
"@unhead/ssr": "^1.7.4",
|
"@unhead/ssr": "^1.8.3",
|
||||||
"@unhead/vue": "^1.7.4",
|
"@unhead/vue": "^1.8.3",
|
||||||
"@vue/shared": "^3.3.4",
|
"@vue/shared": "^3.3.8",
|
||||||
"acorn": "8.10.0",
|
"acorn": "8.11.2",
|
||||||
"c12": "^1.5.1",
|
"c12": "^1.5.1",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"cookie-es": "^1.0.0",
|
"cookie-es": "^1.0.0",
|
||||||
"defu": "^6.1.2",
|
"defu": "^6.1.3",
|
||||||
"destr": "^2.0.1",
|
"destr": "^2.0.2",
|
||||||
"devalue": "^4.3.2",
|
"devalue": "^4.3.2",
|
||||||
"esbuild": "^0.19.5",
|
"esbuild": "^0.19.5",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
|
@ -8715,12 +8679,12 @@
|
||||||
"globby": "^13.2.2",
|
"globby": "^13.2.2",
|
||||||
"h3": "^1.8.2",
|
"h3": "^1.8.2",
|
||||||
"hookable": "^5.5.3",
|
"hookable": "^5.5.3",
|
||||||
"jiti": "^1.20.0",
|
"jiti": "^1.21.0",
|
||||||
"klona": "^2.0.6",
|
"klona": "^2.0.6",
|
||||||
"knitwork": "^1.0.0",
|
"knitwork": "^1.0.0",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.5",
|
||||||
"mlly": "^1.4.2",
|
"mlly": "^1.4.2",
|
||||||
"nitropack": "^2.7.0",
|
"nitropack": "^2.7.2",
|
||||||
"nuxi": "^3.9.1",
|
"nuxi": "^3.9.1",
|
||||||
"nypm": "^0.3.3",
|
"nypm": "^0.3.3",
|
||||||
"ofetch": "^1.3.3",
|
"ofetch": "^1.3.3",
|
||||||
|
@ -8741,7 +8705,7 @@
|
||||||
"unplugin": "^1.5.0",
|
"unplugin": "^1.5.0",
|
||||||
"unplugin-vue-router": "^0.7.0",
|
"unplugin-vue-router": "^0.7.0",
|
||||||
"untyped": "^1.4.0",
|
"untyped": "^1.4.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.8",
|
||||||
"vue-bundle-renderer": "^2.0.0",
|
"vue-bundle-renderer": "^2.0.0",
|
||||||
"vue-devtools-stub": "^0.1.0",
|
"vue-devtools-stub": "^0.1.0",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
|
@ -8766,18 +8730,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nuxt/node_modules/acorn": {
|
|
||||||
"version": "8.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
|
||||||
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
|
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
|
||||||
"acorn": "bin/acorn"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/nuxt/node_modules/escape-string-regexp": {
|
"node_modules/nuxt/node_modules/escape-string-regexp": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
||||||
|
@ -9382,15 +9334,6 @@
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pify": {
|
|
||||||
"version": "2.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
|
||||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pkg-dir": {
|
"node_modules/pkg-dir": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
|
||||||
|
@ -9601,55 +9544,6 @@
|
||||||
"postcss": "^8.2.15"
|
"postcss": "^8.2.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-import": {
|
|
||||||
"version": "15.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
|
||||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"postcss-value-parser": "^4.0.0",
|
|
||||||
"read-cache": "^1.0.0",
|
|
||||||
"resolve": "^1.1.7"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"postcss": "^8.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss-import-resolver": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postcss-import-resolver/-/postcss-import-resolver-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-y001XYgGvVwgxyxw9J1a5kqM/vtmIQGzx34g0A0Oy44MFcy/ZboZw1hu/iN3VYFjSTRzbvd7zZJJz0Kh0AGkTw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"enhanced-resolve": "^4.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss-import-resolver/node_modules/enhanced-resolve": {
|
|
||||||
"version": "4.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
|
|
||||||
"integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"graceful-fs": "^4.1.2",
|
|
||||||
"memory-fs": "^0.5.0",
|
|
||||||
"tapable": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss-import-resolver/node_modules/tapable": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss-merge-longhand": {
|
"node_modules/postcss-merge-longhand": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz",
|
||||||
|
@ -9972,48 +9866,6 @@
|
||||||
"postcss": "^8.2.15"
|
"postcss": "^8.2.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-url": {
|
|
||||||
"version": "10.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz",
|
|
||||||
"integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"make-dir": "~3.1.0",
|
|
||||||
"mime": "~2.5.2",
|
|
||||||
"minimatch": "~3.0.4",
|
|
||||||
"xxhashjs": "~0.2.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"postcss": "^8.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss-url/node_modules/mime": {
|
|
||||||
"version": "2.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
|
|
||||||
"integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
|
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
|
||||||
"mime": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss-url/node_modules/minimatch": {
|
|
||||||
"version": "3.0.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz",
|
|
||||||
"integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"brace-expansion": "^1.1.7"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss-value-parser": {
|
"node_modules/postcss-value-parser": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
|
@ -10021,9 +9873,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/postcss/node_modules/nanoid": {
|
"node_modules/postcss/node_modules/nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -10059,6 +9911,22 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prisma": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.5.2.tgz",
|
||||||
|
"integrity": "sha512-WQtG6fevOL053yoPl6dbHV+IWgKo25IRN4/pwAGqcWmg7CrtoCzvbDbN9fXUc7QS2KK0LimHIqLsaCOX/vHl8w==",
|
||||||
|
"devOptional": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/engines": "5.5.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"prisma": "build/index.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proc-log": {
|
"node_modules/proc-log": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
|
||||||
|
@ -10112,12 +9980,6 @@
|
||||||
"integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==",
|
"integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/prr": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
@ -10188,15 +10050,6 @@
|
||||||
"flat": "^5.0.2"
|
"flat": "^5.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/read-cache": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"pify": "^2.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/read-package-json": {
|
"node_modules/read-package-json": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz",
|
||||||
|
@ -12975,16 +12828,16 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/vue": {
|
"node_modules/vue": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.8.tgz",
|
||||||
"integrity": "sha512-YEMDia1ZTv1TeBbnu6VybatmSteGOS3A3YgfINOfraCbf85wdKHzscD6HSS/vB4GAtI7sa1XPX7HcQaJ1l24zA==",
|
"integrity": "sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.3.7",
|
"@vue/compiler-dom": "3.3.8",
|
||||||
"@vue/compiler-sfc": "3.3.7",
|
"@vue/compiler-sfc": "3.3.8",
|
||||||
"@vue/runtime-dom": "3.3.7",
|
"@vue/runtime-dom": "3.3.8",
|
||||||
"@vue/server-renderer": "3.3.7",
|
"@vue/server-renderer": "3.3.8",
|
||||||
"@vue/shared": "3.3.7"
|
"@vue/shared": "3.3.8"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
|
@ -13244,15 +13097,6 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/xxhashjs": {
|
|
||||||
"version": "0.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
|
|
||||||
"integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"cuint": "^0.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|
|
@ -16,12 +16,14 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
||||||
"@typescript-eslint/parser": "^6.9.1",
|
"@typescript-eslint/parser": "^6.9.1",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.39.0",
|
||||||
"nuxt": "3.8.0",
|
"nuxt": "3.8.1",
|
||||||
|
"prisma": "5.5.2",
|
||||||
"sass": "^1.62.0",
|
"sass": "^1.62.0",
|
||||||
"vite-plugin-vuetify": "^1.0.2",
|
"vite-plugin-vuetify": "^1.0.2",
|
||||||
"vuetify": "^3.1.15"
|
"vuetify": "^3.1.15"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@prisma/client": "5.5.2",
|
||||||
"mysql2": "^3.2.3"
|
"mysql2": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,24 +6,28 @@ import { ref, type Ref } from "vue";
|
||||||
import { VBtn, VForm } from "vuetify/components";
|
import { VBtn, VForm } from "vuetify/components";
|
||||||
import PagedList from "~/components/pagedList.vue";
|
import PagedList from "~/components/pagedList.vue";
|
||||||
import Snowflake from "~/utils/snowflake";
|
import Snowflake from "~/utils/snowflake";
|
||||||
import { client as clientType, order, orderSummary } from "~/utils/types/database";
|
|
||||||
import OrderView from "~/components/orderView.vue";
|
import OrderView from "~/components/orderView.vue";
|
||||||
import EntryEditor, { type fieldDefinition } from "~/components/entryEditor.vue";
|
import EntryEditor, { type fieldDefinition } from "~/components/entryEditor.vue";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const id = route.params.id;
|
const id = route.params.id;
|
||||||
|
|
||||||
const clientRequest = await useFetch(`/api/clients/${id}`);
|
const clientRequest = await useFetch(`/api/clients/${id}` as "/api/clients/:id");
|
||||||
if (clientRequest.error.value) throw createError(clientRequest.error.value?.data ?? "");
|
if (clientRequest.error.value) throw createError(clientRequest.error.value?.data ?? "");
|
||||||
const client = clientRequest.data as Ref<clientType>;
|
type Client = NonNullable<typeof clientRequest.data.value>;
|
||||||
|
const client = clientRequest.data as Ref<Client>;
|
||||||
|
|
||||||
const clientOrdersRequest = await useFetch(`/api/clients/${id}/orders`);
|
const clientOrdersRequest = await useFetch(`/api/clients/${id}/orders` as "/api/clients/:id/orders");
|
||||||
if (clientOrdersRequest.error.value) throw createError(clientOrdersRequest.error.value?.data ?? "");
|
if (clientOrdersRequest.error.value) throw createError(clientOrdersRequest.error.value?.data ?? "");
|
||||||
const clientOrders = clientOrdersRequest.data as Ref<Array<orderSummary>>;
|
type OrderSummary = NonNullable<typeof clientOrdersRequest.data.value>;
|
||||||
|
const clientOrders = clientOrdersRequest.data as Ref<OrderSummary>;
|
||||||
|
|
||||||
|
type Order = Awaited<ReturnType<typeof useFetch<void, any, "/api/orders/:id", "get">>>["data"]["value"];
|
||||||
|
|
||||||
|
// cache
|
||||||
const orders = ref<Map<string, {
|
const orders = ref<Map<string, {
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
value?: order
|
value?: Order
|
||||||
}>>(new Map());
|
}>>(new Map());
|
||||||
|
|
||||||
for (const i of clientOrders.value)
|
for (const i of clientOrders.value)
|
||||||
|
@ -36,7 +40,7 @@ async function loadOrder(id: string) {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
entry.value = await $fetch(`/api/orders/${id}` as "/api/order/:id", {
|
entry.value = await $fetch(`/api/orders/${id}` as "/api/order/:id", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
});
|
}) as Order;
|
||||||
entry.loading = false;
|
entry.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,24 +188,24 @@ function getCreationDate() {
|
||||||
>
|
>
|
||||||
<template #title="i">
|
<template #title="i">
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol>{{ new Date(Number(new Snowflake(BigInt(((i.record) as orderSummary).id)).timestamp)).toLocaleDateString() }}</VCol>
|
<VCol>{{ new Date(Number(new Snowflake(BigInt((i.record.id))).timestamp)).toLocaleDateString() }}</VCol>
|
||||||
<VCol>{{ ((i.record) as orderSummary).value }} PLN</VCol>
|
<VCol>{{ i.record.value }} PLN</VCol>
|
||||||
<VCol>
|
<VCol>
|
||||||
{{ ((i.record) as orderSummary).imported_products_count }}
|
{{ i.record.imported_products_count }}
|
||||||
products,
|
products,
|
||||||
{{ ((i.record) as orderSummary).work_count }}
|
{{ i.record.work_count }}
|
||||||
works
|
works
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</template>
|
</template>
|
||||||
<template #text="i">
|
<template #text="i">
|
||||||
<VProgressLinear
|
<VProgressLinear
|
||||||
:height="orders.get((i.record as orderSummary).id)?.loading ?? true ? undefined : 0"
|
:height="orders.get(i.record.id)?.loading ?? true ? undefined : 0"
|
||||||
absolute
|
absolute
|
||||||
:progress="orders.get((i.record as orderSummary).id)?.loading ?? true"
|
:progress="orders.get(i.record.id)?.loading ?? true"
|
||||||
:indeterminate="orders.get((i.record as orderSummary).id)?.loading ?? true"
|
:indeterminate="orders.get(i.record.id)?.loading ?? true"
|
||||||
/>
|
/>
|
||||||
<OrderView :order="(orders.get((i.record as orderSummary).id)?.value as order | undefined)" />
|
<OrderView :order="orders.get(i.record.id)?.value" />
|
||||||
</template>
|
</template>
|
||||||
</PagedList>
|
</PagedList>
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { type NuxtError } from "nuxt/app";
|
||||||
import { ref, type Ref, reactive } from "vue";
|
import { ref, type Ref, reactive } from "vue";
|
||||||
import { VBtn } from "vuetify/components";
|
import { VBtn } from "vuetify/components";
|
||||||
|
|
||||||
import { type client as clientType } from "~/utils/types/database";
|
|
||||||
import pagedTable from "~/components/pagedTable.vue";
|
import pagedTable from "~/components/pagedTable.vue";
|
||||||
import Alerts, { type AlertData } from "~/components/alerts.vue";
|
import Alerts, { type AlertData } from "~/components/alerts.vue";
|
||||||
import { type fieldDefinition } from "~/components/entryEditor.vue";
|
import { type fieldDefinition } from "~/components/entryEditor.vue";
|
||||||
|
@ -33,7 +32,7 @@ async function rowClicked(client: string, edit = false) {
|
||||||
|
|
||||||
async function rowDelete(client: string) {
|
async function rowDelete(client: string) {
|
||||||
try {
|
try {
|
||||||
await $fetch<clientType>(`/api/clients/${client}`, {
|
await $fetch(`/api/clients/${client}` as "api/clients/:id", {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
clients.value = clients.value.filter(e => e.id !== client);
|
clients.value = clients.value.filter(e => e.id !== client);
|
||||||
|
|
116
schema.prisma
Normal file
116
schema.prisma
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
datasource db {
|
||||||
|
provider = "mysql"
|
||||||
|
url = env("DB_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id BigInt @id @unique @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
username String @unique @db.VarChar(30)
|
||||||
|
email String @unique @db.VarChar(128)
|
||||||
|
password Bytes @db.Binary(64)
|
||||||
|
display_name String? @db.VarChar(30)
|
||||||
|
managedOrders Order[]
|
||||||
|
sessions Session[]
|
||||||
|
|
||||||
|
@@map("users")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
userId BigInt @map("user") @db.UnsignedBigInt
|
||||||
|
expiry_date DateTime? @default(dbgenerated("(now() + interval 30 day)")) @db.Timestamp(0)
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
|
||||||
|
@@index([userId], map: "user_idx")
|
||||||
|
@@map("sessions")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Client {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
name String? @db.VarChar(128)
|
||||||
|
address String? @db.VarChar(128)
|
||||||
|
phone String? @db.VarChar(16)
|
||||||
|
email String? @db.VarChar(128)
|
||||||
|
orders Order[]
|
||||||
|
|
||||||
|
@@map("clients")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Order {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
clientId BigInt @db.UnsignedBigInt @map("client")
|
||||||
|
userId BigInt @db.UnsignedBigInt @map("user")
|
||||||
|
draft Boolean @default(true) @map("is_draft") @db.TinyInt
|
||||||
|
imported_products ImportedProduct[]
|
||||||
|
client Client @relation(fields: [clientId], references: [id])
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
work Work[]
|
||||||
|
|
||||||
|
@@index([clientId])
|
||||||
|
@@index([userId])
|
||||||
|
@@map("orders")
|
||||||
|
}
|
||||||
|
|
||||||
|
model ImportedProduct {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
orderId BigInt @db.UnsignedBigInt @map("order")
|
||||||
|
name String? @db.VarChar(128)
|
||||||
|
link String @db.VarChar(1024)
|
||||||
|
price_imported Decimal @default(0.00) @db.Decimal(10, 2)
|
||||||
|
price Decimal @default(0.00) @db.Decimal(10, 2)
|
||||||
|
order Order @relation(fields: [orderId], references: [id])
|
||||||
|
|
||||||
|
@@index([orderId])
|
||||||
|
@@map("imported_products")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Offer {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
name String @db.VarChar(45)
|
||||||
|
description String? @db.Text
|
||||||
|
recommended_price Decimal? @db.Decimal(10, 2)
|
||||||
|
work Work[]
|
||||||
|
|
||||||
|
@@map("offer")
|
||||||
|
}
|
||||||
|
|
||||||
|
model OrderTemplate {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
name String @db.VarChar(45)
|
||||||
|
description String? @db.Text
|
||||||
|
work_templates WorkTemplate[]
|
||||||
|
|
||||||
|
@@map("order_templates")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Work {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
orderId BigInt @map("order") @db.UnsignedBigInt
|
||||||
|
offerId BigInt @map("offer") @db.UnsignedBigInt
|
||||||
|
price Decimal @db.Decimal(10, 2)
|
||||||
|
notes String? @db.Text
|
||||||
|
fulfilled Boolean @default(false) @map("is_fulfilled") @db.TinyInt
|
||||||
|
order Order @relation(fields: [orderId], references: [id])
|
||||||
|
offer Offer @relation(fields: [offerId], references: [id])
|
||||||
|
|
||||||
|
@@index([offerId], map: "offer_idx")
|
||||||
|
@@index([orderId], map: "order_idx")
|
||||||
|
@@map("work")
|
||||||
|
}
|
||||||
|
|
||||||
|
model WorkTemplate {
|
||||||
|
id BigInt @id @default(dbgenerated("(((unix_timestamp() * 1000) * pow(2,22)) + floor((rand() * pow(2,12))))")) @db.UnsignedBigInt
|
||||||
|
orderTemplateId BigInt @map("order_template") @db.UnsignedBigInt
|
||||||
|
offerId BigInt @map("offer") @db.UnsignedBigInt
|
||||||
|
price Decimal @default(0.00) @db.Decimal(10, 2)
|
||||||
|
notes String? @db.Text
|
||||||
|
orderTemplate OrderTemplate @relation(fields: [orderTemplateId], references: [id])
|
||||||
|
|
||||||
|
@@index([offerId])
|
||||||
|
@@index([orderTemplateId])
|
||||||
|
@@map("work_templates")
|
||||||
|
}
|
Binary file not shown.
167
schemaModel.sql
167
schemaModel.sql
|
@ -1,167 +0,0 @@
|
||||||
-- Server version 8.0.32
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `users`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `users` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`username` varchar(30) NOT NULL,
|
|
||||||
`email` varchar(128) NOT NULL,
|
|
||||||
`password` binary(64) NOT NULL,
|
|
||||||
`display_name` varchar(30) DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `idusers_UNIQUE` (`id`),
|
|
||||||
UNIQUE KEY `username_UNIQUE` (`username`),
|
|
||||||
UNIQUE KEY `email_UNIQUE` (`email`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `clients`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `clients` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`name` varchar(128) DEFAULT NULL,
|
|
||||||
`address` varchar(128) DEFAULT NULL,
|
|
||||||
`phone` varchar(16) DEFAULT NULL,
|
|
||||||
`email` varchar(128) DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `orders`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `orders` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`client` bigint unsigned NOT NULL,
|
|
||||||
`user` bigint unsigned NOT NULL,
|
|
||||||
`is_draft` tinyint NOT NULL DEFAULT '1',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `user_idx` (`user`),
|
|
||||||
KEY `client_idx` (`client`),
|
|
||||||
CONSTRAINT `client` FOREIGN KEY (`client`) REFERENCES `clients` (`id`),
|
|
||||||
CONSTRAINT `user` FOREIGN KEY (`user`) REFERENCES `users` (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `imported_products`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `imported_products` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`order` bigint unsigned NOT NULL,
|
|
||||||
`name` varchar(128) DEFAULT NULL,
|
|
||||||
`link` varchar(1024) NOT NULL,
|
|
||||||
`price_imported` decimal(10,2) NOT NULL DEFAULT '0.00',
|
|
||||||
`price` decimal(10,2) NOT NULL DEFAULT '0.00',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `order_idx` (`order`),
|
|
||||||
CONSTRAINT `order2` FOREIGN KEY (`order`) REFERENCES `orders` (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `offer`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `offer` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`name` varchar(45) NOT NULL,
|
|
||||||
`description` text,
|
|
||||||
`recommended_price` decimal(10,2) DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `order_templates`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `order_templates` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`name` varchar(45) NOT NULL,
|
|
||||||
`description` text,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `sessions`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `sessions` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`user` bigint unsigned NOT NULL,
|
|
||||||
`expiry_date` timestamp NULL DEFAULT ((now() + interval 30 day)),
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `user_idx` (`user`),
|
|
||||||
CONSTRAINT `user_session` FOREIGN KEY (`user`) REFERENCES `users` (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `work`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `work` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`order` bigint unsigned NOT NULL,
|
|
||||||
`offer` bigint unsigned NOT NULL,
|
|
||||||
`price` decimal(10,2) NOT NULL,
|
|
||||||
`notes` text,
|
|
||||||
`is_fulfilled` tinyint NOT NULL DEFAULT '0',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `order_idx` (`order`),
|
|
||||||
KEY `offer_idx` (`offer`),
|
|
||||||
CONSTRAINT `offer` FOREIGN KEY (`offer`) REFERENCES `offer` (`id`),
|
|
||||||
CONSTRAINT `order` FOREIGN KEY (`order`) REFERENCES `orders` (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `work_templates`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE `work_templates` (
|
|
||||||
`id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))),
|
|
||||||
`order_template` bigint unsigned NOT NULL,
|
|
||||||
`offer` bigint unsigned NOT NULL,
|
|
||||||
`price` decimal(10,2) NOT NULL DEFAULT '0.00',
|
|
||||||
`notes` text,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `order_template_idx` (`order_template`),
|
|
||||||
KEY `offer_idx` (`offer`),
|
|
||||||
CONSTRAINT `offer2` FOREIGN KEY (`offer`) REFERENCES `offer` (`id`),
|
|
||||||
CONSTRAINT `order_template` FOREIGN KEY (`order_template`) REFERENCES `order_templates` (`id`)
|
|
||||||
);
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Final view structure for view `orderSummaries`
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE VIEW `orderSummaries` AS
|
|
||||||
SELECT
|
|
||||||
`id`,
|
|
||||||
`client`,
|
|
||||||
`user`,
|
|
||||||
`is_draft`,
|
|
||||||
(COALESCE(`imported_products`.`price`, 0) + COALESCE(`work`.`price`, 0)) AS `value`,
|
|
||||||
COALESCE(`imported_products`.`count`, 0) as `imported_products_count`,
|
|
||||||
COALESCE(`work`.`count`, 0) as `work_count`
|
|
||||||
FROM
|
|
||||||
`orders`
|
|
||||||
LEFT JOIN
|
|
||||||
(
|
|
||||||
SELECT
|
|
||||||
`order`,
|
|
||||||
SUM(`price`) as `price`,
|
|
||||||
COUNT(*) AS `count`
|
|
||||||
FROM `imported_products`
|
|
||||||
GROUP BY `order`
|
|
||||||
) as `imported_products` ON `orders`.`id` = `imported_products`.`order`
|
|
||||||
LEFT JOIN
|
|
||||||
(
|
|
||||||
SELECT
|
|
||||||
`order`,
|
|
||||||
SUM(`price`) AS `price`,
|
|
||||||
COUNT(*) AS `count`
|
|
||||||
FROM `work`
|
|
||||||
GROUP BY `work`.`order`
|
|
||||||
) AS `work` ON `work`.`order` = `orders`.`id`;
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { defineEventHandler, getQuery } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
import { createError } from "#imports";
|
|
||||||
|
|
||||||
import BaaPagination from "~/server/utils/baaPagination";
|
import getPaginatedParameters from "../utils/baaPageParsing";
|
||||||
import { type client } from "~/utils/types/database";
|
import { database } from "../utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
export const baaWrapper = new BaaPagination<client, "id">("clients", "id");
|
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
export default defineEventHandler((e) => {
|
||||||
return baaWrapper.RESTget(e);
|
const pageParameters = getPaginatedParameters(e, 50, 200);
|
||||||
|
return database.client.findPaginated(pageParameters, {}).then(prismaToWeb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import { defineEventHandler, readBody } from "h3";
|
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
||||||
|
import { type Client } from "@prisma/client";
|
||||||
|
|
||||||
import { baaWrapper } from "./clients.get";
|
import getRequestingUser from "../utils/getRequestingUser";
|
||||||
import { type client } from "~/utils/types/database";
|
import { database } from "../utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
import Snowflake from "~/utils/snowflake";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
|
@ -12,10 +15,10 @@ const clientKeys: Array<string> = [
|
||||||
"email",
|
"email",
|
||||||
];
|
];
|
||||||
|
|
||||||
export function checkIsClient(
|
export function checkIsClient<Patch extends boolean = boolean>(
|
||||||
value: any,
|
value: any,
|
||||||
required = false,
|
patch: Patch,
|
||||||
): value is Partial<Omit<client, "id">> {
|
): value is Patch extends true ? Partial<Omit<Client, "id">> : Omit<Client, "id"> {
|
||||||
const errors = new Map<string, string>();
|
const errors = new Map<string, string>();
|
||||||
|
|
||||||
if (typeof value !== "object") {
|
if (typeof value !== "object") {
|
||||||
|
@ -25,12 +28,12 @@ export function checkIsClient(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(typeof value.name === "string" || value.name === null || (!required && value.name === undefined))) errors.set("name", "is not string or null");
|
if (!(typeof value.name === "string" || value.name === null || (!patch && value.name === undefined))) errors.set("name", "is not string or null");
|
||||||
if (!(typeof value.address === "string" || value.address === null || (!required && value.address === undefined))) errors.set("address", "is not string or null");
|
if (!(typeof value.address === "string" || value.address === null || (!patch && value.address === undefined))) errors.set("address", "is not string or null");
|
||||||
if (!(typeof value.phone === "string" || value.phone === null || (!required && value.phone === undefined))) errors.set("phone", "is not string or null");
|
if (!(typeof value.phone === "string" || value.phone === null || (!patch && value.phone === undefined))) errors.set("phone", "is not string or null");
|
||||||
if (!(typeof value.email === "string" || value.email === null || (!required && value.email === undefined))) errors.set("email", "is not string or null");
|
if (!(typeof value.email === "string" || value.email === null || (!patch && value.email === undefined))) errors.set("email", "is not string or null");
|
||||||
|
|
||||||
for (const i in value as Partial<Omit<client, "id">>)
|
for (const i in value as Partial<Omit<Client, "id">>)
|
||||||
if (!clientKeys.includes(i)) errors.set(i, `excessive property`);
|
if (!clientKeys.includes(i)) errors.set(i, `excessive property`);
|
||||||
|
|
||||||
if (errors.size !== 0) {
|
if (errors.size !== 0) {
|
||||||
|
@ -50,6 +53,20 @@ export function checkIsClient(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
return baaWrapper.RESTpost(e, clientKeys as Array<keyof Omit<client, "id">>, (o): o is Omit<client, "id"> => checkIsClient(o, true));
|
const body = await readBody(e);
|
||||||
|
const id = new Snowflake().state;
|
||||||
|
const user = await getRequestingUser(e);
|
||||||
|
|
||||||
|
if (!checkIsClient(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||||
|
|
||||||
|
const rvalue = await database.client.create({
|
||||||
|
data: {
|
||||||
|
...body,
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
setResponseStatus(e, 201);
|
||||||
|
return prismaToWeb(rvalue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,22 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { baaWrapper } from "../clients.get";
|
import { database } from "~/server/utils/database";
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
import { createError } from "#imports";
|
||||||
return baaWrapper.RESTdeleteRecord(e);
|
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
const id = e.context.params?.id as string;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await database.client.delete({
|
||||||
|
where: {
|
||||||
|
id: BigInt(id),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// FIXME: should be 500 on errors other than "RecordNotFound"
|
||||||
|
throw createError({ statusCode: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { baaWrapper } from "../clients.get";
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
import { createError } from "#imports";
|
||||||
return baaWrapper.RESTgetRecord(e);
|
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
const key = e.context.params?.id as string;
|
||||||
|
const rvalue = await database.client.findUnique({
|
||||||
|
where: {
|
||||||
|
id: BigInt(key),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!rvalue) throw createError({ statusCode: 404 });
|
||||||
|
return prismaToWeb(rvalue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,23 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler, readBody } from "h3";
|
||||||
|
|
||||||
import { checkIsClient } from "../clients.post";
|
import { checkIsClient } from "../clients.post";
|
||||||
import { baaWrapper } from "../clients.get";
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
import { createError } from "#imports";
|
||||||
return baaWrapper.RESTpatchRecord(e, checkIsClient);
|
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
const body = await readBody(e);
|
||||||
|
const id = e.context.params?.id as string;
|
||||||
|
|
||||||
|
if (!checkIsClient(body, true)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||||
|
|
||||||
|
const rvalue = await database.client.update({
|
||||||
|
where: {
|
||||||
|
id: BigInt(id),
|
||||||
|
},
|
||||||
|
data: body,
|
||||||
|
});
|
||||||
|
|
||||||
|
return prismaToWeb(rvalue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { baaWrapper } from "~/server/api/orders.get";
|
import { getOrders } from "~/server/api/orders.get";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
import getPaginatedParameters from "~/server/utils/baaPageParsing";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler((e) => {
|
||||||
const baa = await baaWrapper.RESTget(e, 50, 200, "`client` = ?", [e.context.params?.id]);
|
const pageParameters = getPaginatedParameters(e, 50, 200);
|
||||||
console.log(baa);
|
const clientId = e.context.params?.id as string;
|
||||||
return baa;
|
return getOrders(
|
||||||
|
pageParameters,
|
||||||
|
{
|
||||||
|
clientId: BigInt(clientId),
|
||||||
|
},
|
||||||
|
).then(prismaToWeb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { baaWrapper } from "../clients.get";
|
import { database } from "~/server/utils/database";
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
return baaWrapper.RESTrecordCount(e);
|
return {
|
||||||
|
count: await database.client.count({}),
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
import { type data, database } from "../utils/database";
|
import { database } from "../utils/database";
|
||||||
|
|
||||||
export async function isFirstRun() {
|
export async function isFirstRun() {
|
||||||
const [tables] = await database.query({ sql: "SHOW TABLES", rowsAsArray: true }, []) as data<[string]>;
|
try {
|
||||||
if (tables.length === 0) return true;
|
const numberOfUsers = await database.user.count();
|
||||||
if (!tables.find(a => a[0] === "users")) return true;
|
return numberOfUsers === 0;
|
||||||
const [[users]] = await database.query("SELECT COUNT(*) as `count` FROM `users`") as data<{count: number}>;
|
} catch {
|
||||||
if (users.count === 0) return true;
|
// We could fall here if the database is not initialized
|
||||||
return false;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
export default defineEventHandler((e) => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import fs from "node:fs/promises";
|
import { execSync } from "node:child_process";
|
||||||
import { defineEventHandler, setResponseStatus, readBody } from "h3";
|
import { defineEventHandler, setResponseStatus, readBody } from "h3";
|
||||||
|
|
||||||
import { database as db } from "../utils/database";
|
import { database } from "../utils/database";
|
||||||
import { isFirstRun } from "./firstRun.get";
|
import { isFirstRun } from "./firstRun.get";
|
||||||
import { getPasswordHash } from "./login.post";
|
import { getPasswordHash } from "./login.post";
|
||||||
import Snowflake from "~/utils/snowflake";
|
import Snowflake from "~/utils/snowflake";
|
||||||
|
@ -11,7 +11,7 @@ import { createError } from "#imports";
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
if (!isFirstRun()) {
|
if (!isFirstRun()) {
|
||||||
setResponseStatus(e, 404);
|
setResponseStatus(e, 404);
|
||||||
return "";
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = await readBody(e);
|
const body = await readBody(e);
|
||||||
|
@ -23,12 +23,14 @@ export default defineEventHandler(async (e) => {
|
||||||
const email = body.email;
|
const email = body.email;
|
||||||
if (typeof email !== "string") throw createError({ message: "email is not string", statusCode: 400 });
|
if (typeof email !== "string") throw createError({ message: "email is not string", statusCode: 400 });
|
||||||
|
|
||||||
const sql = await fs.readFile("./schemaModel.sql", "utf-8");
|
execSync("npx prisma db push --force-reset");
|
||||||
|
database.user.create({
|
||||||
const database = await db.new({ multipleStatements: true });
|
data: {
|
||||||
await database.query(sql);
|
id: new Snowflake().state,
|
||||||
await database.execute(
|
username,
|
||||||
"INSERT INTO `users` (`id`, `username`, `password`, `email`) VALUES (?, ?, ?, ?)",
|
email,
|
||||||
[new Snowflake().toString(), username, getPasswordHash(password), email]);
|
password: getPasswordHash(password),
|
||||||
return "";
|
},
|
||||||
|
});
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { defineEventHandler, getCookie, setCookie, readBody } from "h3";
|
import { defineEventHandler, getCookie, setCookie, readBody } from "h3";
|
||||||
|
|
||||||
import { database, type data } from "../utils/database";
|
import { database } from "../utils/database";
|
||||||
import { isString } from "../utils/isString";
|
import { isString } from "../utils/isString";
|
||||||
import { cookieSettings } from "../utils/rootUtils";
|
import { cookieSettings } from "../utils/rootUtils";
|
||||||
import Snowflake from "~/utils/snowflake";
|
import Snowflake from "~/utils/snowflake";
|
||||||
|
@ -28,19 +28,26 @@ export default defineEventHandler(async (e) => {
|
||||||
|
|
||||||
const hashedPassword = getPasswordHash(password);
|
const hashedPassword = getPasswordHash(password);
|
||||||
|
|
||||||
const [account] = await database.query(
|
const account = await database.user.findUnique({
|
||||||
"SELECT CONVERT(`id`, CHAR(32)) AS `id` from `users` WHERE `username` = ? AND `password` = ? LIMIT 1",
|
where: {
|
||||||
[login, hashedPassword],
|
username: login,
|
||||||
)as unknown as data<{id: string}>;
|
password: hashedPassword,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (account.length === 0) throw createError({ statusCode: 400, message: "Invalid username or password." });
|
if (account === null) throw createError({ statusCode: 400, message: "Invalid username or password." });
|
||||||
|
|
||||||
const sessionId = new Snowflake().toString();
|
const sessionId = new Snowflake();
|
||||||
|
|
||||||
await database.query(
|
await database.session.create({
|
||||||
"INSERT INTO `sessions` (`id`, `user`) VALUES ( ? , ? )",
|
data: {
|
||||||
[sessionId, account[0].id],
|
id: sessionId.state,
|
||||||
);
|
userId: account.id,
|
||||||
setCookie(e, "token", sessionId, cookieSettings);
|
},
|
||||||
return { message: "Login successful", token: sessionId };
|
});
|
||||||
|
setCookie(e, "token", sessionId.toString(), cookieSettings);
|
||||||
|
return { message: "Login successful", token: sessionId.toString() };
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,9 +23,10 @@ export default defineEventHandler(async (e) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
database.query(
|
database.session.delete({
|
||||||
"DELETE FROM `sessions` WHERE `id` = ?",
|
where: {
|
||||||
[token],
|
id: BigInt(token),
|
||||||
);
|
},
|
||||||
|
});
|
||||||
return { message: "Logged out" };
|
return { message: "Logged out" };
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,37 +1,65 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
import { type Order, type Client, Prisma } from "@prisma/client";
|
||||||
|
|
||||||
import BaaPagination from "../utils/baaPagination";
|
import getPaginatedParameters, { type pageData } from "../utils/baaPageParsing";
|
||||||
import { type data, database } from "../utils/database";
|
import { database } from "../utils/database";
|
||||||
import { type client, type orderSummary } from "~/utils/types/database";
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
export const baaWrapper = new BaaPagination<orderSummary, "id">(
|
type orderSummary = Omit<Order, "clientId"> & {
|
||||||
"orderSummaries",
|
client: Client;
|
||||||
"id",
|
value: number;
|
||||||
"*, CONVERT(`client`, CHAR) AS `client`, CONVERT(`user`, CHAR) as `user`",
|
imported_products_count: number;
|
||||||
);
|
work_count: number;
|
||||||
|
};
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export async function getOrders(
|
||||||
const orders = await baaWrapper.RESTget(e, 50, 200);
|
pageParameters: pageData,
|
||||||
|
where?: Prisma.OrderWhereInput,
|
||||||
|
) {
|
||||||
|
const data = await database.order.findPaginated(
|
||||||
|
pageParameters,
|
||||||
|
{
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
client: true,
|
||||||
|
userId: true,
|
||||||
|
draft: true,
|
||||||
|
imported_products: {
|
||||||
|
select: {
|
||||||
|
price: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
work: {
|
||||||
|
select: {
|
||||||
|
price: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
where,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const uniqueClients: Array<string> = [];
|
const rvalue = new Array<orderSummary>();
|
||||||
for (const i of orders) {
|
|
||||||
if (!uniqueClients.includes(i.client))
|
for (const i of data) {
|
||||||
uniqueClients.push(database.escape(i.client));
|
const importedProductsPriceSum = i.imported_products.reduce((pv, cv) => pv + cv.price.toNumber(), 0);
|
||||||
|
const workPriceSum = i.work.reduce((pv, cv) => pv + cv.price.toNumber(), 0);
|
||||||
|
|
||||||
|
rvalue.push({
|
||||||
|
id: i.id,
|
||||||
|
client: i.client,
|
||||||
|
draft: i.draft,
|
||||||
|
imported_products_count: i.imported_products.length,
|
||||||
|
userId: i.userId,
|
||||||
|
value: importedProductsPriceSum + workPriceSum,
|
||||||
|
work_count: i.work.length,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const [clients] = await database.query(
|
|
||||||
["SELECT",
|
|
||||||
"*,",
|
|
||||||
"CONVERT(`id`, CHAR) AS `id`",
|
|
||||||
"FROM `clients`",
|
|
||||||
"WHERE `id` IN",
|
|
||||||
`(${uniqueClients.join(', ')})`,
|
|
||||||
].join(" "),
|
|
||||||
) as data<client>;
|
|
||||||
|
|
||||||
const rvalue: Array<Omit<typeof orders, "client"> | { client?: client }> = [];
|
|
||||||
|
|
||||||
for (const i of orders)
|
|
||||||
rvalue.push({ ...i, client: clients.find(e => i.client === e.id) });
|
|
||||||
return rvalue;
|
return rvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineEventHandler((e) => {
|
||||||
|
const pageParameters = getPaginatedParameters(e, 50, 200);
|
||||||
|
return getOrders(pageParameters, {}).then(prismaToWeb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,39 +1,44 @@
|
||||||
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
||||||
|
import * as Prisma from "@prisma/client";
|
||||||
|
|
||||||
import { createValidationError, handleRecursedValidationError } from "../utils/validation";
|
import { createValidationError, handleRecursedValidationError } from "../utils/validation";
|
||||||
import { database as db } from "../utils/database";
|
import { database } from "../utils/database";
|
||||||
import getRequestingUser from "../utils/getRequestingUser";
|
import getRequestingUser from "../utils/getRequestingUser";
|
||||||
import { getOrder } from "./orders/[id].get";
|
import { getOrder } from "./orders/[id].get";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
import Snowflake from "~/utils/snowflake";
|
import Snowflake from "~/utils/snowflake";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
type importedProduct = {
|
type importedProduct<inOrder extends boolean = boolean> = {
|
||||||
|
orderId: inOrder extends true ? never : string,
|
||||||
name: string | null,
|
name: string | null,
|
||||||
link: string,
|
link: string,
|
||||||
price_imported: number,
|
price_imported: number,
|
||||||
price: number,
|
price: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
type work = {
|
type work<inOrder extends boolean = boolean> = {
|
||||||
offer: string,
|
orderId: inOrder extends true ? never : string,
|
||||||
|
offerId: string,
|
||||||
price: number,
|
price: number,
|
||||||
notes: string | null,
|
notes: string | null,
|
||||||
is_fulfilled: boolean | 0 | 1,
|
fulfilled: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
type order = {
|
type order = {
|
||||||
client: string,
|
clientId: string,
|
||||||
// user: string,
|
// userId: string,
|
||||||
is_draft: boolean | 0 | 1,
|
draft: boolean,
|
||||||
imported_products: Array<importedProduct>,
|
imported_products: Array<importedProduct<true>>,
|
||||||
work: Array<work>,
|
work: Array<work<true>>,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function checkIsWork<Patch extends boolean = boolean>(
|
export function checkIsWork<Patch extends boolean = boolean, inOrder extends boolean = boolean>(
|
||||||
value: any,
|
value: any,
|
||||||
patch: Patch,
|
patch: Patch,
|
||||||
): value is Patch extends true ? Partial<work> : work {
|
needsOrderId: inOrder,
|
||||||
|
): value is Patch extends true ? Partial<work<inOrder>> : work<inOrder> {
|
||||||
const errors = new Map<string, string>();
|
const errors = new Map<string, string>();
|
||||||
|
|
||||||
if (typeof value !== "object") {
|
if (typeof value !== "object") {
|
||||||
|
@ -43,19 +48,24 @@ export function checkIsWork<Patch extends boolean = boolean>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(typeof value.offer === "string" || (patch && value.offer === undefined))) errors.set("offer", "is not string");
|
if (!(typeof value.orderId === "string" || (patch && value.orderId === undefined) || !needsOrderId)) errors.set("orderId", "is not string");
|
||||||
|
if (!(typeof value.offerId === "string" || (patch && value.offerId === undefined))) errors.set("offerId", "is not string");
|
||||||
if (!(typeof value.price === "number" || (patch && value.price === undefined))) errors.set("price", "is not price");
|
if (!(typeof value.price === "number" || (patch && value.price === undefined))) errors.set("price", "is not price");
|
||||||
if (!(typeof value.notes === "string" || value.notes === null || (patch && value.notes === undefined))) errors.set("notes", "is not string or null");
|
if (!(typeof value.notes === "string" || value.notes === null || (patch && value.notes === undefined))) errors.set("notes", "is not string or null");
|
||||||
if (!(typeof value.is_fulfilled === "boolean" || value.is_fulfilled === 0 || value.is_fulfilled === 1 || (patch && value.is_fulfilled === undefined))) errors.set("is_fulfilled", "is not boolean");
|
if (!(typeof value.is_fulfilled === "boolean" || (patch && value.is_fulfilled === undefined))) errors.set("is_fulfilled", "is not boolean");
|
||||||
|
|
||||||
|
// TODO: Excessive property checking
|
||||||
|
// Excessive properties should be checked and an error should be thrown if there is one
|
||||||
|
|
||||||
if (errors.size !== 0) throw createValidationError(errors);
|
if (errors.size !== 0) throw createValidationError(errors);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkIsImportedProduct<Patch extends boolean = boolean>(
|
export function checkIsImportedProduct<Patch extends boolean = boolean, inOrder extends boolean = boolean>(
|
||||||
value: any,
|
value: any,
|
||||||
patch: Patch,
|
patch: Patch,
|
||||||
): value is Patch extends true ? Partial<importedProduct> : importedProduct {
|
needsOrderId: inOrder,
|
||||||
|
): value is Patch extends true ? Partial<importedProduct<inOrder>> : importedProduct<inOrder> {
|
||||||
const errors = new Map<string, string>();
|
const errors = new Map<string, string>();
|
||||||
|
|
||||||
if (typeof value !== "object") {
|
if (typeof value !== "object") {
|
||||||
|
@ -65,10 +75,14 @@ export function checkIsImportedProduct<Patch extends boolean = boolean>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(typeof value.orderId === "string" || (patch && value.orderId === undefined) || !needsOrderId)) errors.set("orderId", "is not string");
|
||||||
if (!(typeof value.name === "string" || value.name === null || (patch && value.name === undefined))) errors.set("name", "is not string or null");
|
if (!(typeof value.name === "string" || value.name === null || (patch && value.name === undefined))) errors.set("name", "is not string or null");
|
||||||
if (!(typeof value.link === "string" || (patch && value.name === undefined))) errors.set("link", "is not string");
|
if (!(typeof value.link === "string" || (patch && value.name === undefined))) errors.set("link", "is not string");
|
||||||
if (!(typeof value.price_imported === "number" || (patch && value.name === undefined))) errors.set("price_imported", "is not number");
|
if (!(typeof value.price_imported === "number" || (patch && value.name === undefined))) errors.set("price_imported", "is not number");
|
||||||
if (!(typeof value.price || (patch && value.price === undefined))) errors.set("price", "is not number");
|
if (!(typeof value.price === "number" || (patch && value.price === undefined))) errors.set("price", "is not number");
|
||||||
|
|
||||||
|
// TODO: Excessive property checking
|
||||||
|
// Excessive properties should be checked and an error should be thrown if there is one
|
||||||
|
|
||||||
if (errors.size !== 0) throw createValidationError(errors);
|
if (errors.size !== 0) throw createValidationError(errors);
|
||||||
|
|
||||||
|
@ -78,7 +92,7 @@ export function checkIsImportedProduct<Patch extends boolean = boolean>(
|
||||||
export function checkIsOrder<Patch extends boolean = boolean>(
|
export function checkIsOrder<Patch extends boolean = boolean>(
|
||||||
value: any,
|
value: any,
|
||||||
patch: Patch,
|
patch: Patch,
|
||||||
): value is Patch extends true ? Partial<Pick<order, "client" | "is_draft">> : order {
|
): value is Patch extends true ? Partial<Omit<order, "imported_products" | "work">> : order {
|
||||||
const errors = new Map<string, string>();
|
const errors = new Map<string, string>();
|
||||||
|
|
||||||
if (typeof value !== "object") {
|
if (typeof value !== "object") {
|
||||||
|
@ -88,19 +102,22 @@ export function checkIsOrder<Patch extends boolean = boolean>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(typeof value.client === "string" || (patch && value.client === undefined))) errors.set("client", "is not string");
|
if (!(typeof value.clientId === "string" || (patch && value.clientId === undefined))) errors.set("clientId", "is not string");
|
||||||
if (!(typeof value.is_draft === "boolean" || value.is_draft === 0 || value.is_draft === 1 || (patch && value.is_draft === undefined))) errors.set("is_draft", "is not boolean");
|
if (!(typeof value.draft === "boolean" || (patch && value.is_draft === undefined))) errors.set("draft", "is not boolean");
|
||||||
if (!(value.imported_products instanceof Array)) errors.set("imported_products", "is not array");
|
if (!(value.imported_products instanceof Array)) errors.set("imported_products", "is not array");
|
||||||
else if (patch && value.imported_products !== undefined) errors.set("imported_products", "cannot patch from order");
|
else if (patch && value.imported_products !== undefined) errors.set("imported_products", "cannot patch from order");
|
||||||
if (!(value.work instanceof Array)) errors.set("work", "is not array");
|
if (!(value.work instanceof Array)) errors.set("work", "is not array");
|
||||||
else if (patch && value.work !== undefined) errors.set("work", "cannot patch from order");
|
else if (patch && value.work !== undefined) errors.set("work", "cannot patch from order");
|
||||||
|
|
||||||
|
// TODO: Excessive property checking
|
||||||
|
// Excessive properties should be checked and an error should be thrown if there is one
|
||||||
|
|
||||||
if (!patch) {
|
if (!patch) {
|
||||||
const importedProducts = value.imported_products;
|
const importedProducts = value.imported_products;
|
||||||
if (importedProducts instanceof Array) {
|
if (importedProducts instanceof Array) {
|
||||||
for (const i in importedProducts) {
|
for (const i in importedProducts) {
|
||||||
try {
|
try {
|
||||||
checkIsImportedProduct(importedProducts[i], patch);
|
checkIsImportedProduct(importedProducts[i], patch, false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
handleRecursedValidationError(e, errors, `imported_products[${i}]`);
|
handleRecursedValidationError(e, errors, `imported_products[${i}]`);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +128,7 @@ export function checkIsOrder<Patch extends boolean = boolean>(
|
||||||
if (work instanceof Array) {
|
if (work instanceof Array) {
|
||||||
for (const i in work) {
|
for (const i in work) {
|
||||||
try {
|
try {
|
||||||
checkIsWork(work[i], patch);
|
checkIsWork(work[i], patch, false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
handleRecursedValidationError(e, errors, `work[${i}]`);
|
handleRecursedValidationError(e, errors, `work[${i}]`);
|
||||||
}
|
}
|
||||||
|
@ -126,49 +143,49 @@ export function checkIsOrder<Patch extends boolean = boolean>(
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const body = await readBody(e);
|
const body = await readBody(e);
|
||||||
const id = new Snowflake().toString();
|
const id = new Snowflake().state;
|
||||||
const user = await getRequestingUser(e);
|
const user = await getRequestingUser(e);
|
||||||
|
|
||||||
if (!checkIsOrder(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
if (!checkIsOrder(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||||
|
|
||||||
const database = await db.new();
|
await database.order.create({
|
||||||
await database.beginTransaction();
|
data: {
|
||||||
|
clientId: BigInt(body.clientId),
|
||||||
await database.query(
|
draft: body.draft,
|
||||||
["INSERT INTO",
|
imported_products: {
|
||||||
"`orders`",
|
createMany: {
|
||||||
"VALUES",
|
data: body.imported_products.reduce(
|
||||||
"(?, ?, ?, ?)",
|
(pV, cV) => {
|
||||||
].join(" "),
|
pV.push({
|
||||||
[id, body.client, user.id, body.is_draft],
|
...cV,
|
||||||
);
|
id: new Snowflake().state,
|
||||||
|
});
|
||||||
const promises: Array<Promise<any>> = [];
|
return pV;
|
||||||
for (const i of body.imported_products) {
|
},
|
||||||
promises.push(database.query(
|
[] as Array<Omit<Prisma.Prisma.ImportedProductCreateManyOrderInput, "orderId">>,
|
||||||
["INSERT INTO",
|
),
|
||||||
"`imported_products`",
|
},
|
||||||
"VALUES",
|
},
|
||||||
"(?, ?, ?, ?, ?, ?)",
|
work: {
|
||||||
].join(" "),
|
createMany: {
|
||||||
[new Snowflake().toString(), id, i.name, i.link, i.price_imported, i.price],
|
data: body.work.reduce(
|
||||||
));
|
(pV, cV) => {
|
||||||
}
|
pV.push({
|
||||||
|
...cV,
|
||||||
for (const i of body.work) {
|
id: new Snowflake().state,
|
||||||
promises.push(database.query(
|
offerId: BigInt(cV.offerId),
|
||||||
["INSERT INTO",
|
});
|
||||||
"`work`",
|
return pV;
|
||||||
"VALUES",
|
},
|
||||||
"(?, ?, ?, ?, ?, ?)",
|
[] as Array<Omit<Prisma.Prisma.WorkCreateManyOrderInput, "orderId">>,
|
||||||
].join(" "),
|
),
|
||||||
[new Snowflake().toString(), id, i.offer, i.price, i.notes, i.is_fulfilled],
|
},
|
||||||
));
|
},
|
||||||
}
|
id,
|
||||||
|
userId: user.id,
|
||||||
await Promise.all(promises);
|
},
|
||||||
await database.commit();
|
});
|
||||||
|
|
||||||
setResponseStatus(e, 201);
|
setResponseStatus(e, 201);
|
||||||
return getOrder(id);
|
return getOrder(id).then(prismaToWeb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
import { type ResultSetHeader } from "mysql2";
|
|
||||||
|
|
||||||
import { database } from "~/server/utils/database";
|
import { database } from "~/server/utils/database";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const id = e.context.params?.id;
|
const id = e.context.params?.id as string;
|
||||||
|
|
||||||
const [result] = await database.query(
|
try {
|
||||||
"DELETE FROM `orders` WHERE `id` = ?",
|
await database.order.delete({
|
||||||
[id],
|
where: {
|
||||||
) as unknown as [ResultSetHeader];
|
id: BigInt(id),
|
||||||
|
},
|
||||||
if (result.affectedRows === 0) throw createError({ statusCode: 404 });
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// FIXME: should be 500 on errors other than "RecordNotFound"
|
||||||
|
throw createError({ statusCode: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,109 +1,38 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
import { type offer as offerType, type order } from "~/utils/types/database";
|
import { database } from "~/server/utils/database";
|
||||||
import { database, type data } from "~/server/utils/database";
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
export async function orderExists(id: string) {
|
export async function orderExists(id: bigint) {
|
||||||
const [[exists]] = await database.query(
|
const exists = await database.order.findUnique({
|
||||||
"SELECT EXISTS(*) AS `exists` FROM `orders` WHERE `id` = ?",
|
where: {
|
||||||
[id],
|
id,
|
||||||
) as data<{exists: 0 | 1}>;
|
},
|
||||||
|
});
|
||||||
return exists.exists === 1;
|
return exists !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getImportedProducts(id: string) {
|
export async function getOrder(id: bigint) {
|
||||||
const [importedProducts] = await database.query(
|
const order = await database.order.findUnique({
|
||||||
["SELECT",
|
where: {
|
||||||
"CONVERT(`id`, CHAR) AS `id`,",
|
id,
|
||||||
"`name`,",
|
},
|
||||||
"`link`,",
|
include: {
|
||||||
"`price`,",
|
imported_products: true,
|
||||||
"`price_imported`",
|
work: {
|
||||||
"FROM `imported_products`",
|
include: {
|
||||||
"WHERE `order` = ?",
|
offer: true,
|
||||||
].join(" "),
|
},
|
||||||
[id],
|
},
|
||||||
) as data<{
|
},
|
||||||
id: string,
|
});
|
||||||
name: string | null,
|
|
||||||
link: string,
|
|
||||||
price: string,
|
|
||||||
price_imported: string
|
|
||||||
}>;
|
|
||||||
|
|
||||||
return importedProducts;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWork(id: string) {
|
|
||||||
const [work] = await database.query(
|
|
||||||
["SELECT",
|
|
||||||
"CONVERT(`id`, CHAR) AS `id`,",
|
|
||||||
"CONVERT(`offer`, CHAR) AS `offer`,",
|
|
||||||
"`price`,",
|
|
||||||
"`notes`,",
|
|
||||||
"`is_fulfilled`",
|
|
||||||
"FROM `work`",
|
|
||||||
"WHERE `order` = ?",
|
|
||||||
].join(" "),
|
|
||||||
[id],
|
|
||||||
) as data<{
|
|
||||||
id: string,
|
|
||||||
offer: offerType,
|
|
||||||
price: number,
|
|
||||||
notes: string | null,
|
|
||||||
is_fulfilled: 0 | 1,
|
|
||||||
}>;
|
|
||||||
|
|
||||||
const [offer] = await database.query(
|
|
||||||
["SELECT",
|
|
||||||
"CONVERT(`offer`.`id`, CHAR) AS `id`,",
|
|
||||||
"`offer`.`name`,",
|
|
||||||
"`offer`.`description`,",
|
|
||||||
"`offer`.`recommended_price`",
|
|
||||||
"FROM",
|
|
||||||
"`work`",
|
|
||||||
"LEFT JOIN `offer` ON `work`.`offer` = `offer`.`id`",
|
|
||||||
"WHERE `work`.`order` = ?",
|
|
||||||
].join(" "),
|
|
||||||
[id],
|
|
||||||
) as data<offerType>;
|
|
||||||
|
|
||||||
// @ts-ignore i.offer is string, but it needs to be an offer object
|
|
||||||
for (const i of work) i.offer = offer.find(e => e.id === i.offer) as offerType;
|
|
||||||
return work;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getOrder(id: string): Promise<order> {
|
|
||||||
const [[order]] = await database.query(
|
|
||||||
["SELECT",
|
|
||||||
"CONVERT(`id`, CHAR) AS `id`,",
|
|
||||||
"CONVERT(`client`, CHAR) AS `client`,",
|
|
||||||
"CONVERT(`user`, CHAR) AS `user`, ",
|
|
||||||
"`is_draft`,",
|
|
||||||
"`value`",
|
|
||||||
"FROM `orderSummaries`",
|
|
||||||
"WHERE `id` = ?",
|
|
||||||
].join(" "),
|
|
||||||
[id],
|
|
||||||
) as data<{
|
|
||||||
id: string,
|
|
||||||
client: string,
|
|
||||||
user: string,
|
|
||||||
is_draft: 0 | 1,
|
|
||||||
value: number,
|
|
||||||
}>;
|
|
||||||
|
|
||||||
if (!order) throw createError({ statusCode: 404 });
|
if (!order) throw createError({ statusCode: 404 });
|
||||||
|
return order;
|
||||||
const importedProducts = await getImportedProducts(id);
|
|
||||||
const work = await getWork(id);
|
|
||||||
|
|
||||||
return { ...order, imported_products: importedProducts, work };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
export default defineEventHandler((e) => {
|
||||||
const key = e.context.params?.id;
|
const key = e.context.params?.id as string;
|
||||||
return getOrder(key as string);
|
return getOrder(BigInt(key)).then(prismaToWeb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,19 +1,27 @@
|
||||||
import { defineEventHandler, readBody } from "h3";
|
import { defineEventHandler, readBody } from "h3";
|
||||||
|
|
||||||
import { checkIsOrder } from "../orders.post";
|
import { checkIsOrder } from "../orders.post";
|
||||||
import { database as db } from "~/server/utils/database";
|
import { getOrder } from "./[id].get";
|
||||||
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const body = await readBody(e);
|
const body = await readBody(e);
|
||||||
const id = e.context.params?.id;
|
const id = e.context.params?.id as string;
|
||||||
|
|
||||||
if (!checkIsOrder(e, true)) throw createError({ message: "Invalid body", statusCode: 400 });
|
if (!checkIsOrder(body, true)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||||
|
|
||||||
const database = await db.new();
|
await database.order.update({
|
||||||
await database.beginTransaction();
|
where: {
|
||||||
|
id: BigInt(id),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
clientId: body.clientId ? BigInt(body.clientId) : undefined,
|
||||||
|
draft: body.draft,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(body))
|
return getOrder(BigInt(id)).then(prismaToWeb);
|
||||||
database.query(`UPDATE TABLE \`orders\` SET \`${k}\` = ? WHERE \`id\` = ?`, [v, id]);
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,27 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { orderExists, getImportedProducts } from "../[id].get";
|
import { orderExists } from "../[id].get";
|
||||||
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const id = e.context.params?.id as string;
|
const orderId = e.context.params?.id as string;
|
||||||
|
|
||||||
if (!orderExists(id)) throw createError({ statusCode: 404 });
|
if (!(await orderExists(BigInt(orderId)))) throw createError({ statusCode: 404 });
|
||||||
|
|
||||||
const importedProducts = await getImportedProducts(id);
|
return database.importedProduct.findMany({
|
||||||
return importedProducts;
|
where: {
|
||||||
|
orderId: BigInt(orderId),
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
link: true,
|
||||||
|
name: true,
|
||||||
|
orderId: true,
|
||||||
|
price: true,
|
||||||
|
price_imported: true,
|
||||||
|
},
|
||||||
|
}).then(prismaToWeb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +1,33 @@
|
||||||
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
||||||
|
|
||||||
import { checkIsImportedProduct } from "../../orders.post";
|
import { checkIsImportedProduct } from "../../orders.post";
|
||||||
import { getImportedProducts, orderExists } from "../[id].get";
|
import { orderExists } from "../[id].get";
|
||||||
import Snowflake from "~/utils/snowflake";
|
import Snowflake from "~/utils/snowflake";
|
||||||
import { database } from "~/server/utils/database";
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const body = await readBody(e);
|
const body = await readBody(e);
|
||||||
const idOrder = e.context.params?.id as string;
|
const idOrder = e.context.params?.id as string;
|
||||||
const idImportedProducts = new Snowflake().toString();
|
const idImportedProduct = new Snowflake().state;
|
||||||
|
|
||||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
if (!await orderExists(BigInt(idOrder))) throw createError({ statusCode: 404 });
|
||||||
if (!checkIsImportedProduct(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
if (!checkIsImportedProduct(body, false, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||||
|
|
||||||
await database.query(
|
const rvalue = await database.importedProduct.create({
|
||||||
["INSERT INTO",
|
data: {
|
||||||
"`imported_products`",
|
id: idImportedProduct,
|
||||||
"VALUES",
|
link: body.link,
|
||||||
"(?, ?, ?, ?, ?, ?)",
|
name: body.name,
|
||||||
].join(" "),
|
orderId: BigInt(idOrder),
|
||||||
[idImportedProducts, idOrder, body.name, body.link, body.price_imported, body.price],
|
price: body.price,
|
||||||
);
|
price_imported: body.price_imported,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setResponseStatus(e, 201);
|
setResponseStatus(e, 201);
|
||||||
return getImportedProducts(idOrder);
|
|
||||||
|
return prismaToWeb(rvalue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,31 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { orderExists, getWork } from "../[id].get";
|
import { orderExists } from "../[id].get";
|
||||||
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const id = e.context.params?.id as string;
|
const orderId = e.context.params?.id as string;
|
||||||
|
|
||||||
if (!orderExists(id)) throw createError({ statusCode: 404 });
|
if (!await orderExists(BigInt(orderId))) throw createError({ statusCode: 404 });
|
||||||
|
|
||||||
const work = await getWork(id);
|
const data = await database.work.findMany({
|
||||||
return work;
|
where: {
|
||||||
|
orderId: BigInt(orderId),
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
fulfilled: true,
|
||||||
|
notes: true,
|
||||||
|
offer: true,
|
||||||
|
orderId: true,
|
||||||
|
price: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) throw createError({ statusCode: 404 });
|
||||||
|
|
||||||
|
return prismaToWeb(data);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,30 +1,34 @@
|
||||||
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
||||||
|
import { Decimal } from "@prisma/client/runtime/library";
|
||||||
|
|
||||||
import { checkIsWork } from "../../orders.post";
|
import { checkIsWork } from "../../orders.post";
|
||||||
import { getWork, orderExists } from "../[id].get";
|
import { orderExists } from "../[id].get";
|
||||||
import Snowflake from "~/utils/snowflake";
|
import Snowflake from "~/utils/snowflake";
|
||||||
import { database } from "~/server/utils/database";
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const body = await readBody(e);
|
const body = await readBody(e);
|
||||||
const idOrder = e.context.params?.id as string;
|
const idOrder = e.context.params?.id as string;
|
||||||
const idWork = new Snowflake().toString();
|
const idWork = new Snowflake().state;
|
||||||
|
|
||||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
if (!orderExists(BigInt(idOrder))) throw createError({ statusCode: 404 });
|
||||||
if (!checkIsWork(body, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
if (!checkIsWork(body, false, false)) throw createError({ message: "Invalid body", statusCode: 400 });
|
||||||
|
|
||||||
await database.query(
|
const rvalue = await database.work.create({
|
||||||
["INSERT INTO",
|
data: {
|
||||||
"`work`",
|
id: BigInt(idWork),
|
||||||
"VALUES",
|
fulfilled: body.fulfilled,
|
||||||
"(?, ?, ?, ?, ?, ?)",
|
notes: body.notes,
|
||||||
].join(" "),
|
offerId: BigInt(body.offerId),
|
||||||
[idWork, idOrder, body.offer, body.price, body.notes, body.is_fulfilled],
|
orderId: BigInt(body.orderId),
|
||||||
);
|
price: new Decimal(body.price),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setResponseStatus(e, 201);
|
setResponseStatus(e, 201);
|
||||||
|
|
||||||
return getWork(idWork);
|
return prismaToWeb(rvalue);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { type ResultSetHeader } from "mysql2";
|
|
||||||
import { orderExists } from "../../[id].get";
|
|
||||||
import { database } from "~/server/utils/database";
|
import { database } from "~/server/utils/database";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
@ -10,13 +8,17 @@ export default defineEventHandler(async (e) => {
|
||||||
const idOrder = e.context.params?.id as string;
|
const idOrder = e.context.params?.id as string;
|
||||||
const idWork = e.context.params?.idWork as string;
|
const idWork = e.context.params?.idWork as string;
|
||||||
|
|
||||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
try {
|
||||||
|
await database.work.delete({
|
||||||
|
where: {
|
||||||
|
id: BigInt(idWork),
|
||||||
|
orderId: BigInt(idOrder),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// FIXME: should be 500 on errors other than "RecordNotFound"
|
||||||
|
throw createError({ statusCode: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
const [response] = await database.query(
|
|
||||||
"DELETE FROM `work` WHERE `id` = ?",
|
|
||||||
[idWork],
|
|
||||||
) as unknown as [ResultSetHeader];
|
|
||||||
|
|
||||||
if (response.affectedRows === 0) throw createError({ statusCode: 404 });
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,32 @@
|
||||||
import { defineEventHandler } from "h3";
|
import { defineEventHandler } from "h3";
|
||||||
|
|
||||||
import { orderExists, getWork } from "../../[id].get";
|
import { orderExists } from "../../[id].get";
|
||||||
|
import { database } from "~/server/utils/database";
|
||||||
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default defineEventHandler((e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
const idOrder = e.context.params?.id as string;
|
const idOrder = e.context.params?.id as string;
|
||||||
const idWork = e.context.params?.idWork as string;
|
const idWork = e.context.params?.idWork as string;
|
||||||
|
|
||||||
if (!orderExists(idOrder)) throw createError({ statusCode: 404 });
|
if (!await orderExists(BigInt(idOrder))) throw createError({ statusCode: 404 });
|
||||||
return getWork(idWork);
|
const data = await database.work.findUnique({
|
||||||
|
where: {
|
||||||
|
orderId: BigInt(idOrder),
|
||||||
|
id: BigInt(idWork),
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
fulfilled: true,
|
||||||
|
notes: true,
|
||||||
|
offer: true,
|
||||||
|
orderId: true,
|
||||||
|
price: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) throw createError({ statusCode: 404 });
|
||||||
|
|
||||||
|
return prismaToWeb(data);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
/* global defineEventHandler, getCookie */
|
import { defineEventHandler } from "h3";
|
||||||
import { defineEventHandler, getCookie } from "h3";
|
|
||||||
|
|
||||||
import { database, type data } from "~/server/utils/database";
|
import getRequestingUser from "~/server/utils/getRequestingUser";
|
||||||
import { type user } from "~/utils/types/database";
|
import { prismaToWeb } from "~/server/utils/prismaToWeb";
|
||||||
|
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler((e) => {
|
||||||
const token = getCookie(e, "token");
|
return getRequestingUser(e).then(prismaToWeb);
|
||||||
const [[userData]] = await database.query(
|
|
||||||
"SELECT CONVERT(`users`.`id`, CHAR(32)) as `id`, `users`.`username` as `username`, `users`.`email` as `email`, `users`.`display_name` as `display_name` FROM `sessions` LEFT JOIN `users` ON `sessions`.`user` = `users`.`id` WHERE `sessions`.`id` = ?",
|
|
||||||
[token],
|
|
||||||
) as unknown as data<user>;
|
|
||||||
|
|
||||||
return userData;
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { defineEventHandler, getCookie } from "h3";
|
import { defineEventHandler, getCookie } from "h3";
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
import { database, type data } from "~/server/utils/database";
|
import { database } from "~/server/utils/database";
|
||||||
|
import getRequestingUser from "~/server/utils/getRequestingUser";
|
||||||
|
|
||||||
const endpointsWithoutAuth: string[] = [
|
const endpointsWithoutAuth: string[] = [
|
||||||
"/dbtest",
|
"/dbtest",
|
||||||
|
@ -34,13 +35,14 @@ export default defineEventHandler(async (e) => {
|
||||||
export async function isAuthorised(token: string | undefined): Promise<boolean> {
|
export async function isAuthorised(token: string | undefined): Promise<boolean> {
|
||||||
if (!token) return false;
|
if (!token) return false;
|
||||||
try {
|
try {
|
||||||
const [[session]] = await database.query(
|
await database.session.findUniqueOrThrow({
|
||||||
"SELECT EXISTS(SELECT `id` FROM `sessions` WHERE `id` = ? AND `expiry_date` >= NOW()) as `logged_in`",
|
where: {
|
||||||
[token],
|
id: BigInt(token),
|
||||||
) as unknown as data<{logged_in: number}>;
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return session.logged_in === 1;
|
return true;
|
||||||
} catch {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
108
server/utils/baaPageParsing.ts
Normal file
108
server/utils/baaPageParsing.ts
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
// BAA stands for Before Around After
|
||||||
|
|
||||||
|
import { getQuery, type H3Event } from "h3";
|
||||||
|
import { type QueryObject } from "ufo";
|
||||||
|
|
||||||
|
import { isString } from "./isString";
|
||||||
|
|
||||||
|
import { createError } from "#imports";
|
||||||
|
|
||||||
|
type queryType<none extends boolean = boolean> = none extends false ? {
|
||||||
|
type: "before" | "after" | "around",
|
||||||
|
id: bigint
|
||||||
|
} : {
|
||||||
|
type: null
|
||||||
|
};
|
||||||
|
|
||||||
|
export type pageData<none extends boolean = boolean> = queryType<none> & { count: number }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets queryType for a given query with a value
|
||||||
|
* @param query the query to parse
|
||||||
|
* @throws if query malformed (multiple before/after/around)
|
||||||
|
*/
|
||||||
|
function getLocationParameterType(query: QueryObject): queryType {
|
||||||
|
const before = query.before;
|
||||||
|
const after = query.after;
|
||||||
|
const around = query.around;
|
||||||
|
|
||||||
|
let setLocationParametersCount = 0;
|
||||||
|
let rvalue: queryType = { type: null };
|
||||||
|
|
||||||
|
if (isString(before)) {
|
||||||
|
setLocationParametersCount++;
|
||||||
|
rvalue = { type: "before", id: BigInt(before) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isString(after)) {
|
||||||
|
setLocationParametersCount++;
|
||||||
|
rvalue = { type: "after", id: BigInt(after) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isString(around)) {
|
||||||
|
setLocationParametersCount++;
|
||||||
|
rvalue = { type: "around", id: BigInt(around) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setLocationParametersCount > 1) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
message: "multiple location parameters not allowed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return rvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the count parameter from the query object.
|
||||||
|
* @param query the query to check.
|
||||||
|
* @param defaultCount the default count if the query doesn't have count parameter. (default 50)
|
||||||
|
* @param countLimit the maximum count of the parameter before throwing. (default 200)
|
||||||
|
* @returns the value of count parameter.
|
||||||
|
* @throws if the parameter in query exceeds provided countLimit.
|
||||||
|
*/
|
||||||
|
function getRequestedCount(
|
||||||
|
query: QueryObject,
|
||||||
|
defaultCount = 50,
|
||||||
|
countLimit = 200,
|
||||||
|
) {
|
||||||
|
let count = defaultCount;
|
||||||
|
if (query.limit) count = Number(query.limit);
|
||||||
|
|
||||||
|
if (count > countLimit) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
message: `Cannot retrieve more than ${countLimit} records`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (count <= 0) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
message: "Tried to retireve 0 or less records",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the baa page parameters from the H3event,
|
||||||
|
* @param e the H3event to fetch parameters.
|
||||||
|
* @param defaultCount the default count to use if there is no count parameter. (default 50)
|
||||||
|
* @param countLimit the maximum value of the count parameter before throwing an error. (default 200)
|
||||||
|
* @returns the page data found in the query.
|
||||||
|
* @throws if event has a count parameter in the query that exceed provided countLimit.
|
||||||
|
*/
|
||||||
|
export default function getPaginatedParameters(
|
||||||
|
e: H3Event,
|
||||||
|
defaultCount = 50,
|
||||||
|
countLimit = 200,
|
||||||
|
): pageData {
|
||||||
|
const query = getQuery(e);
|
||||||
|
const queryParameters = getLocationParameterType(query);
|
||||||
|
const queryCount = getRequestedCount(query, defaultCount, countLimit);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...queryParameters,
|
||||||
|
count: queryCount,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,261 +0,0 @@
|
||||||
import { defineEventHandler, getQuery, readBody, setResponseStatus, H3Event } from "h3";
|
|
||||||
import { type ResultSetHeader } from "mysql2/promise";
|
|
||||||
|
|
||||||
import { type data, database } from "./database";
|
|
||||||
import { isString } from "./isString";
|
|
||||||
import Snowflake from "~/utils/snowflake";
|
|
||||||
import { type client } from "~/utils/types/database";
|
|
||||||
|
|
||||||
import { createError } from "#imports";
|
|
||||||
|
|
||||||
type queryType = {
|
|
||||||
type: "before" | "after" | "around",
|
|
||||||
id: string
|
|
||||||
} | {
|
|
||||||
type: null
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before, around, after pagination wrapper
|
|
||||||
*/
|
|
||||||
export default class BaaPagination<T extends {[k: string]: any}, keyType extends string = "id"> {
|
|
||||||
readonly table: string;
|
|
||||||
readonly key: keyType;
|
|
||||||
readonly select: string;
|
|
||||||
readonly groupBy: string;
|
|
||||||
|
|
||||||
private get sqlGroupBy() {
|
|
||||||
return this.groupBy !== "" ? `GROUP BY ${this.groupBy}` : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets queryType for a given query with a value
|
|
||||||
* @param query the query to parse
|
|
||||||
* @throws if query malformed (multiple before/after/around)
|
|
||||||
*/
|
|
||||||
static getLocationParameterType(query: any): queryType {
|
|
||||||
const before = query.before;
|
|
||||||
const after = query.after;
|
|
||||||
const around = query.around;
|
|
||||||
|
|
||||||
let setLocationParametersCount = 0;
|
|
||||||
let rvalue: queryType = { type: null };
|
|
||||||
|
|
||||||
if (isString(before)) {
|
|
||||||
setLocationParametersCount++;
|
|
||||||
rvalue = { type: "before", id: before };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isString(after)) {
|
|
||||||
setLocationParametersCount++;
|
|
||||||
rvalue = { type: "after", id: after };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isString(around)) {
|
|
||||||
setLocationParametersCount++;
|
|
||||||
rvalue = { type: "around", id: around };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setLocationParametersCount > 1) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 400,
|
|
||||||
message: "multiple location parameters not allowed",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return rvalue;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPagedResults(
|
|
||||||
queryType: queryType,
|
|
||||||
limit = 50,
|
|
||||||
where = "",
|
|
||||||
bind: Array<any> = [],
|
|
||||||
) {
|
|
||||||
const sqlwhere = where !== "" ? `AND (${where})` : "";
|
|
||||||
switch (queryType.type) {
|
|
||||||
case "before": {
|
|
||||||
const [data] = await database.query(
|
|
||||||
`SELECT ${this.select}, CONVERT(\`${this.key}\`, CHAR) AS \`${this.key}\` FROM \`${this.table}\` WHERE \`${this.key}\` < ? ${sqlwhere} ORDER BY \`${this.key}\` DESC ${this.sqlGroupBy} LIMIT ?`,
|
|
||||||
[queryType.id, ...bind, limit],
|
|
||||||
) as unknown as data<T>;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
case "after": {
|
|
||||||
const [data] = await database.query(
|
|
||||||
`SELECT ${this.select}, CONVERT(\`${this.key}\`, CHAR) AS \`${this.key}\` FROM \`${this.table}\` WHERE \`${this.key}\` > ? ${sqlwhere} ORDER BY \`${this.key}\` DESC ${this.sqlGroupBy} LIMIT ?`,
|
|
||||||
[queryType.id, ...bind, limit],
|
|
||||||
) as unknown as data<T>;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
case "around": {
|
|
||||||
const [data] = await database.query(
|
|
||||||
` SELECT ${this.select}, CONVERT(\`${this.key}\`, CHAR) AS \`${this.key}\` FROM (\n` +
|
|
||||||
`(SELECT * FROM \`${this.table}\` WHERE \`${this.key}\` >= ? ${sqlwhere} ORDER BY \`${this.key}\` ${this.sqlGroupBy} ASC LIMIT ?)\n` +
|
|
||||||
"UNION ALL\n" +
|
|
||||||
`(SELECT ${this.select} FROM \`${this.table}\` WHERE \`${this.key}\` < ? ${sqlwhere} ORDER BY \`${this.key}\` DESC ${this.sqlGroupBy} LIMIT ?)\n` +
|
|
||||||
`) as \`x\` ORDER BY \`${this.key}\` DESC`,
|
|
||||||
[queryType.id, ...bind, Math.ceil(limit / 2), queryType.id, ...bind, Math.floor(limit / 2)],
|
|
||||||
) as unknown as data<T>;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
case null: {
|
|
||||||
const [data] = await database.query(
|
|
||||||
`SELECT ${this.select}, CONVERT(\`${this.key}\`, CHAR) AS \`${this.key}\` FROM \`${this.table}\` WHERE TRUE ${sqlwhere} ORDER BY \`${this.key}\` DESC ${this.sqlGroupBy} LIMIT ?`,
|
|
||||||
[...bind, limit],
|
|
||||||
) as unknown as data<T>;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw createError("Not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RESTget(
|
|
||||||
e: H3Event,
|
|
||||||
defaultLimit = 50,
|
|
||||||
limitLimit = 200,
|
|
||||||
where = "",
|
|
||||||
bind: Array<any> = [],
|
|
||||||
) {
|
|
||||||
const query = getQuery(e);
|
|
||||||
|
|
||||||
let limit = defaultLimit;
|
|
||||||
if (query.limit) limit = Number(query.limit);
|
|
||||||
if (limit > limitLimit) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 400,
|
|
||||||
message: `Cannot retrieve more than ${limitLimit} records`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (limit <= 0) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 400,
|
|
||||||
message: "Tried to retireve 0 or less records",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryData = BaaPagination.getLocationParameterType(query);
|
|
||||||
|
|
||||||
return this.getPagedResults(queryData, limit, where, bind);
|
|
||||||
}
|
|
||||||
|
|
||||||
async RESTpost<K extends keyof Omit<T, keyType>>(
|
|
||||||
e: H3Event,
|
|
||||||
fields: Array<K>,
|
|
||||||
valueChecker: (obj: unknown) => obj is {[P in K]: T[P]},
|
|
||||||
) {
|
|
||||||
const body = await readBody(e);
|
|
||||||
const id = new Snowflake().toString();
|
|
||||||
|
|
||||||
if (!valueChecker(body)) throw createError({ message: "Invalid body", statusCode: 400 });
|
|
||||||
|
|
||||||
const arrayToInsert: Array<any> = [id];
|
|
||||||
arrayToInsert.push(...fields.map(field => body[field]));
|
|
||||||
|
|
||||||
await database.query(
|
|
||||||
`INSERT INTO \`${this.table}\` ` +
|
|
||||||
`(\`${this.key}\`,\`${fields.join("`, `")}\`) ` +
|
|
||||||
"VALUES (" +
|
|
||||||
"?, ".repeat(fields.length) +
|
|
||||||
"?)",
|
|
||||||
arrayToInsert,
|
|
||||||
);
|
|
||||||
|
|
||||||
setResponseStatus(e, 201);
|
|
||||||
|
|
||||||
// FIXME: data may be turncated in the database
|
|
||||||
// either throw an error when data is too large or
|
|
||||||
// reply with turncated data
|
|
||||||
return { id, ...body };
|
|
||||||
}
|
|
||||||
|
|
||||||
async RESTgetRecord(e: H3Event) {
|
|
||||||
const key = e.context.params?.[this.key];
|
|
||||||
const [data] = await database.query(
|
|
||||||
`SELECT ${this.select}, CONVERT(\`${this.key}\`, CHAR) AS \`${this.key}\` FROM \`${this.table}\` WHERE \`${this.key}\` = ?`,
|
|
||||||
[key],
|
|
||||||
) as data<T>;
|
|
||||||
|
|
||||||
if (!data[0]) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 404,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
async RESTpatchRecord(
|
|
||||||
e: H3Event,
|
|
||||||
valueChecker: (obj: unknown) => obj is Partial<Omit<T, keyType>>,
|
|
||||||
) {
|
|
||||||
const body = await readBody(e);
|
|
||||||
const key = e.context.params?.[this.key];
|
|
||||||
|
|
||||||
if (!valueChecker(body)) throw createError({ message: "Invalid body", statusCode: 400 });
|
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(body)) {
|
|
||||||
// FIXME: use single database.query method instead of looping through keys and values
|
|
||||||
const [res] = await database.query(
|
|
||||||
// I believe it is safe to put key (k) in the template
|
|
||||||
// because it is limited to 4 values here
|
|
||||||
`UPDATE \`${this.table}\` SET \`${k}\` = ? WHERE \`${this.key}\` = ?`,
|
|
||||||
[v, key],
|
|
||||||
) as unknown as [ResultSetHeader];
|
|
||||||
|
|
||||||
if (res.affectedRows !== 1) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 404,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [data] = await database.query(
|
|
||||||
`SELECT ${this.select}, CONVERT(\`${this.key}\`, CHAR) AS \`${this.key}\` FROM \`${this.table}\` WHERE \`${this.key}\` = ?`,
|
|
||||||
[key],
|
|
||||||
) as data<T>;
|
|
||||||
|
|
||||||
return data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
async RESTdeleteRecord(e: H3Event) {
|
|
||||||
const key = e.context.params?.[this.key];
|
|
||||||
|
|
||||||
const [result] = await database.query(
|
|
||||||
`DELETE FROM \`${this.table}\` WHERE \`${this.key}\` = ?`,
|
|
||||||
[key],
|
|
||||||
) as unknown as [ResultSetHeader];
|
|
||||||
|
|
||||||
if (result.affectedRows === 0) throw createError({ statusCode: 404 });
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async RESTrecordCount(
|
|
||||||
e :H3Event,
|
|
||||||
where = "",
|
|
||||||
bind: Array<any> = [],
|
|
||||||
) {
|
|
||||||
const sqlwhere = where !== "" ? `WHERE ${where}` : "";
|
|
||||||
const [[data]] = await database.query(
|
|
||||||
`SELECT COUNT(*) as \`count\` FROM \`${this.table}\` ${sqlwhere} ${this.sqlGroupBy}`,
|
|
||||||
bind,
|
|
||||||
) as data<{count: number}>;
|
|
||||||
|
|
||||||
if (!data) throw createError("Database returned no rows");
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
table: string,
|
|
||||||
key: keyType,
|
|
||||||
select = "*",
|
|
||||||
groupBy = "",
|
|
||||||
) {
|
|
||||||
this.table = table;
|
|
||||||
this.key = key;
|
|
||||||
this.select = select;
|
|
||||||
this.groupBy = groupBy;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +1,99 @@
|
||||||
import mysql, { type Connection } from "mysql2/promise";
|
import { PrismaClient, Prisma } from "@prisma/client";
|
||||||
|
|
||||||
const connectionOptions: mysql.ConnectionOptions = {
|
import { type pageData } from "./baaPageParsing";
|
||||||
host: process.env.DB_HOST,
|
|
||||||
port: Number(process.env.DB_PORT),
|
|
||||||
user: process.env.DB_USER,
|
|
||||||
password: process.env.DB_PASSWORD,
|
|
||||||
database: process.env.DB_SCHEMA,
|
|
||||||
decimalNumbers: true,
|
|
||||||
supportBigNumbers: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const database =
|
type model = PrismaClient[Uncapitalize<Prisma.ModelName>];
|
||||||
await mysql.createConnection(connectionOptions) as Connection & {
|
|
||||||
new: (localConnectionOptions?: mysql.ConnectionOptions | undefined) => Promise<Connection>
|
|
||||||
};
|
|
||||||
database.new = (localConnectionOptions?: mysql.ConnectionOptions | undefined) => { return mysql.createConnection({ ...localConnectionOptions, ...connectionOptions }); };
|
|
||||||
|
|
||||||
export type data<T> = [T[], mysql.FieldPacket[]];
|
function getBeforeParameters<T, A>(
|
||||||
|
pageData: pageData<false>,
|
||||||
|
fetchArgs: Prisma.Args<T, "findMany">,
|
||||||
|
) {
|
||||||
|
const _fetchArgs = Object.assign({}, fetchArgs);
|
||||||
|
return Object.assign(_fetchArgs, {
|
||||||
|
take: pageData.count,
|
||||||
|
orderBy: [
|
||||||
|
{ id: "desc" },
|
||||||
|
],
|
||||||
|
where: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
_lt: pageData.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetchArgs.where,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAfterParameters<T>(
|
||||||
|
pageData: pageData<false>,
|
||||||
|
fetchArgs: Prisma.Args<T, "findMany">,
|
||||||
|
) {
|
||||||
|
const _fetchArgs = Object.assign({}, fetchArgs);
|
||||||
|
return Object.assign(_fetchArgs, {
|
||||||
|
take: pageData.count,
|
||||||
|
orderBy: [
|
||||||
|
{ id: "desc" },
|
||||||
|
],
|
||||||
|
where: {
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
_gt: pageData.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetchArgs.where,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNullParameters<T>(
|
||||||
|
pageData: pageData<true>,
|
||||||
|
fetchArgs: Prisma.Args<T, "findMany">,
|
||||||
|
) {
|
||||||
|
const _fetchArgs = Object.assign({}, fetchArgs);
|
||||||
|
return Object.assign(_fetchArgs, {
|
||||||
|
take: pageData.count,
|
||||||
|
orderBy: [
|
||||||
|
{ id: "desc" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const database = new PrismaClient().$extends({
|
||||||
|
model: {
|
||||||
|
$allModels: {
|
||||||
|
findPaginated<T, A>(
|
||||||
|
this: T,
|
||||||
|
pageData: pageData,
|
||||||
|
fetchArgs: Prisma.Exact<A, Prisma.Args<T, "findMany">>,
|
||||||
|
): Promise<Prisma.Result<T, A, "findMany">> {
|
||||||
|
const context = Prisma.getExtensionContext(this) as any;
|
||||||
|
switch (pageData.type) {
|
||||||
|
case "before":
|
||||||
|
return context.findMany(getBeforeParameters(pageData, fetchArgs));
|
||||||
|
case "after":
|
||||||
|
return context.findMany(getAfterParameters(pageData, fetchArgs));
|
||||||
|
case "around":
|
||||||
|
return Promise.all([
|
||||||
|
context.findMany(getBeforeParameters({
|
||||||
|
type: "before",
|
||||||
|
id: pageData.id,
|
||||||
|
count: Math.ceil(pageData.count),
|
||||||
|
}, fetchArgs)),
|
||||||
|
context.findMany(getAfterParameters({
|
||||||
|
type: "after",
|
||||||
|
id: pageData.id,
|
||||||
|
count: Math.floor(pageData.count),
|
||||||
|
}, fetchArgs)),
|
||||||
|
]).then(rv => rv.flat()) as Promise<any>;
|
||||||
|
case null:
|
||||||
|
return context.findMany(getNullParameters(pageData, fetchArgs));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
import { getCookie, H3Event } from "h3";
|
import { getCookie, H3Event } from "h3";
|
||||||
|
|
||||||
import { database, type data } from "./database";
|
import { database } from "./database";
|
||||||
import { type user } from "~/utils/types/database";
|
|
||||||
|
|
||||||
import { createError } from "#imports";
|
import { createError } from "#imports";
|
||||||
|
|
||||||
export default async function getRequestingUser(e: H3Event) {
|
export default async function getRequestingUser(e: H3Event) {
|
||||||
const cookie = getCookie(e, "token");
|
const cookie = getCookie(e, "token");
|
||||||
const [[user]] = await database.query(
|
if (!cookie) throw createError("User not found");
|
||||||
["SELECT",
|
const { user } = await database.session.findUnique({
|
||||||
"CONVERT(`users`.`id`, CHAR) as `id`,",
|
where: {
|
||||||
"`users`.`username`,",
|
id: BigInt(cookie),
|
||||||
"`users`.`email`,",
|
},
|
||||||
"`users`.`display_name`",
|
select: {
|
||||||
"FROM",
|
user: {
|
||||||
"`sessions`",
|
select: {
|
||||||
"LEFT JOIN `users` ON `sessions`.`user` = `users`.`id`",
|
display_name: true,
|
||||||
"WHERE `sessions`.`id` = ?",
|
email: true,
|
||||||
].join(" "),
|
id: true,
|
||||||
[cookie],
|
username: true,
|
||||||
) as data<user>;
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).then((e) => {
|
||||||
|
if (e === null) throw createError("User not found");
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
|
||||||
if (!user) throw createError("User not found");
|
if (!user) throw createError("User not found");
|
||||||
return user;
|
return user;
|
||||||
|
|
44
server/utils/prismaToWeb.ts
Normal file
44
server/utils/prismaToWeb.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { Decimal } from "@prisma/client/runtime/library";
|
||||||
|
|
||||||
|
type func = (...args: any[]) => any | Function;
|
||||||
|
|
||||||
|
export type replaceJsonUnparsableToString<T> =
|
||||||
|
T extends Array<infer E> ? Array<replaceJsonUnparsableToString<E>>
|
||||||
|
: {
|
||||||
|
[K in keyof T]:
|
||||||
|
T[K] extends null ? null
|
||||||
|
: T[K] extends func ? never
|
||||||
|
: T[K] extends Decimal ? `${number}`
|
||||||
|
: T[K] extends Array<infer E> ? Array<replaceJsonUnparsableToString<E>>
|
||||||
|
: T[K] extends object ? replaceJsonUnparsableToString<T[K]>
|
||||||
|
: T[K] extends bigint ? `${bigint}`
|
||||||
|
: T[K]
|
||||||
|
};
|
||||||
|
|
||||||
|
type exactToInterface = (...args: any[]) => any extends Function ? true : false;
|
||||||
|
|
||||||
|
function arrayPrismaToWeb<T>(array: Array<T>) {
|
||||||
|
return array.reduce(
|
||||||
|
(pV, cV) => {
|
||||||
|
pV.push(prismaToWeb(cV));
|
||||||
|
return pV;
|
||||||
|
},
|
||||||
|
[] as Array<replaceJsonUnparsableToString<T>>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function prismaToWeb<T>(ivalue: T): replaceJsonUnparsableToString<T> {
|
||||||
|
const rvalue: any = ivalue instanceof Array ? [] : {};
|
||||||
|
|
||||||
|
for (const i in ivalue) {
|
||||||
|
const current = ivalue[i];
|
||||||
|
if (current === null) rvalue[i] = null;
|
||||||
|
else if (typeof current === 'function') continue;
|
||||||
|
else if (current instanceof Decimal) rvalue[i] = current.toString();
|
||||||
|
else if (current instanceof Array) rvalue[i] = arrayPrismaToWeb(current);
|
||||||
|
else if (typeof current === 'object') rvalue[i] = prismaToWeb(current);
|
||||||
|
else if (typeof current === 'bigint') rvalue[i] = current.toString();
|
||||||
|
else rvalue[i] = current;
|
||||||
|
}
|
||||||
|
return rvalue;
|
||||||
|
}
|
|
@ -1,99 +0,0 @@
|
||||||
export interface client {
|
|
||||||
id: string;
|
|
||||||
name: string | null;
|
|
||||||
address: string | null;
|
|
||||||
phone: string | null;
|
|
||||||
email: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface user {
|
|
||||||
id: string;
|
|
||||||
username: string;
|
|
||||||
email: string;
|
|
||||||
display_name?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface session {
|
|
||||||
id: string;
|
|
||||||
user: string;
|
|
||||||
expiry_date: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface imported_product {
|
|
||||||
id: string;
|
|
||||||
// order: string,
|
|
||||||
name?: string;
|
|
||||||
link: string;
|
|
||||||
price_imported: string;
|
|
||||||
price: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface offer {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
recommended_price?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface work {
|
|
||||||
id: string;
|
|
||||||
// order: string,
|
|
||||||
offer: string | offer;
|
|
||||||
price: string;
|
|
||||||
notes: string;
|
|
||||||
is_fulfilled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface order {
|
|
||||||
imported_products: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string | null;
|
|
||||||
link: string;
|
|
||||||
price: string;
|
|
||||||
price_imported: string;
|
|
||||||
}>;
|
|
||||||
work: {
|
|
||||||
id: string;
|
|
||||||
offer: offer;
|
|
||||||
price: number;
|
|
||||||
notes: string | null;
|
|
||||||
is_fulfilled: 0 | 1;
|
|
||||||
}[];
|
|
||||||
id: string;
|
|
||||||
client: string;
|
|
||||||
user: string;
|
|
||||||
is_draft: 0 | 1;
|
|
||||||
value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface orderSummary {
|
|
||||||
id: string;
|
|
||||||
client: string;
|
|
||||||
user: string;
|
|
||||||
is_draft: 0 | 1;
|
|
||||||
value: string;
|
|
||||||
imported_products_count: number;
|
|
||||||
work_count: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface work_template {
|
|
||||||
id: string;
|
|
||||||
// order_template: string,
|
|
||||||
offer: string | offer;
|
|
||||||
price: string;
|
|
||||||
notes?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface order_template {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1 is true, 0 is false
|
|
||||||
export type Dboolean =
|
|
||||||
| boolean
|
|
||||||
| 0 // false
|
|
||||||
| 1; // true
|
|
||||||
|
|
||||||
export type Dnumber = number | `${number}`;
|
|
Loading…
Reference in a new issue