mirror of
https://github.com/jorgev259/soc_site-astro.git
synced 2025-06-29 07:57:41 +00:00
Set up sequelize
This commit is contained in:
parent
6833439a4a
commit
87c08df02b
47 changed files with 2171 additions and 6 deletions
|
|
@ -15,6 +15,7 @@ const config: CodegenConfig = {
|
||||||
resolverGeneration: 'disabled',
|
resolverGeneration: 'disabled',
|
||||||
typesPluginsConfig: {
|
typesPluginsConfig: {
|
||||||
contextType: '../client.mts#ResolverContext',
|
contextType: '../client.mts#ResolverContext',
|
||||||
|
maybeValue: 'T'
|
||||||
},
|
},
|
||||||
add: {
|
add: {
|
||||||
'./types.generated.ts': { content: '// @ts-nocheck' },
|
'./types.generated.ts': { content: '// @ts-nocheck' },
|
||||||
|
|
|
||||||
268
package-lock.json
generated
268
package-lock.json
generated
|
|
@ -15,15 +15,20 @@
|
||||||
"@auth/core": "^0.32.0",
|
"@auth/core": "^0.32.0",
|
||||||
"@eddeee888/gcg-typescript-resolver-files": "^0.10.4",
|
"@eddeee888/gcg-typescript-resolver-files": "^0.10.4",
|
||||||
"@graphql-codegen/cli": "^5.0.2",
|
"@graphql-codegen/cli": "^5.0.2",
|
||||||
|
"@graphql-tools/load-files": "^7.0.0",
|
||||||
"@graphql-tools/resolvers-composition": "^7.0.1",
|
"@graphql-tools/resolvers-composition": "^7.0.1",
|
||||||
"@graphql-tools/schema": "^10.0.4",
|
"@graphql-tools/schema": "^10.0.4",
|
||||||
"astro": "^4.13.1",
|
"astro": "^4.13.1",
|
||||||
"auth-astro": "^4.1.2",
|
"auth-astro": "^4.1.2",
|
||||||
"graphql-scalars": "^1.23.0",
|
"graphql-scalars": "^1.23.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"mysql2": "^3.11.0",
|
||||||
|
"sequelize": "^6.37.3",
|
||||||
"tailwindcss": "^3.4.8"
|
"tailwindcss": "^3.4.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@parcel/watcher": "^2.4.1",
|
"@parcel/watcher": "^2.4.1",
|
||||||
|
"@types/lodash": "^4.17.7",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
|
|
@ -2185,6 +2190,22 @@
|
||||||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@graphql-tools/load-files": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@graphql-tools/load-files/-/load-files-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-P98amERIwI7FD8Bsq6xUbz9Mj63W8qucfrE/WQjad5jFMZYdFFt46a99FFdfx8S/ZYgpAlj/AZbaTtWLitMgNQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"globby": "11.1.0",
|
||||||
|
"tslib": "^2.4.0",
|
||||||
|
"unixify": "1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@graphql-tools/load/node_modules/p-limit": {
|
"node_modules/@graphql-tools/load/node_modules/p-limit": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||||
|
|
@ -3200,6 +3221,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
||||||
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="
|
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/lodash": {
|
||||||
|
"version": "4.17.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz",
|
||||||
|
"integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/mdast": {
|
"node_modules/@types/mdast": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
|
||||||
|
|
@ -3234,6 +3261,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz",
|
||||||
"integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ=="
|
"integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/validator": {
|
||||||
|
"version": "13.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.0.tgz",
|
||||||
|
"integrity": "sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag=="
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.12",
|
"version": "8.5.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
|
||||||
|
|
@ -4198,6 +4230,14 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/aws-ssl-profiles": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/axe-core": {
|
"node_modules/axe-core": {
|
||||||
"version": "4.10.0",
|
"version": "4.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz",
|
||||||
|
|
@ -5398,6 +5438,14 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
|
|
@ -5525,6 +5573,11 @@
|
||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dottie": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA=="
|
||||||
|
},
|
||||||
"node_modules/dset": {
|
"node_modules/dset": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz",
|
||||||
|
|
@ -6737,6 +6790,14 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/generate-function": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-property": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/gensync": {
|
"node_modules/gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
|
|
@ -7484,6 +7545,14 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/inflection": {
|
||||||
|
"version": "1.13.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz",
|
||||||
|
"integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==",
|
||||||
|
"engines": [
|
||||||
|
"node >= 0.4.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/inflight": {
|
"node_modules/inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
|
|
@ -8105,6 +8174,11 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-property": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="
|
||||||
|
},
|
||||||
"node_modules/is-regex": {
|
"node_modules/is-regex": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
||||||
|
|
@ -8904,6 +8978,11 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/long": {
|
||||||
|
"version": "5.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||||
|
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||||
|
},
|
||||||
"node_modules/longest-streak": {
|
"node_modules/longest-streak": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
|
||||||
|
|
@ -9829,6 +9908,25 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/moment": {
|
||||||
|
"version": "2.30.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||||
|
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/moment-timezone": {
|
||||||
|
"version": "0.5.45",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz",
|
||||||
|
"integrity": "sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"moment": "^2.29.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mrmime": {
|
"node_modules/mrmime": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||||
|
|
@ -9852,6 +9950,44 @@
|
||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/mysql2": {
|
||||||
|
"version": "3.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz",
|
||||||
|
"integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==",
|
||||||
|
"dependencies": {
|
||||||
|
"aws-ssl-profiles": "^1.1.1",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"generate-function": "^2.3.1",
|
||||||
|
"iconv-lite": "^0.6.3",
|
||||||
|
"long": "^5.2.1",
|
||||||
|
"lru-cache": "^8.0.0",
|
||||||
|
"named-placeholders": "^1.1.3",
|
||||||
|
"seq-queue": "^0.0.5",
|
||||||
|
"sqlstring": "^2.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mysql2/node_modules/iconv-lite": {
|
||||||
|
"version": "0.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
|
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mysql2/node_modules/lru-cache": {
|
||||||
|
"version": "8.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
|
||||||
|
"integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mz": {
|
"node_modules/mz": {
|
||||||
"version": "2.7.0",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||||
|
|
@ -9862,6 +9998,25 @@
|
||||||
"thenify-all": "^1.0.0"
|
"thenify-all": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/named-placeholders": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^7.14.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/named-placeholders/node_modules/lru-cache": {
|
||||||
|
"version": "7.18.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
|
||||||
|
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
|
|
@ -10668,6 +10823,11 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pg-connection-string": {
|
||||||
|
"version": "2.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz",
|
||||||
|
"integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA=="
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
||||||
|
|
@ -11489,6 +11649,11 @@
|
||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/retry-as-promised": {
|
||||||
|
"version": "7.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz",
|
||||||
|
"integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA=="
|
||||||
|
},
|
||||||
"node_modules/reusify": {
|
"node_modules/reusify": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||||
|
|
@ -11796,6 +11961,80 @@
|
||||||
"upper-case-first": "^2.0.2"
|
"upper-case-first": "^2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/seq-queue": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
|
||||||
|
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
|
||||||
|
},
|
||||||
|
"node_modules/sequelize": {
|
||||||
|
"version": "6.37.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.3.tgz",
|
||||||
|
"integrity": "sha512-V2FTqYpdZjPy3VQrZvjTPnOoLm0KudCRXfGWp48QwhyPPp2yW8z0p0sCYZd/em847Tl2dVxJJ1DR+hF+O77T7A==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/sequelize"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@types/debug": "^4.1.8",
|
||||||
|
"@types/validator": "^13.7.17",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"dottie": "^2.0.6",
|
||||||
|
"inflection": "^1.13.4",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"moment": "^2.29.4",
|
||||||
|
"moment-timezone": "^0.5.43",
|
||||||
|
"pg-connection-string": "^2.6.1",
|
||||||
|
"retry-as-promised": "^7.0.4",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"sequelize-pool": "^7.1.0",
|
||||||
|
"toposort-class": "^1.0.1",
|
||||||
|
"uuid": "^8.3.2",
|
||||||
|
"validator": "^13.9.0",
|
||||||
|
"wkx": "^0.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ibm_db": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"mariadb": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"mysql2": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"oracledb": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"pg": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"pg-hstore": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"snowflake-sdk": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sqlite3": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"tedious": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sequelize-pool": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/server-destroy": {
|
"node_modules/server-destroy": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
|
||||||
|
|
@ -12073,6 +12312,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
|
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
|
||||||
},
|
},
|
||||||
|
"node_modules/sqlstring": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
|
@ -12562,6 +12809,11 @@
|
||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/toposort-class": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg=="
|
||||||
|
},
|
||||||
"node_modules/tr46": {
|
"node_modules/tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
|
@ -13057,6 +13309,14 @@
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/validator": {
|
||||||
|
"version": "13.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
|
||||||
|
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/value-or-promise": {
|
"node_modules/value-or-promise": {
|
||||||
"version": "1.0.12",
|
"version": "1.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz",
|
||||||
|
|
@ -13561,6 +13821,14 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wkx": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/word-wrap": {
|
"node_modules/word-wrap": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,20 @@
|
||||||
"@auth/core": "^0.32.0",
|
"@auth/core": "^0.32.0",
|
||||||
"@eddeee888/gcg-typescript-resolver-files": "^0.10.4",
|
"@eddeee888/gcg-typescript-resolver-files": "^0.10.4",
|
||||||
"@graphql-codegen/cli": "^5.0.2",
|
"@graphql-codegen/cli": "^5.0.2",
|
||||||
|
"@graphql-tools/load-files": "^7.0.0",
|
||||||
"@graphql-tools/resolvers-composition": "^7.0.1",
|
"@graphql-tools/resolvers-composition": "^7.0.1",
|
||||||
"@graphql-tools/schema": "^10.0.4",
|
"@graphql-tools/schema": "^10.0.4",
|
||||||
"astro": "^4.13.1",
|
"astro": "^4.13.1",
|
||||||
"auth-astro": "^4.1.2",
|
"auth-astro": "^4.1.2",
|
||||||
"graphql-scalars": "^1.23.0",
|
"graphql-scalars": "^1.23.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"mysql2": "^3.11.0",
|
||||||
|
"sequelize": "^6.37.3",
|
||||||
"tailwindcss": "^3.4.8"
|
"tailwindcss": "^3.4.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@parcel/watcher": "^2.4.1",
|
"@parcel/watcher": "^2.4.1",
|
||||||
|
"@types/lodash": "^4.17.7",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
|
|
|
||||||
2
src/constants/index.ts
Normal file
2
src/constants/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export const PLACEHOLDER =
|
||||||
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAECAIAAADETxJQAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAMUlEQVQImWN4fGrVhZ0z/v+5zZAc5yfOwGCtrsbg4em/f7ZvZ7w2Q15Vi6e1iggPAwBwDg7L//0+xAAAAABJRU5ErkJggg=='
|
||||||
|
|
@ -1,19 +1,27 @@
|
||||||
import { makeExecutableSchema } from "@graphql-tools/schema";
|
import ApolloPackage from '@apollo/client'
|
||||||
import { ApolloClient, InMemoryCache } from "@apollo/client";
|
const { ApolloClient, InMemoryCache } = ApolloPackage;
|
||||||
import { SchemaLink } from "@apollo/client/link/schema"
|
import { SchemaLink } from "@apollo/client/link/schema"
|
||||||
|
import { makeExecutableSchema } from "@graphql-tools/schema";
|
||||||
|
import { loadFilesSync } from '@graphql-tools/load-files'
|
||||||
|
import { mergeResolvers } from '@graphql-tools/merge'
|
||||||
|
import path from "node:path"
|
||||||
|
|
||||||
import { typeDefs } from "./__generated__/typeDefs.generated";
|
import { typeDefs } from "./__generated__/typeDefs.generated";
|
||||||
import { resolvers } from "./__generated__/resolvers.generated";
|
// import { resolvers } from "./__generated__/resolvers.generated";
|
||||||
|
import db from "@/sequelize";
|
||||||
|
import resolverArray from '@/graphql/resolvers'
|
||||||
|
|
||||||
|
export const resolvers = mergeResolvers(resolverArray)
|
||||||
|
|
||||||
const schema = makeExecutableSchema({ typeDefs, resolvers })
|
const schema = makeExecutableSchema({ typeDefs, resolvers })
|
||||||
export type ResolverContext = { request?: Request; /*session?: Session */ }
|
export type ResolverContext = { request?: Request, db: any /*session?: Session */ }
|
||||||
|
|
||||||
export async function getApolloClient(request?: Request) {
|
export async function getApolloClient(request?: Request) {
|
||||||
// const session = request ? await getSession(request) : undefined
|
// const session = request ? await getSession(request) : undefined
|
||||||
|
|
||||||
return new ApolloClient({
|
return new ApolloClient({
|
||||||
ssrMode: true,
|
ssrMode: true,
|
||||||
link: new SchemaLink({ schema, context: { request } }),
|
link: new SchemaLink({ schema, context: { request, db } }),
|
||||||
cache: new InMemoryCache()
|
cache: new InMemoryCache()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
7
src/graphql/resolvers/index.js
Normal file
7
src/graphql/resolvers/index.js
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
// import mutations from './mutations'
|
||||||
|
import queries from './queries'
|
||||||
|
// import types from './types'
|
||||||
|
|
||||||
|
const resolvers = { /*...mutations,*/ ...queries /*...types*/ }
|
||||||
|
|
||||||
|
export default resolvers
|
||||||
54
src/graphql/resolvers/mutations/comments.js
Normal file
54
src/graphql/resolvers/mutations/comments.js
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
// import axios from 'axios'
|
||||||
|
|
||||||
|
import { isAuthedApp } from '@/server/utils/resolvers'
|
||||||
|
import { getSession, getUser } from '@/next/utils/getSession'
|
||||||
|
|
||||||
|
// const token = process.env.IRONCLAD
|
||||||
|
|
||||||
|
const resolversComposition = {
|
||||||
|
'Mutation.*': [isAuthedApp]
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Mutation: {
|
||||||
|
updateComment: async (_, { text, anon, albumId }, { db }) => {
|
||||||
|
const { username } = await getSession()
|
||||||
|
const row = await db.models.comment.findOne({
|
||||||
|
where: { albumId, username }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (row) {
|
||||||
|
await row.update({ text, anon })
|
||||||
|
await row.save()
|
||||||
|
} else await db.models.comment.create({ albumId, username, text, anon })
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
addFavorite: async (_, { albumId }, { db }) => {
|
||||||
|
const user = await getUser(db)
|
||||||
|
await user.addAlbum(albumId)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
removeFavorite: async (_, { albumId }, { db }) => {
|
||||||
|
const user = await getUser(db)
|
||||||
|
await user.removeAlbum(albumId)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
rateAlbum: async (_, { albumId, score }, { db }) => {
|
||||||
|
const { username } = await getSession()
|
||||||
|
const row = await db.models.rating.findOne({
|
||||||
|
where: { albumId, username }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (row) {
|
||||||
|
await row.update({ score })
|
||||||
|
await row.save()
|
||||||
|
} else await db.models.rating.create({ albumId, username, score })
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeResolvers(resolvers, resolversComposition)
|
||||||
81
src/graphql/resolvers/mutations/create.js
Normal file
81
src/graphql/resolvers/mutations/create.js
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
|
||||||
|
import { createLog, createUpdateLog } from '@/server/utils/log'
|
||||||
|
import { getImgColor, img } from '@/server/utils/image'
|
||||||
|
import { hasRole } from '@/server/utils/resolvers'
|
||||||
|
import { handleComplete } from '@/server/utils/requests'
|
||||||
|
import { slugify } from '@/server/utils/slugify'
|
||||||
|
import { UserInputError } from '@/next/server/utils/graphQLErrors'
|
||||||
|
|
||||||
|
const resolversComposition = { 'Mutation.*': hasRole('CREATE') }
|
||||||
|
const resolvers = {
|
||||||
|
Mutation: {
|
||||||
|
createAlbum: async (parent, data, { db }, info) =>
|
||||||
|
db.transaction(async (transaction) => {
|
||||||
|
data.artists = data.artists
|
||||||
|
? data.artists.map((artist) => {
|
||||||
|
return { name: artist, slug: slugify(artist) }
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
await db.models.artist.bulkCreate(data.artists, {
|
||||||
|
ignoreDuplicates: true,
|
||||||
|
transaction
|
||||||
|
})
|
||||||
|
|
||||||
|
const album = await db.models.album.create(data, {
|
||||||
|
include: [
|
||||||
|
db.models.disc,
|
||||||
|
db.models.store,
|
||||||
|
{
|
||||||
|
model: db.models.download,
|
||||||
|
include: [db.models.link]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
transaction
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
album.setArtists(
|
||||||
|
data.artists
|
||||||
|
.filter(({ slug }) => slug.length > 0)
|
||||||
|
.map(({ slug }) => slug),
|
||||||
|
{ transaction }
|
||||||
|
),
|
||||||
|
album.setCategories(data.categories || [], { transaction }),
|
||||||
|
album.setClassifications(data.classifications || [], { transaction }),
|
||||||
|
album.setPlatforms(data.platforms || [], { transaction }),
|
||||||
|
album.setGames(data.games || [], { transaction }),
|
||||||
|
album.setAnimations(data.animations || [], { transaction }),
|
||||||
|
album.setRelated(data.related || [], { transaction }),
|
||||||
|
createLog(db, 'createAlbum', data, transaction)
|
||||||
|
])
|
||||||
|
|
||||||
|
const { id } = album.dataValues
|
||||||
|
album.placeholder = data.cover
|
||||||
|
? await img(data.cover, 'album', id)
|
||||||
|
: undefined
|
||||||
|
album.headerColor = data.cover
|
||||||
|
? await getImgColor(`album/${id}`)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
await album.save({ transaction })
|
||||||
|
|
||||||
|
if (album.status === 'show') handleComplete(db, data, album)
|
||||||
|
|
||||||
|
return album
|
||||||
|
}),
|
||||||
|
|
||||||
|
deleteAlbum: async (parent, { id }, { db }, info) => {
|
||||||
|
const album = await db.models.album.findByPk(id)
|
||||||
|
if (!album) throw UserInputError('Not Found')
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await createUpdateLog(db, 'deleteAlbum', album, transaction)
|
||||||
|
await album.destroy({ transaction })
|
||||||
|
return 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeResolvers(resolvers, resolversComposition)
|
||||||
12
src/graphql/resolvers/mutations/index.js
Normal file
12
src/graphql/resolvers/mutations/index.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import merge from 'lodash/merge'
|
||||||
|
|
||||||
|
import comments from './comments'
|
||||||
|
import create from './create'
|
||||||
|
import requests from './requests'
|
||||||
|
import site from './site'
|
||||||
|
import update from './update'
|
||||||
|
import user from './user'
|
||||||
|
|
||||||
|
const mutations = merge(comments, create, requests, site, update, user)
|
||||||
|
|
||||||
|
export default mutations
|
||||||
86
src/graphql/resolvers/mutations/requests.js
Normal file
86
src/graphql/resolvers/mutations/requests.js
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
import { mergeResolvers } from '@graphql-tools/merge'
|
||||||
|
|
||||||
|
import { hasRole, isAuthedApp } from '@/server/utils/resolvers'
|
||||||
|
import { getUser } from '@/next/utils/getSession'
|
||||||
|
import { requestPOST } from '@/server/utils/requests'
|
||||||
|
import { UserInputError } from '@/next/server/utils/graphQLErrors'
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Mutation: {
|
||||||
|
editRequest: async (parent, data, { db }, info) => {
|
||||||
|
const request = await db.models.request.findByPk(data.id)
|
||||||
|
if (!request) throw UserInputError('Request not found')
|
||||||
|
|
||||||
|
await db.transaction(async (transaction) => {
|
||||||
|
await request.set(data, { transaction })
|
||||||
|
|
||||||
|
if (request.changed('state')) {
|
||||||
|
switch (request.state) {
|
||||||
|
case 'complete':
|
||||||
|
await requestPOST('complete', { requestId: request.id })
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'hold':
|
||||||
|
await requestPOST('hold', {
|
||||||
|
requestId: request.id,
|
||||||
|
reason: data.reason
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await request.save({ transaction })
|
||||||
|
})
|
||||||
|
|
||||||
|
return request
|
||||||
|
},
|
||||||
|
|
||||||
|
rejectRequest: async (parent, data, { db }, info) => {
|
||||||
|
const request = await db.models.request.findByPk(data.id)
|
||||||
|
if (!request) throw UserInputError('Request not found')
|
||||||
|
|
||||||
|
await requestPOST('reject', {
|
||||||
|
requestId: request.id,
|
||||||
|
reason: data.reason
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitActions = {
|
||||||
|
Mutation: {
|
||||||
|
submitAlbum: async (parent, data, { db }, info) => {
|
||||||
|
const { request: requestId, title, vgmdb, links } = data
|
||||||
|
let request
|
||||||
|
|
||||||
|
if (requestId) {
|
||||||
|
request = await db.models.request.findByPk(requestId)
|
||||||
|
|
||||||
|
if (!request) throw UserInputError('Request not found')
|
||||||
|
if (request.state === 'complete')
|
||||||
|
throw UserInputError('Request already complete')
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await getUser(db)
|
||||||
|
|
||||||
|
return db.models.submission.create({
|
||||||
|
title,
|
||||||
|
vgmdb,
|
||||||
|
links,
|
||||||
|
requestId,
|
||||||
|
userUsername: user.username
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestResolvers = composeResolvers(resolvers, {
|
||||||
|
'Mutation.*': hasRole('REQUESTS')
|
||||||
|
})
|
||||||
|
const submitResolvers = composeResolvers(submitActions, {
|
||||||
|
'Mutation.*': [isAuthedApp]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default mergeResolvers([requestResolvers, submitResolvers])
|
||||||
37
src/graphql/resolvers/mutations/site.js
Normal file
37
src/graphql/resolvers/mutations/site.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
import { img } from '@/server/utils/image'
|
||||||
|
import { hasRole } from '@/server/utils/resolvers'
|
||||||
|
import { UserInputError } from '@/next/server/utils/graphQLErrors'
|
||||||
|
|
||||||
|
const resolversComposition = { 'Mutation.*': hasRole('UPDATE') }
|
||||||
|
const resolvers = {
|
||||||
|
Mutation: {
|
||||||
|
config: async (parent, data, { db, payload }, info) =>
|
||||||
|
db.models.config
|
||||||
|
.upsert(data)
|
||||||
|
.then(() => db.models.config.findByPk(data.name)),
|
||||||
|
|
||||||
|
uploadBanner: async (parent, { banner }, { db, payload }) => {
|
||||||
|
const timestamp = Date.now()
|
||||||
|
await img(banner, 'live', timestamp)
|
||||||
|
await db.models.config.upsert({ name: 'banner', value: timestamp })
|
||||||
|
|
||||||
|
return 1
|
||||||
|
},
|
||||||
|
|
||||||
|
selectBanner: async (parent, { name }, { db }) => {
|
||||||
|
const filePath = path.join('/var/www/soc_img/img/live', `${name}.png`)
|
||||||
|
if (!(await fs.pathExists(filePath)))
|
||||||
|
throw UserInputError(`Banner '${name}' doesnt exist`)
|
||||||
|
|
||||||
|
await db.models.config.upsert({ name: 'banner', value: name })
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeResolvers(resolvers, resolversComposition)
|
||||||
335
src/graphql/resolvers/mutations/update.js
Normal file
335
src/graphql/resolvers/mutations/update.js
Normal file
|
|
@ -0,0 +1,335 @@
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
|
||||||
|
import { createLog, createUpdateLog } from '@/server/utils/log'
|
||||||
|
import { img, getImgColor } from '@/server/utils/image'
|
||||||
|
import { hasRole } from '@/server/utils/resolvers'
|
||||||
|
import { handleComplete } from '@/server/utils/requests'
|
||||||
|
import { slugify } from '@/server/utils/slugify'
|
||||||
|
|
||||||
|
const resolversComposition = { 'Mutation.*': hasRole('UPDATE') }
|
||||||
|
const resolvers = {
|
||||||
|
Mutation: {
|
||||||
|
createPublisher: async (parent, data, { db }, info) =>
|
||||||
|
db.transaction(async (transaction) => {
|
||||||
|
const pub = await db.models.publisher.create(data, { transaction })
|
||||||
|
data.id = pub.id
|
||||||
|
|
||||||
|
await createLog(db, 'createPublisher', data, transaction)
|
||||||
|
|
||||||
|
return pub
|
||||||
|
}),
|
||||||
|
updatePublisher: async (parent, { id, name }, { db }, info) => {
|
||||||
|
const pub = await db.models.publisher.findByPk(id)
|
||||||
|
pub.name = name
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await pub.save({ transaction })
|
||||||
|
|
||||||
|
await createUpdateLog(db, 'updatePublisher', pub, transaction)
|
||||||
|
return pub
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deletePublisher: async (parent, { id }, { db }) => {
|
||||||
|
const pub = await db.models.publisher.findByPk(id)
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await pub.destroy({ transaction })
|
||||||
|
|
||||||
|
await createLog(db, 'deletePublisher', pub.dataValues, transaction)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
createPlatform: async (parent, data, { db }, info) =>
|
||||||
|
db.transaction(async (transaction) => {
|
||||||
|
const plat = db.models.platform.create(data, { transaction })
|
||||||
|
data.id = plat.id
|
||||||
|
|
||||||
|
await createLog(db, 'createPlatform', data, transaction)
|
||||||
|
return plat
|
||||||
|
}),
|
||||||
|
updatePlatform: async (parent, { key, name, type }, { db }, info) => {
|
||||||
|
const plat = await db.models.platform.findByPk(key)
|
||||||
|
if (name) plat.name = name
|
||||||
|
if (type !== plat.type) plat.type = type
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await plat.save({ transaction })
|
||||||
|
|
||||||
|
await createUpdateLog(db, 'updatePlatform', plat, transaction)
|
||||||
|
return plat
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deletePlatform: async (parent, { key }, { db }) => {
|
||||||
|
const plat = await db.models.platform.findByPk(key)
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await plat.destroy({ transaction })
|
||||||
|
await createLog(db, 'deletePlatform', plat.dataValues, transaction)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
createStudio: async (parent, data, { db }, info) =>
|
||||||
|
db.transaction(async (transaction) => {
|
||||||
|
const studio = db.models.studio.create(data, { transaction })
|
||||||
|
data.slug = studio.slug
|
||||||
|
await createLog(db, 'createStudio', data, transaction)
|
||||||
|
return studio
|
||||||
|
}),
|
||||||
|
updateStudio: async (parent, { slug, name }, { db }, info) => {
|
||||||
|
const studio = await db.models.studio.findByPk(slug)
|
||||||
|
studio.name = name
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await studio.save({ transaction })
|
||||||
|
await createUpdateLog(db, 'updateStudio', studio, transaction)
|
||||||
|
return studio
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteStudio: async (parent, { slug, name }, { db }, info) => {
|
||||||
|
const studio = await db.models.studio.findByPk(slug)
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
studio.destroy({ transaction })
|
||||||
|
await createLog(db, 'deleteStudio', studio.dataValues, transaction)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
createSeries: async (parent, data, { db }, info) =>
|
||||||
|
db.transaction(async (transaction) => {
|
||||||
|
const series = await db.models.series.create(data, { transaction })
|
||||||
|
const { slug } = series.dataValues
|
||||||
|
|
||||||
|
series.placeholder = data.cover
|
||||||
|
? await img(data.cover, 'series', slug)
|
||||||
|
: undefined
|
||||||
|
series.headerColor = data.cover
|
||||||
|
? await getImgColor(`series/${slug}`)
|
||||||
|
: undefined
|
||||||
|
await series.save({ transaction })
|
||||||
|
|
||||||
|
await createLog(db, 'createSeries', data, transaction)
|
||||||
|
return series
|
||||||
|
}),
|
||||||
|
updateSeries: async (parent, { slug, name, cover }, { db }, info) => {
|
||||||
|
const series = await db.models.series.findByPk(slug)
|
||||||
|
if (name) series.name = name
|
||||||
|
if (cover) {
|
||||||
|
series.placeholder = await img(cover, 'series', slug)
|
||||||
|
series.headerColor = await getImgColor(`series/${slug}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await series.save({ transaction })
|
||||||
|
await createUpdateLog(db, 'updateSeries', series, transaction)
|
||||||
|
return series
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteSeries: async (parent, { slug }, { db }) => {
|
||||||
|
const series = await db.models.series.findByPk(slug)
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await series.destroy({ transaction })
|
||||||
|
await createLog(db, 'deleteSeries', series.dataValues, transaction)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
createGame: async (parent, data, { db }, info) => {
|
||||||
|
const game = await db.models.game.create(data)
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await Promise.all([
|
||||||
|
game.setSeries(data.series, { transaction }),
|
||||||
|
game.setPublishers(data.publishers, { transaction }),
|
||||||
|
game.setPlatforms(data.platforms, { transaction })
|
||||||
|
])
|
||||||
|
|
||||||
|
game.placeholder = data.cover
|
||||||
|
? await img(data.cover, 'game', data.slug)
|
||||||
|
: ''
|
||||||
|
game.headerColor = data.cover
|
||||||
|
? await getImgColor(`game/${data.slug}`)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
await game.save({ transaction })
|
||||||
|
await createLog(db, 'createGame', data, transaction)
|
||||||
|
|
||||||
|
return game
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateGame: async (parent, args, { db }, info) => {
|
||||||
|
const {
|
||||||
|
slug,
|
||||||
|
name,
|
||||||
|
cover,
|
||||||
|
releaseDate,
|
||||||
|
series = [],
|
||||||
|
publishers,
|
||||||
|
platforms
|
||||||
|
} = args
|
||||||
|
const game = await db.models.game.findByPk(slug)
|
||||||
|
|
||||||
|
game.name = name
|
||||||
|
game.releaseDate = releaseDate
|
||||||
|
|
||||||
|
if (cover) {
|
||||||
|
game.placeholder = await img(cover, 'game', slug)
|
||||||
|
series.headerColor = await getImgColor(`game/${slug}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make more comprehensible log
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
game.setSeries(series, { transaction })
|
||||||
|
game.setPublishers(publishers, { transaction })
|
||||||
|
game.setPlatforms(platforms, { transaction })
|
||||||
|
await game.save({ transaction })
|
||||||
|
await createUpdateLog(db, 'updateGame', game, transaction)
|
||||||
|
|
||||||
|
return game
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteGame: async (parent, { slug }, { db }) => {
|
||||||
|
const game = await db.models.game.findByPk(slug)
|
||||||
|
const log = {
|
||||||
|
...game.dataValues,
|
||||||
|
series: await game.getSeries(),
|
||||||
|
publishers: await game.getPublishers(),
|
||||||
|
platforms: await game.getPlatforms()
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await game.destroy({ transaction })
|
||||||
|
await createLog(db, 'deleteSeries', log, transaction)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
createAnimation: async (parent, data, { db }, info) => {
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
const anim = await db.models.animation.create(data, { transaction })
|
||||||
|
await anim.setStudios(data.studios, { transaction })
|
||||||
|
|
||||||
|
anim.placeholder = data.cover
|
||||||
|
? await img(data.cover, 'anim', anim.id)
|
||||||
|
: ''
|
||||||
|
anim.headerColor = data.cover
|
||||||
|
? await getImgColor(`anim/${anim.id}`)
|
||||||
|
: undefined
|
||||||
|
await anim.save({ transaction })
|
||||||
|
|
||||||
|
await createLog(db, 'createAnimation', data, transaction)
|
||||||
|
|
||||||
|
return anim
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateAnimation: async (parent, data, { db }, info) => {
|
||||||
|
const anim = await db.models.animation.findByPk(data.id)
|
||||||
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
|
anim[key] = value
|
||||||
|
})
|
||||||
|
|
||||||
|
if (data.cover) {
|
||||||
|
anim.placeholder = await img(data.cover, 'anim', anim.id)
|
||||||
|
anim.headerColor = await getImgColor(`anim/${anim.id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
anim.setStudios(data.studios, { transaction })
|
||||||
|
|
||||||
|
await anim.save({ transaction })
|
||||||
|
await createUpdateLog(db, 'updateAnimation', anim, transaction)
|
||||||
|
return anim
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteAnimation: async (parent, { id }, { db }) => {
|
||||||
|
const anim = await db.models.animation.findByPk(id)
|
||||||
|
|
||||||
|
const log = {
|
||||||
|
...anim.dataValues,
|
||||||
|
studios: await anim.getStudios()
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await anim.destroy({ transaction })
|
||||||
|
await createLog(db, 'deleteAnim', log, transaction)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updateAlbum: async (parent, data, { db }, info) => {
|
||||||
|
try {
|
||||||
|
const album = await db.models.album.findByPk(data.id)
|
||||||
|
const triggerPost =
|
||||||
|
data.status !== album.status.repeat(1) && data.status === 'show'
|
||||||
|
data.artists = data.artists
|
||||||
|
? data.artists.map((artist) => {
|
||||||
|
return { name: artist, slug: slugify(artist) }
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
|
||||||
|
await db.transaction(async (transaction) => {
|
||||||
|
await db.models.artist.bulkCreate(data.artists, {
|
||||||
|
ignoreDuplicates: true,
|
||||||
|
transaction
|
||||||
|
})
|
||||||
|
|
||||||
|
// implement better log lol lmao
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
album.update(data, { transaction }),
|
||||||
|
album.setArtists(
|
||||||
|
data.artists.map(({ slug }) => slug),
|
||||||
|
{ transaction }
|
||||||
|
),
|
||||||
|
album.setCategories(data.categories || [], { transaction }),
|
||||||
|
album.setClassifications(data.classifications || [], {
|
||||||
|
transaction
|
||||||
|
}),
|
||||||
|
album.setPlatforms(data.platforms || [], { transaction }),
|
||||||
|
album.setGames(data.games || []),
|
||||||
|
{ transaction },
|
||||||
|
album.setRelated(data.related || [], { transaction }),
|
||||||
|
album.setAnimations(data.animations || [], { transaction }),
|
||||||
|
db.models.disc
|
||||||
|
.destroy({ where: { albumId: album.dataValues.id }, transaction })
|
||||||
|
.then(() =>
|
||||||
|
(data.discs || []).map((disc) =>
|
||||||
|
album.createDisc(disc, { transaction })
|
||||||
|
)
|
||||||
|
),
|
||||||
|
db.models.store
|
||||||
|
.destroy({ where: { albumId: album.dataValues.id }, transaction })
|
||||||
|
.then(() =>
|
||||||
|
(data.stores || []).map((store) =>
|
||||||
|
album.createStore(store, { transaction })
|
||||||
|
)
|
||||||
|
),
|
||||||
|
db.models.download
|
||||||
|
.destroy({ where: { albumId: album.dataValues.id }, transaction })
|
||||||
|
.then(() =>
|
||||||
|
(data.downloads || []).map((download) =>
|
||||||
|
album.createDownload(download, {
|
||||||
|
include: [db.models.link],
|
||||||
|
transaction
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
createUpdateLog(db, 'updateAlbum', album, transaction)
|
||||||
|
])
|
||||||
|
|
||||||
|
if (data.cover) {
|
||||||
|
album.placeholder = await img(data.cover, 'album', album.id)
|
||||||
|
album.headerColor = await getImgColor(`album/${album.id}`)
|
||||||
|
await album.save({ transaction })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (triggerPost) handleComplete(db, data, album)
|
||||||
|
|
||||||
|
return album
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
throw new Error(err.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeResolvers(resolvers, resolversComposition)
|
||||||
220
src/graphql/resolvers/mutations/user.js
Normal file
220
src/graphql/resolvers/mutations/user.js
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
import bcrypt from 'bcrypt'
|
||||||
|
import generator from 'generate-password'
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
import { DateTime } from 'luxon'
|
||||||
|
import { Op } from 'sequelize'
|
||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
import sharp from 'sharp'
|
||||||
|
|
||||||
|
import { createForgor } from '@/server/utils/forgor'
|
||||||
|
import { isAuthedApp } from '@/server/utils/resolvers'
|
||||||
|
import { processImage } from '@/server/utils/image'
|
||||||
|
import { getSession, getUser } from '@/next/utils/getSession'
|
||||||
|
import {
|
||||||
|
ForbiddenError,
|
||||||
|
UserInputError
|
||||||
|
} from '@/next/server/utils/graphQLErrors'
|
||||||
|
|
||||||
|
const resolversComposition = {
|
||||||
|
'Mutation.updateUser': [isAuthedApp]
|
||||||
|
}
|
||||||
|
|
||||||
|
const streamToString = (stream) => {
|
||||||
|
const chunks = []
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)))
|
||||||
|
stream.on('error', (err) => reject(err))
|
||||||
|
stream.on('end', () => resolve(Buffer.concat(chunks)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cropPFP(streamItem, username, imgId) {
|
||||||
|
const { createReadStream } = await streamItem
|
||||||
|
const pathString = '/var/www/soc_img/img/user'
|
||||||
|
const fullPath = path.join(pathString, `${username}_${imgId}.png`)
|
||||||
|
|
||||||
|
await fs.ensureDir(pathString)
|
||||||
|
|
||||||
|
const image = await streamToString(createReadStream())
|
||||||
|
let sharpImage = sharp(image)
|
||||||
|
const metadata = await sharpImage.metadata()
|
||||||
|
const { width, height } = metadata
|
||||||
|
|
||||||
|
if (width !== height) {
|
||||||
|
sharpImage = sharpImage.extract(
|
||||||
|
width > height
|
||||||
|
? {
|
||||||
|
left: Math.floor((width - height) / 2),
|
||||||
|
top: 0,
|
||||||
|
width: height,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
left: 0,
|
||||||
|
top: Math.floor((height - width) / 2),
|
||||||
|
width,
|
||||||
|
height: width
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
await sharpImage.resize({ width: 200, height: 200 }).png().toFile(fullPath)
|
||||||
|
|
||||||
|
return await processImage(fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Mutation: {
|
||||||
|
login: async (_, { username, password }, { db }) => {
|
||||||
|
const user = await db.models.user.findByPk(username)
|
||||||
|
if (!user) throw UserInputError()
|
||||||
|
|
||||||
|
const valid = await bcrypt.compare(password, user.password)
|
||||||
|
if (!valid) throw UserInputError()
|
||||||
|
|
||||||
|
const session = await getSession()
|
||||||
|
session.username = user.username
|
||||||
|
// Remove this when new site version is fully implemented
|
||||||
|
session.permissions = (await user.getRoles())
|
||||||
|
.map((r) => r.permissions)
|
||||||
|
.flat()
|
||||||
|
await session.save()
|
||||||
|
|
||||||
|
return 200
|
||||||
|
},
|
||||||
|
logout: async () => {
|
||||||
|
const session = await getSession()
|
||||||
|
await session.destroy()
|
||||||
|
|
||||||
|
return 200
|
||||||
|
},
|
||||||
|
registerUser: async (_, { username, email, pfp }, { db }) => {
|
||||||
|
await Promise.all([
|
||||||
|
db.models.user.findByPk(username).then((result) => {
|
||||||
|
if (result) throw UserInputError('Username already in use')
|
||||||
|
}),
|
||||||
|
db.models.user.findOne({ where: { email } }).then((result) => {
|
||||||
|
if (result) throw UserInputError('Email already in use')
|
||||||
|
})
|
||||||
|
])
|
||||||
|
|
||||||
|
const password = generator.generate({
|
||||||
|
length: 30,
|
||||||
|
numbers: true,
|
||||||
|
upercase: true,
|
||||||
|
strict: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
const user = await db.models.user.create(
|
||||||
|
{ username, email, password: await bcrypt.hash(password, 10) },
|
||||||
|
{ transaction }
|
||||||
|
)
|
||||||
|
if (pfp) {
|
||||||
|
const imgId = Date.now()
|
||||||
|
user.placeholder = await cropPFP(pfp, username, imgId)
|
||||||
|
user.imgId = imgId
|
||||||
|
} else {
|
||||||
|
user.placeholder =
|
||||||
|
'data:image/webp;base64,UklGRlQAAABXRUJQVlA4IEgAAACwAQCdASoEAAQAAUAmJZgCdAEO9p5AAPa//NFYLcn+a7b+3z7ynq/qXv+iG0yH/y1D9eBf9pqWugq9G0RnxmxwsjaA2bW8AAA='
|
||||||
|
}
|
||||||
|
|
||||||
|
await user.save({ transaction })
|
||||||
|
await createForgor(user, db, transaction)
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateUserRoles: async (
|
||||||
|
parent,
|
||||||
|
{ username, roles },
|
||||||
|
{ db, payload },
|
||||||
|
info
|
||||||
|
) => {
|
||||||
|
const user = await db.models.user.findByPk(username)
|
||||||
|
user.setRoles(roles)
|
||||||
|
await user.save()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
deleteUser: async (parent, { username }, { db, payload }, info) => {
|
||||||
|
const user = await db.models.user.findByPk(username)
|
||||||
|
if (!user) throw UserInputError('Not Found')
|
||||||
|
user.destroy()
|
||||||
|
return 1
|
||||||
|
},
|
||||||
|
|
||||||
|
createForgorLink: async (_, { key }, { db }) => {
|
||||||
|
const user = await db.models.user.findOne({
|
||||||
|
where: { [Op.or]: [{ username: key }, { email: key }] }
|
||||||
|
})
|
||||||
|
if (!user) throw UserInputError('Not Found')
|
||||||
|
|
||||||
|
await createForgor(user, db)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
updatePass: async (_, { key, pass }, { db }) => {
|
||||||
|
const row = await db.models.forgor.findByPk(key)
|
||||||
|
if (!row) throw ForbiddenError()
|
||||||
|
|
||||||
|
const now = DateTime.now()
|
||||||
|
const expires = DateTime.fromJSDate(row.expires)
|
||||||
|
|
||||||
|
if (now > expires) throw ForbiddenError()
|
||||||
|
|
||||||
|
const user = await db.models.user.findByPk(row.username)
|
||||||
|
user.password = await bcrypt.hash(pass, 10)
|
||||||
|
|
||||||
|
return db.transaction(async (transaction) => {
|
||||||
|
await user.save({ transaction })
|
||||||
|
await row.destroy({ transaction })
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateUser: async (_, { username, email, password, pfp }, { db }) => {
|
||||||
|
const user = await getUser(db)
|
||||||
|
if (username) user.username = username
|
||||||
|
if (email) user.email = email
|
||||||
|
if (password) user.password = await bcrypt.hash(password, 10)
|
||||||
|
if (pfp) {
|
||||||
|
const pathString = '/var/www/soc_img/img/user'
|
||||||
|
await fs.remove(
|
||||||
|
path.join(pathString, `${user.username}_${user.imgId}.png`)
|
||||||
|
)
|
||||||
|
|
||||||
|
const imgId = Date.now()
|
||||||
|
user.placeholder = await cropPFP(pfp, username, imgId)
|
||||||
|
user.imgId = imgId
|
||||||
|
}
|
||||||
|
|
||||||
|
await user.save()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
|
||||||
|
createRole: async (parent, args, { db, payload }) =>
|
||||||
|
db.models.role.create(args),
|
||||||
|
updateRole: async (parent, { key, name, permissions }, { db, payload }) => {
|
||||||
|
const role = await db.models.role.findByPk(key)
|
||||||
|
if (!role) throw UserInputError('Not Found')
|
||||||
|
|
||||||
|
if (role.name !== name) {
|
||||||
|
await db.query(
|
||||||
|
`UPDATE roles SET name = "${name}" WHERE name = "${key}"`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
role.permissions = permissions
|
||||||
|
|
||||||
|
await role.save()
|
||||||
|
return role
|
||||||
|
},
|
||||||
|
deleteRole: async (parent, { name }, { db, payload }) => {
|
||||||
|
const role = await db.models.role.findByPk(name)
|
||||||
|
if (!role) throw UserInputError('Not Found')
|
||||||
|
await role.destroy()
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeResolvers(resolvers, resolversComposition)
|
||||||
58
src/graphql/resolvers/queries/album.ts
Normal file
58
src/graphql/resolvers/queries/album.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { Op } from 'sequelize'
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Query: {
|
||||||
|
artists: (parent, args, { db }, info) => db.models.artist.findAll(),
|
||||||
|
platforms: (parent, args, { db }, info) => db.models.platform.findAll(),
|
||||||
|
publishers: (parent, args, { db }, info) => db.models.publisher.findAll(),
|
||||||
|
publisher: (parent, { id }, { db }, info) =>
|
||||||
|
db.models.publisher.findByPk(id),
|
||||||
|
categories: (parent, args, { db }, info) => db.models.category.findAll(),
|
||||||
|
classifications: (parent, args, { db }, info) =>
|
||||||
|
db.models.classification.findAll(),
|
||||||
|
series: (parent, args, { db }, info) => db.models.series.findAll(),
|
||||||
|
games: (parent, args, { db }, info) => db.models.game.findAll(),
|
||||||
|
game: (parent, { slug }, { db }, info) => db.models.game.findByPk(slug),
|
||||||
|
album: (_, { id }, { db }) => db.models.album.findByPk(id),
|
||||||
|
downloads: (parent, { id }, { db }) =>
|
||||||
|
db.models.download.findAll({ where: { albumId: id } }),
|
||||||
|
albums: (_, __, { db }, info) =>
|
||||||
|
db.models.album.findAll({
|
||||||
|
}),
|
||||||
|
|
||||||
|
platform: async (parent, { id }, { db }) => db.models.platform.findByPk(id),
|
||||||
|
animation: (parent, { id }, { db }) => db.models.animation.findByPk(id),
|
||||||
|
animations: (parent, args, { db }) => db.models.animation.findAll(),
|
||||||
|
studio: (parent, { slug }, { db }) => db.models.studio.findByPk(slug),
|
||||||
|
studios: (parent, { slug }, { db }) => db.models.studio.findAll(),
|
||||||
|
seriesOne: (parent, { slug }, { db }, info) =>
|
||||||
|
db.models.series.findByPk(slug),
|
||||||
|
albumCount: async (parent, params, { db }) => db.models.album.count(),
|
||||||
|
recentSeries: (parent, { limit }, { db }) =>
|
||||||
|
db.models.series.findAll({
|
||||||
|
limit,
|
||||||
|
order: [['createdAt', 'DESC']]
|
||||||
|
}),
|
||||||
|
recentPublishers: (parent, { limit }, { db }) =>
|
||||||
|
db.models.publisher.findAll({
|
||||||
|
limit,
|
||||||
|
order: [['createdAt', 'DESC']]
|
||||||
|
}),
|
||||||
|
recentPlatforms: (parent, { limit, type }, { db }) =>
|
||||||
|
db.models.platform.findAll({
|
||||||
|
limit,
|
||||||
|
order: [['createdAt', 'DESC']],
|
||||||
|
where: { type: { [Op.like]: `%${type}%` } }
|
||||||
|
}),
|
||||||
|
|
||||||
|
getRandomAlbum: async (parent, { limit = 1 }, { db }) => {
|
||||||
|
const result = await db.models.album.findAll({
|
||||||
|
order: db.random(),
|
||||||
|
limit
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resolvers
|
||||||
15
src/graphql/resolvers/queries/index.ts
Normal file
15
src/graphql/resolvers/queries/index.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import merge from 'lodash/merge'
|
||||||
|
|
||||||
|
import search from './search'
|
||||||
|
/*
|
||||||
|
import album from './album'
|
||||||
|
import requests from './requests'
|
||||||
|
|
||||||
|
import site from './site'
|
||||||
|
import user from './user'
|
||||||
|
import vgmdb from './vgmdb'
|
||||||
|
*/
|
||||||
|
|
||||||
|
const queries = merge(search/*album, requests, search, site, user, vgmdb*/)
|
||||||
|
|
||||||
|
export default queries
|
||||||
76
src/graphql/resolvers/queries/requests.js
Normal file
76
src/graphql/resolvers/queries/requests.js
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { Op, fn, col, where } from 'sequelize'
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Query: {
|
||||||
|
requests: (_, {
|
||||||
|
state = ['complete', 'hold', 'pending'],
|
||||||
|
donator = [true, false]
|
||||||
|
}, { db }) => db.models.request.findAll({ where: { state, donator } }),
|
||||||
|
request: (_, { link }, { db }) => db.models.request.findOne({ where: { link } }),
|
||||||
|
|
||||||
|
searchRequests: async (_, {
|
||||||
|
state = ['complete', 'hold', 'pending'],
|
||||||
|
donator = [true, false],
|
||||||
|
limit = 10,
|
||||||
|
page = 0,
|
||||||
|
filter
|
||||||
|
}, { db }) => {
|
||||||
|
const options = { limit, offset: limit * page }
|
||||||
|
const optionsWhere = { state, donator }
|
||||||
|
|
||||||
|
async function exactSearch () {
|
||||||
|
if (!filter) return
|
||||||
|
|
||||||
|
const results = await db.models.request.findAndCountAll({
|
||||||
|
where: {
|
||||||
|
...optionsWhere,
|
||||||
|
[Op.or]: [
|
||||||
|
{ id: filter },
|
||||||
|
{ link: filter },
|
||||||
|
{ user: filter },
|
||||||
|
{ userID: filter }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
|
||||||
|
if (results.rows.length > 0) return results
|
||||||
|
}
|
||||||
|
|
||||||
|
function looseSearch () {
|
||||||
|
return db.models.request.findAndCountAll({
|
||||||
|
where: [
|
||||||
|
optionsWhere,
|
||||||
|
where(fn('LOWER', col('title')), { [Op.like]: `%${filter || ''}%` })
|
||||||
|
],
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return await exactSearch() || looseSearch()
|
||||||
|
},
|
||||||
|
|
||||||
|
submissions: (_, args, context) => {
|
||||||
|
const { filter = '', state = ['pending'] } = args
|
||||||
|
const { db } = context
|
||||||
|
|
||||||
|
return db.models.submission.findAll({
|
||||||
|
where: {
|
||||||
|
[Op.and]: [
|
||||||
|
{ state: { [Op.in]: state } },
|
||||||
|
{
|
||||||
|
[Op.or]: [
|
||||||
|
{ id: filter },
|
||||||
|
{ vgmdb: filter },
|
||||||
|
{ userUsername: filter },
|
||||||
|
where(fn('LOWER', col('title')), { [Op.like]: `%${filter.toLowerCase()}%` })
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resolvers
|
||||||
82
src/graphql/resolvers/queries/search.ts
Normal file
82
src/graphql/resolvers/queries/search.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import Sequelize from 'sequelize'
|
||||||
|
const { Op, literal } = Sequelize
|
||||||
|
import type { Resolvers } from '@/graphql/__generated__/types.generated'
|
||||||
|
|
||||||
|
const fuzzySearch = (words: string[]) => `^${words.map(w => `(?=.*\b${w}\b)`)}.+/i`
|
||||||
|
|
||||||
|
const resolvers: Resolvers = {
|
||||||
|
Query: {
|
||||||
|
searchAlbum: (parent, args, { db }) => {
|
||||||
|
const { title, categories, limit = 10, offset = 0, order = ['createdAt'], mode = 'DESC', status = ['show'] } = args
|
||||||
|
const titleWords = title?.split(' ') || []
|
||||||
|
|
||||||
|
return db.models.album.findAndCountAll({
|
||||||
|
limit, offset,
|
||||||
|
where: {
|
||||||
|
[Op.or]: [
|
||||||
|
{ title: { [Op.regexp]: fuzzySearch(titleWords) } },
|
||||||
|
{ subTitle: { [Op.regexp]: fuzzySearch(titleWords) } }
|
||||||
|
],
|
||||||
|
status: { [Op.in]: status }
|
||||||
|
},
|
||||||
|
include: categories ? [{ model: db.models.category, where: { name: { [Op.in]: categories } } }] : [],
|
||||||
|
order: [literal('`album`.`status` = \'coming\' DESC'), ...order.map(o => [o, mode])]
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
/* searchAlbumByArtist: async (parent, { name, categories, limit, page = 0, order = ['createdAt'], mode = 'DESC', status = ['show'] }, { db }) => {
|
||||||
|
const include = [{ model: db.models.artist, where: { name: { [Op.like]: `%${name}%` } } }]
|
||||||
|
|
||||||
|
if (categories) include.push({ model: db.models.class, where: { name: { [Op.in]: categories } } })
|
||||||
|
|
||||||
|
return searchPage({ limit, page, model: 'album' }, {
|
||||||
|
where: { status: { [Op.in]: status } },
|
||||||
|
include,
|
||||||
|
order: order.map(o => [o, mode])
|
||||||
|
}, db)
|
||||||
|
},
|
||||||
|
searchAnimation: (parent, { title = '', limit, page = 0, order = 'createdAt', mode = 'DESC' }, { db }) => searchPage({ title, limit, page, model: 'animation' }, {
|
||||||
|
where: { title: { [Op.like]: `%${title}%` } },
|
||||||
|
order: [[order, mode]]
|
||||||
|
}, db),
|
||||||
|
searchStudio: (parent, { name = '', limit, page = 0, order = 'createdAt', mode = 'DESC' }, { db }) => searchPage({ name, limit, page, model: 'studio' }, {
|
||||||
|
where: { name: { [Op.like]: `%${name}%` } },
|
||||||
|
order: [[order, mode]]
|
||||||
|
}, db),
|
||||||
|
searchGame: (parent, { name = '', limit, page = 0, order = 'createdAt', mode = 'DESC' }, { db }) => searchPage({ name, limit, page, model: 'game' }, {
|
||||||
|
where: { name: { [Op.like]: `%${name}%` } },
|
||||||
|
order: [[order, mode]]
|
||||||
|
}, db),
|
||||||
|
searchSeries: (parent, { name = '', limit, page = 0, order = 'createdAt', mode = 'DESC' }, { db }) => searchPage({ name, limit, page, model: 'series' }, {
|
||||||
|
where: { name: { [Op.like]: `%${name}%` } },
|
||||||
|
order: [[order, mode]]
|
||||||
|
}, db),
|
||||||
|
searchSeriesByName: (parent, { name }, { db }) => db.models.series.findAll({
|
||||||
|
where: {
|
||||||
|
name: {
|
||||||
|
[Op.like]: `%${name}%`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
searchPublishersByName: (parent, { name }, { db }) => db.models.publisher.findAll({
|
||||||
|
where: {
|
||||||
|
name: {
|
||||||
|
[Op.like]: `%${name}%`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
searchPlatformsByName: (parent, { name, categories }, { db }) => db.models.platform.findAll({
|
||||||
|
where: {
|
||||||
|
name: {
|
||||||
|
[Op.like]: `%${name}%`
|
||||||
|
},
|
||||||
|
type: { [Op.or]: categories }
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
searchPlatformsByCategories: (parent, { categories }, { db }) => categories.length === 0
|
||||||
|
? []
|
||||||
|
: db.models.platform.findAll({ where: { type: { [Op.or]: categories } } }) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resolvers
|
||||||
36
src/graphql/resolvers/queries/site.js
Normal file
36
src/graphql/resolvers/queries/site.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import fg from 'fast-glob'
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
|
||||||
|
import { hasRole } from '@/server/utils/resolvers'
|
||||||
|
|
||||||
|
const resolversComposition = { 'Query.banners': hasRole('UPDATE') }
|
||||||
|
const resolvers = {
|
||||||
|
Query: {
|
||||||
|
config: (parent, { name }, { db }, info) => {
|
||||||
|
return db.models.config
|
||||||
|
.findOrCreate({ where: { name } })
|
||||||
|
.then(() => db.models.config.findByPk(name))
|
||||||
|
},
|
||||||
|
|
||||||
|
highlight: async (parent, args, { db }) => {
|
||||||
|
const { value } = await db.models.config.findByPk('highlight')
|
||||||
|
return db.models.album.findByPk(value)
|
||||||
|
},
|
||||||
|
|
||||||
|
banners: async (parent, args) => {
|
||||||
|
const filePaths = await fg(['/var/www/soc_img/img/live/**/*.png'])
|
||||||
|
const images = filePaths.map((f) => f.split('/').pop())
|
||||||
|
|
||||||
|
return images
|
||||||
|
},
|
||||||
|
|
||||||
|
recentComments: async (parent, { limit = 5 }, { db }) => {
|
||||||
|
return db.models.comment.findAll({
|
||||||
|
limit,
|
||||||
|
order: [['updatedAt', 'DESC']]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeResolvers(resolvers, resolversComposition)
|
||||||
33
src/graphql/resolvers/queries/user.js
Normal file
33
src/graphql/resolvers/queries/user.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { Op } from 'sequelize'
|
||||||
|
import { composeResolvers } from '@graphql-tools/resolvers-composition'
|
||||||
|
|
||||||
|
import info from '@/next/constants/info.json'
|
||||||
|
import { hasRole } from '@/server/utils/resolvers'
|
||||||
|
import { getUser } from '@/next/utils/getSession'
|
||||||
|
|
||||||
|
const { permissions } = info
|
||||||
|
|
||||||
|
const resolversComposition = { 'Query.users': hasRole('MANAGE_USER') }
|
||||||
|
const resolvers = {
|
||||||
|
Query: {
|
||||||
|
me: (parent, args, { db }) => getUser(db),
|
||||||
|
permissions: () => permissions,
|
||||||
|
roles: (parent, args, { db }) => db.models.role.findAll(),
|
||||||
|
users: (parent, args, { db }) => {
|
||||||
|
const search = args.search.trim()
|
||||||
|
if (search.length < 3) return []
|
||||||
|
|
||||||
|
return db.models.user.findAll({
|
||||||
|
where: {
|
||||||
|
[Op.or]: [
|
||||||
|
{ username: { [Op.like]: `%${search}%` } },
|
||||||
|
{ email: search }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
user: async (_, { user }, { db }) => user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default composeResolvers(resolvers, resolversComposition)
|
||||||
9
src/graphql/resolvers/queries/vgmdb.ts
Normal file
9
src/graphql/resolvers/queries/vgmdb.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import getPuppeteer from 'vgmdb-parser/lib/puppeteer'
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Query: {
|
||||||
|
vgmdb: (_, { url }) => getPuppeteer(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resolvers
|
||||||
154
src/graphql/resolvers/types/album.js
Normal file
154
src/graphql/resolvers/types/album.js
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
import { GraphQLUpload } from 'graphql-upload-minimal'
|
||||||
|
|
||||||
|
import {
|
||||||
|
checkHeaderColor,
|
||||||
|
solveRating,
|
||||||
|
checkPlaceholder
|
||||||
|
} from '@/server/utils/resolvers'
|
||||||
|
|
||||||
|
import { getUser } from '@/next/utils/getSession'
|
||||||
|
|
||||||
|
const resolvers = {
|
||||||
|
Upload: GraphQLUpload,
|
||||||
|
Album: {
|
||||||
|
artists: (parent, args, context, info) => parent.getArtists(),
|
||||||
|
categories: (parent, args, context, info) => parent.getCategories(),
|
||||||
|
classifications: (parent, args, context, info) =>
|
||||||
|
parent.getClassifications(),
|
||||||
|
platforms: (parent, args, context, info) =>
|
||||||
|
parent.getPlatforms({ order: ['name'] }),
|
||||||
|
games: (parent, args, context, info) => parent.getGames(),
|
||||||
|
discs: (parent, args, context, info) =>
|
||||||
|
parent.getDiscs({ order: [['number', 'ASC']] }),
|
||||||
|
related: (parent, args, context, info) => parent.getRelated(),
|
||||||
|
stores: (parent) => parent.getStores(),
|
||||||
|
animations: (parent) => parent.getAnimations(),
|
||||||
|
downloads: (parent) => parent.getDownloads(),
|
||||||
|
comments: (parent) => parent.getComments(),
|
||||||
|
isFavorite: async (album, _, { db }) => {
|
||||||
|
const user = await getUser(db)
|
||||||
|
return user ? album.hasUser(user.username) : null
|
||||||
|
},
|
||||||
|
selfComment: async (album, _, { db }) => {
|
||||||
|
const user = await getUser(db)
|
||||||
|
return user
|
||||||
|
? db.models.comment.findOne({
|
||||||
|
where: { albumId: album.id, username: user.username }
|
||||||
|
})
|
||||||
|
: null
|
||||||
|
},
|
||||||
|
selfScore: async (album, _, { db }) => {
|
||||||
|
const user = await getUser(db)
|
||||||
|
return user
|
||||||
|
? (
|
||||||
|
await db.models.rating.findOne({
|
||||||
|
where: { albumId: album.id, username: user.username }
|
||||||
|
})
|
||||||
|
)?.score
|
||||||
|
: null
|
||||||
|
},
|
||||||
|
favorites: (album, _, { db }) => album.countUsers(),
|
||||||
|
placeholder: (album, _, { db }) => checkPlaceholder(album, 'album'),
|
||||||
|
headerColor: (album, _, { db }) => checkHeaderColor(album, 'album'),
|
||||||
|
avgRating: async (album, _, { db }) => solveRating(album)
|
||||||
|
},
|
||||||
|
|
||||||
|
Comment: {
|
||||||
|
username: (parent) => (parent.anon ? null : parent.username),
|
||||||
|
album: (comment, _, { db }) => comment.getAlbum()
|
||||||
|
},
|
||||||
|
|
||||||
|
Category: {
|
||||||
|
albums: (parent) => parent.getAlbums(),
|
||||||
|
count: (parent, args, { db }) =>
|
||||||
|
db.models.album.count({
|
||||||
|
include: [{ model: db.models.category, where: { name: parent.name } }]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
Download: {
|
||||||
|
links: async (download) => {
|
||||||
|
const links = await download.getLinks()
|
||||||
|
const filterLinks = links.filter(
|
||||||
|
(link) => !link.url.includes('adshrink.it')
|
||||||
|
)
|
||||||
|
const outLinks = filterLinks.length === 0 ? links : filterLinks
|
||||||
|
|
||||||
|
// return outLinks.filter((link) => link.provider !== 'TERABOX')
|
||||||
|
return outLinks
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Link: {
|
||||||
|
url: async (link) => {
|
||||||
|
const download = await link.getDownload()
|
||||||
|
const links = await download.getLinks()
|
||||||
|
|
||||||
|
return links.every((link) => link.url.includes('adshrink.it'))
|
||||||
|
? link.directUrl
|
||||||
|
: link.url
|
||||||
|
},
|
||||||
|
|
||||||
|
directUrl: async (link, args, { db }) => {
|
||||||
|
const download = await link.getDownload()
|
||||||
|
const links = await download.getLinks()
|
||||||
|
|
||||||
|
const fallback = links.every((link) => link.url.includes('adshrink.it'))
|
||||||
|
if (fallback) return
|
||||||
|
|
||||||
|
const user = await getUser(db)
|
||||||
|
if (!user) return null
|
||||||
|
|
||||||
|
const roles = await user.getRoles()
|
||||||
|
const perms = roles.map((r) => r.permissions).flat()
|
||||||
|
|
||||||
|
const donator = perms.includes('DIRECT')
|
||||||
|
if (!donator) return null
|
||||||
|
|
||||||
|
return link.directUrl
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Game: {
|
||||||
|
albums: async (game, { order = [] }) => game.getAlbums({ order }),
|
||||||
|
series: (parent, args, context, info) => parent.getSeries(),
|
||||||
|
publishers: (parent, args, context, info) => parent.getPublishers(),
|
||||||
|
platforms: (parent, args, context, info) =>
|
||||||
|
parent.getPlatforms({ order: ['name'] }),
|
||||||
|
placeholder: (game, _, { db }) => checkPlaceholder(game, 'game'),
|
||||||
|
headerColor: (game, _, { db }) => checkHeaderColor(game, 'game')
|
||||||
|
},
|
||||||
|
|
||||||
|
Platform: {
|
||||||
|
albums: (parent) => parent.getAlbums(),
|
||||||
|
games: (platform, args, { db }) => platform.getGames()
|
||||||
|
},
|
||||||
|
|
||||||
|
Animation: {
|
||||||
|
studios: (parent) => parent.getStudios(),
|
||||||
|
albums: (anim, { order = [] }) => anim.getAlbums({ order }),
|
||||||
|
placeholder: (anim, _, { db }) => checkPlaceholder(anim, 'anim'),
|
||||||
|
headerColor: (anim, _, { db }) => checkPlaceholder(anim, 'anim')
|
||||||
|
},
|
||||||
|
|
||||||
|
Studio: {
|
||||||
|
animations: (studio) => studio.getAnimations()
|
||||||
|
},
|
||||||
|
|
||||||
|
Series: {
|
||||||
|
games: (parent, args, context, info) => parent.getGames(),
|
||||||
|
placeholder: (series, _, { db }) => checkPlaceholder(series, 'series'),
|
||||||
|
headerColor: (series, _, { db }) => checkPlaceholder(series, 'series')
|
||||||
|
},
|
||||||
|
|
||||||
|
Publisher: {
|
||||||
|
games: (parent, args, context, info) => parent.getGames()
|
||||||
|
},
|
||||||
|
|
||||||
|
Disc: {
|
||||||
|
album: (parent) => parent.getAlbum(),
|
||||||
|
tracks: (parent) => parent.body.split(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resolvers
|
||||||
8
src/graphql/resolvers/types/index.js
Normal file
8
src/graphql/resolvers/types/index.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import merge from 'lodash/merge'
|
||||||
|
|
||||||
|
import album from './album'
|
||||||
|
import user from './user'
|
||||||
|
|
||||||
|
const types = merge(album, user)
|
||||||
|
|
||||||
|
export default types
|
||||||
46
src/graphql/resolvers/types/user.js
Normal file
46
src/graphql/resolvers/types/user.js
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { Op } from 'sequelize'
|
||||||
|
|
||||||
|
import pages from '@/next/constants/pages.json'
|
||||||
|
import { getUser } from '@/next/utils/getSession'
|
||||||
|
|
||||||
|
const userResolvable = {
|
||||||
|
roles: parent => parent.getRoles(),
|
||||||
|
permissions: async parent => {
|
||||||
|
const roles = await parent.getRoles()
|
||||||
|
return roles.map(r => r.permissions).flat()
|
||||||
|
},
|
||||||
|
pages: async parent => {
|
||||||
|
const roles = await parent.getRoles()
|
||||||
|
const permissions = roles.map(r => r.permissions).flat()
|
||||||
|
|
||||||
|
return pages.filter(({ perms }) => perms.length === 0 || perms.some(r => permissions.includes(r)))
|
||||||
|
},
|
||||||
|
comments: (user, _, { db }) => user.getComments({ where: { albumId: { [Op.not]: null } } }),
|
||||||
|
favorites: user => user.getAlbums(),
|
||||||
|
imgUrl: async user => `https://cdn.sittingonclouds.net/user/${
|
||||||
|
user.imgId ? `${user.username}_${user.imgId}` : 'default'
|
||||||
|
}.png`
|
||||||
|
}
|
||||||
|
|
||||||
|
const funcs = {
|
||||||
|
User: userResolvable,
|
||||||
|
UserMe: userResolvable,
|
||||||
|
Role: { permissions: parent => typeof parent.permissions === 'string' || parent.permissions instanceof String ? JSON.parse(parent.permissions) : parent.permissions },
|
||||||
|
Submission: {
|
||||||
|
submitter: submission => submission.getUser(),
|
||||||
|
links: async (submission, _, { db }) => {
|
||||||
|
const user = await getUser(db)
|
||||||
|
if (!user) return null
|
||||||
|
|
||||||
|
const roles = await user.getRoles()
|
||||||
|
const perms = roles.map(r => r.permissions).flat()
|
||||||
|
|
||||||
|
if (!perms.includes('REQUESTS')) return null
|
||||||
|
|
||||||
|
return submission.links
|
||||||
|
},
|
||||||
|
request: submission => submission.getRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default funcs
|
||||||
|
|
@ -145,8 +145,8 @@ type Query {
|
||||||
searchAlbum(
|
searchAlbum(
|
||||||
title: String
|
title: String
|
||||||
categories: [String]
|
categories: [String]
|
||||||
|
offset: Int
|
||||||
limit: Int
|
limit: Int
|
||||||
page: Int
|
|
||||||
order: [String]
|
order: [String]
|
||||||
mode: String
|
mode: String
|
||||||
status: [String!]
|
status: [String!]
|
||||||
|
|
|
||||||
22
src/sequelize/index.js
Normal file
22
src/sequelize/index.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import mysql2 from 'mysql2'
|
||||||
|
import { Sequelize } from 'sequelize'
|
||||||
|
|
||||||
|
import relations from './relations'
|
||||||
|
import models from './models'
|
||||||
|
|
||||||
|
const options = process.env.GITHUB_ACTIONS
|
||||||
|
? 'sqlite::memory:'
|
||||||
|
: JSON.parse(import.meta.env.SEQUELIZE)
|
||||||
|
|
||||||
|
if (!process.env.GITHUB_ACTIONS && options.dialect === 'mysql')
|
||||||
|
options.dialectModule = mysql2
|
||||||
|
|
||||||
|
if (import.meta.env.DEV && options.logging === undefined)
|
||||||
|
options.logging = console.log
|
||||||
|
|
||||||
|
const db = new Sequelize(options)
|
||||||
|
|
||||||
|
Object.values(models).forEach((model) => model(db))
|
||||||
|
relations(db)
|
||||||
|
|
||||||
|
export default db
|
||||||
22
src/sequelize/models/album.js
Normal file
22
src/sequelize/models/album.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
import { PLACEHOLDER } from '@/constants'
|
||||||
|
|
||||||
|
const model = (sequelize) =>
|
||||||
|
sequelize.define('album', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true
|
||||||
|
},
|
||||||
|
title: DataTypes.STRING,
|
||||||
|
subTitle: DataTypes.TEXT,
|
||||||
|
releaseDate: DataTypes.DATEONLY,
|
||||||
|
label: DataTypes.STRING,
|
||||||
|
vgmdb: DataTypes.STRING,
|
||||||
|
description: DataTypes.STRING,
|
||||||
|
status: { type: DataTypes.STRING, defaultValue: 'show' },
|
||||||
|
placeholder: { type: DataTypes.TEXT, defaultValue: PLACEHOLDER },
|
||||||
|
headerColor: { type: DataTypes.STRING, defaultValue: '#ffffff' }
|
||||||
|
})
|
||||||
|
|
||||||
|
export default model
|
||||||
35
src/sequelize/models/animation.js
Normal file
35
src/sequelize/models/animation.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
import { PLACEHOLDER } from '@/constants'
|
||||||
|
|
||||||
|
const animation = (sequelize) => {
|
||||||
|
sequelize.define(
|
||||||
|
'animation',
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true
|
||||||
|
},
|
||||||
|
title: { type: DataTypes.STRING, unique: true },
|
||||||
|
subTitle: { type: DataTypes.STRING },
|
||||||
|
releaseDate: DataTypes.DATEONLY,
|
||||||
|
placeholder: { type: DataTypes.TEXT, defaultValue: PLACEHOLDER },
|
||||||
|
headerColor: { type: DataTypes.STRING, defaultValue: '#ffffff' }
|
||||||
|
},
|
||||||
|
{ freezeTableName: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
sequelize.define(
|
||||||
|
'studio',
|
||||||
|
{
|
||||||
|
slug: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: DataTypes.STRING
|
||||||
|
},
|
||||||
|
{ freezeTableName: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default animation
|
||||||
20
src/sequelize/models/artist.js
Normal file
20
src/sequelize/models/artist.js
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Artist = sequelize.define(
|
||||||
|
'artist',
|
||||||
|
{
|
||||||
|
slug: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: DataTypes.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return Artist
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
19
src/sequelize/models/category.js
Normal file
19
src/sequelize/models/category.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Category = sequelize.define(
|
||||||
|
'category',
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return Category
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
19
src/sequelize/models/classification.js
Normal file
19
src/sequelize/models/classification.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Classification = sequelize.define(
|
||||||
|
'classification',
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return Classification
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
12
src/sequelize/models/comment.js
Normal file
12
src/sequelize/models/comment.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
|
||||||
|
const model = (sequelize) => {
|
||||||
|
sequelize.define('comment', {
|
||||||
|
text: DataTypes.STRING(300),
|
||||||
|
anon: DataTypes.BOOLEAN
|
||||||
|
})
|
||||||
|
|
||||||
|
sequelize.define('rating', { score: DataTypes.INTEGER })
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
23
src/sequelize/models/config.js
Normal file
23
src/sequelize/models/config.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const config = sequelize.define(
|
||||||
|
'config',
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
defaultValue: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
11
src/sequelize/models/disc.js
Normal file
11
src/sequelize/models/disc.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Disc = sequelize.define('disc', {
|
||||||
|
number: DataTypes.INTEGER,
|
||||||
|
body: DataTypes.TEXT
|
||||||
|
})
|
||||||
|
|
||||||
|
return Disc
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
11
src/sequelize/models/download.js
Normal file
11
src/sequelize/models/download.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Download = sequelize.define('download', {
|
||||||
|
title: DataTypes.STRING,
|
||||||
|
small: DataTypes.BOOLEAN
|
||||||
|
})
|
||||||
|
|
||||||
|
return Download
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
27
src/sequelize/models/game.js
Normal file
27
src/sequelize/models/game.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
import { PLACEHOLDER } from '@/constants'
|
||||||
|
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Game = sequelize.define(
|
||||||
|
'game',
|
||||||
|
{
|
||||||
|
slug: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING
|
||||||
|
},
|
||||||
|
releaseDate: DataTypes.DATEONLY,
|
||||||
|
placeholder: { type: DataTypes.TEXT, defaultValue: PLACEHOLDER },
|
||||||
|
headerColor: { type: DataTypes.STRING, defaultValue: '#ffffff' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return Game
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
45
src/sequelize/models/index.js
Normal file
45
src/sequelize/models/index.js
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import album from './album'
|
||||||
|
import animation from './animation'
|
||||||
|
import artist from './artist'
|
||||||
|
import category from './category'
|
||||||
|
import classification from './classification'
|
||||||
|
import comment from './comment'
|
||||||
|
import config from './config'
|
||||||
|
import disc from './disc'
|
||||||
|
import download from './download'
|
||||||
|
import game from './game'
|
||||||
|
import link from './link'
|
||||||
|
import log from './log'
|
||||||
|
import platform from './platform'
|
||||||
|
import publisher from './publisher'
|
||||||
|
import request from './request'
|
||||||
|
import role from './role'
|
||||||
|
import series from './series'
|
||||||
|
import store from './store'
|
||||||
|
import submission from './submission'
|
||||||
|
import user from './user'
|
||||||
|
|
||||||
|
const models = {
|
||||||
|
album,
|
||||||
|
animation,
|
||||||
|
artist,
|
||||||
|
category,
|
||||||
|
classification,
|
||||||
|
comment,
|
||||||
|
config,
|
||||||
|
disc,
|
||||||
|
download,
|
||||||
|
game,
|
||||||
|
link,
|
||||||
|
log,
|
||||||
|
platform,
|
||||||
|
publisher,
|
||||||
|
request,
|
||||||
|
role,
|
||||||
|
series,
|
||||||
|
store,
|
||||||
|
submission,
|
||||||
|
user
|
||||||
|
}
|
||||||
|
|
||||||
|
export default models
|
||||||
13
src/sequelize/models/link.js
Normal file
13
src/sequelize/models/link.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Link = sequelize.define('link', {
|
||||||
|
url: DataTypes.STRING,
|
||||||
|
directUrl: DataTypes.STRING,
|
||||||
|
provider: DataTypes.STRING,
|
||||||
|
custom: DataTypes.STRING
|
||||||
|
})
|
||||||
|
|
||||||
|
return Link
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
17
src/sequelize/models/log.js
Normal file
17
src/sequelize/models/log.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
return sequelize.define('log', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
autoIncrement: true,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
action: DataTypes.STRING,
|
||||||
|
data: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
27
src/sequelize/models/platform.js
Normal file
27
src/sequelize/models/platform.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Platform = sequelize.define(
|
||||||
|
'platform',
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
autoIncrement: true,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
defaultValue: 'Game'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return Platform
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
23
src/sequelize/models/publisher.js
Normal file
23
src/sequelize/models/publisher.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Publisher = sequelize.define(
|
||||||
|
'publisher',
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
autoIncrement: true,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return Publisher
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
21
src/sequelize/models/request.js
Normal file
21
src/sequelize/models/request.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
|
||||||
|
const request = (sequelize) =>
|
||||||
|
sequelize.define('request', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true
|
||||||
|
},
|
||||||
|
title: DataTypes.STRING,
|
||||||
|
link: DataTypes.STRING,
|
||||||
|
user: DataTypes.STRING,
|
||||||
|
userID: DataTypes.STRING,
|
||||||
|
state: { type: DataTypes.STRING, allowNull: false },
|
||||||
|
donator: { type: DataTypes.BOOLEAN, allowNull: false },
|
||||||
|
reason: DataTypes.STRING,
|
||||||
|
comments: DataTypes.STRING,
|
||||||
|
message: DataTypes.STRING
|
||||||
|
})
|
||||||
|
|
||||||
|
export default request
|
||||||
14
src/sequelize/models/role.js
Normal file
14
src/sequelize/models/role.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Role = sequelize.define('role', {
|
||||||
|
name: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
permissions: DataTypes.JSON
|
||||||
|
})
|
||||||
|
|
||||||
|
return Role
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
24
src/sequelize/models/series.js
Normal file
24
src/sequelize/models/series.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
import { PLACEHOLDER } from '@/constants'
|
||||||
|
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Series = sequelize.define(
|
||||||
|
'series',
|
||||||
|
{
|
||||||
|
slug: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: { type: DataTypes.STRING },
|
||||||
|
placeholder: { type: DataTypes.TEXT, defaultValue: PLACEHOLDER },
|
||||||
|
headerColor: { type: DataTypes.STRING, defaultValue: '#ffffff' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
freezeTableName: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return Series
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
10
src/sequelize/models/store.js
Normal file
10
src/sequelize/models/store.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const Store = sequelize.define('store', {
|
||||||
|
url: DataTypes.STRING,
|
||||||
|
provider: DataTypes.STRING
|
||||||
|
})
|
||||||
|
return Store
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
26
src/sequelize/models/submission.js
Normal file
26
src/sequelize/models/submission.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
|
||||||
|
const model = (sequelize) =>
|
||||||
|
sequelize.define('submission', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
defaultValue: 'pending'
|
||||||
|
},
|
||||||
|
title: DataTypes.STRING,
|
||||||
|
vgmdb: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true
|
||||||
|
},
|
||||||
|
links: DataTypes.TEXT,
|
||||||
|
score: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
defaultValue: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default model
|
||||||
23
src/sequelize/models/user.js
Normal file
23
src/sequelize/models/user.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { DataTypes } from 'sequelize'
|
||||||
|
|
||||||
|
const model = (sequelize) => {
|
||||||
|
const User = sequelize.define('user', {
|
||||||
|
username: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
email: DataTypes.STRING,
|
||||||
|
password: DataTypes.STRING,
|
||||||
|
placeholder: { type: DataTypes.TEXT },
|
||||||
|
imgId: DataTypes.STRING
|
||||||
|
})
|
||||||
|
|
||||||
|
sequelize.define('forgor', {
|
||||||
|
key: { type: DataTypes.STRING, primaryKey: true },
|
||||||
|
expires: DataTypes.DATE
|
||||||
|
})
|
||||||
|
|
||||||
|
return User
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
68
src/sequelize/relations.js
Normal file
68
src/sequelize/relations.js
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
export default function relations (sequelize) {
|
||||||
|
const {
|
||||||
|
album, classification, disc, download, link,
|
||||||
|
publisher, game, series,
|
||||||
|
platform, artist, category, store,
|
||||||
|
animation, studio,
|
||||||
|
user, role, forgor, log, comment, rating,
|
||||||
|
submission, request
|
||||||
|
} = sequelize.models
|
||||||
|
|
||||||
|
user.belongsToMany(role, { through: 'User_Role' })
|
||||||
|
log.belongsTo(user, { foreignKey: 'username' })
|
||||||
|
forgor.belongsTo(user, { foreignKey: 'username' })
|
||||||
|
|
||||||
|
submission.belongsTo(user)
|
||||||
|
submission.belongsTo(request)
|
||||||
|
user.hasMany(submission)
|
||||||
|
request.hasMany(submission)
|
||||||
|
|
||||||
|
classification.belongsToMany(album, { through: 'Album_Classification' })
|
||||||
|
|
||||||
|
disc.belongsTo(album)
|
||||||
|
|
||||||
|
download.hasMany(link)
|
||||||
|
link.belongsTo(download)
|
||||||
|
|
||||||
|
game.belongsToMany(publisher, { through: 'Publisher_Game' })
|
||||||
|
game.belongsToMany(album, { through: 'Album_Game' })
|
||||||
|
game.belongsToMany(series, { through: 'Series_Game' })
|
||||||
|
|
||||||
|
game.belongsToMany(platform, { through: 'Game_Platform' })
|
||||||
|
platform.belongsToMany(game, { through: 'Game_Platform' })
|
||||||
|
|
||||||
|
album.belongsToMany(artist, { onDelete: 'SET NULL', through: 'Album_Artist' })
|
||||||
|
album.belongsToMany(classification, { onDelete: 'SET NULL', through: 'Album_Classification' })
|
||||||
|
album.belongsToMany(category, { onDelete: 'SET NULL', through: 'Album_Category' })
|
||||||
|
album.belongsToMany(platform, { onDelete: 'SET NULL', through: 'Album_Platform' })
|
||||||
|
album.belongsToMany(game, { onDelete: 'SET NULL', through: 'Album_Game' })
|
||||||
|
album.belongsToMany(animation, { through: 'Album_Animation' })
|
||||||
|
album.hasMany(disc, { onDelete: 'SET NULL' })
|
||||||
|
album.hasMany(download, { onDelete: 'SET NULL' })
|
||||||
|
album.hasMany(store, { onDelete: 'SET NULL' })
|
||||||
|
album.belongsToMany(album, { onDelete: 'SET NULL', through: 'related_album', as: 'related' })
|
||||||
|
|
||||||
|
platform.belongsToMany(album, { through: 'Album_Platform' })
|
||||||
|
|
||||||
|
publisher.belongsToMany(game, { through: 'Publisher_Game' })
|
||||||
|
|
||||||
|
series.belongsToMany(game, { through: 'Series_Game' })
|
||||||
|
|
||||||
|
animation.belongsToMany(studio, { through: 'Studio_Animation' })
|
||||||
|
studio.belongsToMany(animation, { through: 'Studio_Animation' })
|
||||||
|
|
||||||
|
animation.belongsToMany(album, { through: 'Album_Animation' })
|
||||||
|
|
||||||
|
album.hasMany(comment, { onDelete: 'SET NULL' })
|
||||||
|
comment.belongsTo(album)
|
||||||
|
user.hasMany(comment, { foreignKey: 'username' })
|
||||||
|
comment.belongsTo(user, { foreignKey: 'username' })
|
||||||
|
|
||||||
|
album.hasMany(rating)
|
||||||
|
rating.belongsTo(album)
|
||||||
|
user.hasMany(rating, { foreignKey: 'username' })
|
||||||
|
rating.belongsTo(user, { foreignKey: 'username' })
|
||||||
|
|
||||||
|
user.belongsToMany(album, { through: 'favorites', foreignKey: 'username' })
|
||||||
|
album.belongsToMany(user, { through: 'favorites' })
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue