Database Connection Update #4

Merged
humenius merged 49 commits from feature/database-connection into master 2021-02-08 03:16:51 +01:00
15 changed files with 276 additions and 181 deletions
Showing only changes of commit ceea2a7616 - Show all commits

7
backend/.env Normal file
View File

@@ -0,0 +1,7 @@
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables
# Prisma supports the native connection string format for PostgreSQL, MySQL and SQLite.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"

View File

@@ -1,6 +1,6 @@
{
"name": "backend",
"version": "0.0.1",
"name": "ts-onlinetime-ranks-backend",
"version": "0.0.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1179,15 +1179,31 @@
}
},
"@nestjs/common": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-7.1.1.tgz",
"integrity": "sha512-ZcFbHw2LEkTG9lR84ysNutHnrZPiRYjdjHM7nDCz0zXra98Cu4mKw0wOdoMmtd6WFtpVaSd9JVMXYWvHleFzmw==",
"version": "7.6.5",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-7.6.5.tgz",
"integrity": "sha512-WvBJd71ktaCRm9KTURVqn1YMyUzsOIkvezjP7WEpP9DVqQUOFVvn6/osJGZky/qL+zE4P7NBNyoXM94bpYvMwQ==",
"requires": {
"axios": "0.19.2",
"cli-color": "2.0.0",
"iterare": "1.2.0",
"tslib": "2.0.0",
"uuid": "8.0.0"
"axios": "0.21.1",
"iterare": "1.2.1",
"tslib": "2.0.3",
"uuid": "8.3.2"
},
"dependencies": {
"iterare": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz",
"integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q=="
},
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
}
}
},
"@nestjs/core": {
@@ -1351,6 +1367,41 @@
"node-fetch": "^2.3.0"
}
},
"@prisma/bar": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@prisma/bar/-/bar-0.0.1.tgz",
"integrity": "sha512-FVLhwVkbfhXlBhroWfIXMLi+3Jh9IEzYp+9z+MUUiw3ZsbcoAil7CN9/QIjHc4/TcCRyRfuSmT7qCnn4O+TjJw==",
"dev": true
},
"@prisma/cli": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/@prisma/cli/-/cli-2.14.0.tgz",
"integrity": "sha512-zKYiOGlc/Y0VVRQew0jMR2sGSFnKnNGlgY4ToB5K1JMv7jCg51w+FJe2FwTOF4uWv+0Yp2KC1b0TAP8KUbNJ3A==",
"dev": true,
"requires": {
"@prisma/bar": "^0.0.1",
"@prisma/engines": "2.14.0-28.5d491261d382a2a5ffdc71de17072b0e409f1cc1"
}
},
"@prisma/client": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-2.14.0.tgz",
"integrity": "sha512-0PiiZ2maM9OP/G5mynzftvD4DFrtibeyvZf5U7Be360mtSvgLHQhZ/CHbChb0BVeWeyJuTmAqqni98LcdVgttw==",
"requires": {
"@prisma/engines-version": "2.14.0-28.5d491261d382a2a5ffdc71de17072b0e409f1cc1"
}
},
"@prisma/engines": {
"version": "2.14.0-28.5d491261d382a2a5ffdc71de17072b0e409f1cc1",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-2.14.0-28.5d491261d382a2a5ffdc71de17072b0e409f1cc1.tgz",
"integrity": "sha512-t5/Mq0VtL7khYQtbap8myr7RwyIvmruCFxsph6oTi8QZaklmuxSp7FAC2DWBz8r/KoZFngMpmliKfDrWN7uwzQ==",
"dev": true
},
"@prisma/engines-version": {
"version": "2.14.0-28.5d491261d382a2a5ffdc71de17072b0e409f1cc1",
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-2.14.0-28.5d491261d382a2a5ffdc71de17072b0e409f1cc1.tgz",
"integrity": "sha512-Oz3yNV//9UTJ+ral5tF6Ryb/MLfOE3+2F3/bH4waTbNRDd/zXKoS3jTI3ViU8yRQ1AsOQa9/pV/kXSlxgtAh8Q=="
},
"@schematics/schematics": {
"version": "0.901.7",
"resolved": "https://registry.npmjs.org/@schematics/schematics/-/schematics-0.901.7.tgz",
@@ -2038,11 +2089,6 @@
"type-fest": "^0.11.0"
}
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@@ -2256,11 +2302,11 @@
"dev": true
},
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "1.5.10"
"follow-redirects": "^1.10.0"
}
},
"babel-jest": {
@@ -2921,19 +2967,6 @@
}
}
},
"cli-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.0.tgz",
"integrity": "sha512-a0VZ8LeraW0jTuCkuAGMNufareGHhyZU9z8OGsW0gXd1hZGi1SRuNRXdbGkraBBKnhyUhyebFWnRbp+dIn0f0A==",
"requires": {
"ansi-regex": "^2.1.1",
"d": "^1.0.1",
"es5-ext": "^0.10.51",
"es6-iterator": "^2.0.3",
"memoizee": "^0.4.14",
"timers-ext": "^0.1.7"
}
},
"cli-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -3372,15 +3405,6 @@
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
"dev": true
},
"d": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"requires": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -3405,6 +3429,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -3658,9 +3683,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"elliptic": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
"integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"dev": true,
"requires": {
"bn.js": "^4.4.0",
@@ -3778,46 +3803,6 @@
"is-symbol": "^1.0.2"
}
},
"es5-ext": {
"version": "0.10.53",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
"integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
"requires": {
"es6-iterator": "~2.0.3",
"es6-symbol": "~3.1.3",
"next-tick": "~1.0.0"
}
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
"requires": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"requires": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"es6-weak-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
"integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
"requires": {
"d": "1",
"es5-ext": "^0.10.46",
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.1"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -4201,15 +4186,6 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
"requires": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"events": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
@@ -4390,21 +4366,6 @@
}
}
},
"ext": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
"integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
"requires": {
"type": "^2.0.0"
},
"dependencies": {
"type": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz",
"integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow=="
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -4706,12 +4667,9 @@
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
}
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
},
"for-in": {
"version": "1.0.2",
@@ -5544,11 +5502,6 @@
"isobject": "^3.0.1"
}
},
"is-promise": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
@@ -7445,14 +7398,6 @@
"yallist": "^3.0.2"
}
},
"lru-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
"integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
"requires": {
"es5-ext": "~0.10.2"
}
},
"macos-release": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz",
@@ -7524,21 +7469,6 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"memoizee": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz",
"integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==",
"requires": {
"d": "1",
"es5-ext": "^0.10.45",
"es6-weak-map": "^2.0.2",
"event-emitter": "^0.3.5",
"is-promise": "^2.1",
"lru-queue": "0.1",
"next-tick": "1",
"timers-ext": "^0.1.5"
}
},
"memory-fs": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
@@ -7916,11 +7846,6 @@
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
"dev": true
},
"next-tick": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -7937,9 +7862,9 @@
}
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-int64": {
"version": "0.4.0",
@@ -9300,12 +9225,6 @@
}
}
},
"serialize-javascript": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
"dev": true
},
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
@@ -10180,22 +10099,31 @@
}
},
"terser-webpack-plugin": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
"integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
"dev": true,
"requires": {
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^2.1.2",
"serialize-javascript": "^4.0.0",
"source-map": "^0.6.1",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
},
"dependencies": {
"serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -10289,15 +10217,6 @@
"setimmediate": "^1.0.4"
}
},
"timers-ext": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
"integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
"requires": {
"es5-ext": "~0.10.46",
"next-tick": "1"
}
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -10563,11 +10482,6 @@
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",

View File

@@ -20,10 +20,11 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/common": "^7.0.0",
"@nestjs/common": "^7.6.5",
"@nestjs/core": "^7.0.0",
"@nestjs/platform-express": "^7.0.0",
"node-fetch": "^2.6.0",
"@prisma/client": "^2.14.0",
"node-fetch": "^2.6.1",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.5.4",
@@ -33,6 +34,7 @@
"@nestjs/cli": "^7.0.0",
"@nestjs/schematics": "^7.0.0",
"@nestjs/testing": "^7.0.0",
"@prisma/cli": "^2.14.0",
"@types/express": "^4.17.3",
"@types/jest": "25.1.4",
"@types/node": "^13.9.1",

1
backend/prisma/.env Normal file
View File

@@ -0,0 +1 @@
DATABASE_URL="mysql://root:lGmKgXmydCT4u2sXHk7IeM@humenius.me:13307/sinusbot?schema=sinusbot"

View File

@@ -0,0 +1,48 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = "mysql://root:lGmKgXmydCT4u2sXHk7IeM@humenius.me:13307/sinusbot?schema=sinusbot"
}
model ranks {
entry_id Int @id @default(autoincrement())
season_id Int
rank_id Int @unique
rank_name String
seasons seasons @relation(fields: [season_id], references: [season_id])
timetracker timetracker[]
@@unique([season_id, rank_id], name: "ranks_season_id_rank_id_uindex")
}
model seasons {
season_id Int @id @default(autoincrement())
start_date DateTime @default(now())
end_date DateTime?
ranks ranks[]
timetracker timetracker[]
}
model timetracker {
entry_id Int @id @default(autoincrement())
user_uid String
season_id Int
rank_id Int?
time Int
ranks ranks? @relation(fields: [rank_id], references: [rank_id])
seasons seasons @relation(fields: [season_id], references: [season_id])
user user @relation(fields: [user_uid], references: [uid])
@@unique([user_uid, season_id], name: "timetracker_user_uid_season_id_uindex")
@@index([rank_id], name: "timetracker_ranks_rank_id_fk")
@@index([season_id], name: "timetracker_seasons_season_id_fk")
}
model user {
uid String @id
name String?
timetracker timetracker[]
}

View File

@@ -0,0 +1,3 @@
export interface Predicate<T, O> {
process(input: T): O;
}

13
backend/src/api/sort.ts Normal file
View File

@@ -0,0 +1,13 @@
export class Sort {
public static descending = (a: number, b: number) => {
if (a < b) {
return 1;
}
if (a > b) {
return -1;
}
return 0;
}
}

View File

@@ -0,0 +1,11 @@
export class TimeUtil {
public static humanize = (seconds: number) => {
const d = Math.floor(seconds / (3600 * 24));
const h = Math.floor(seconds % (3600 * 24) / 3600);
const m = Math.floor(seconds % 3600 / 60);
const s = Math.floor(seconds % 60);
return `${d}d ${h}h ${m}m ${s}s`;
}
}

View File

@@ -1,5 +1,7 @@
import { Controller, Get } from '@nestjs/common';
import { Controller, Get, HttpException, HttpStatus } from '@nestjs/common';
import { AppService } from './app.service';
import { DatabaseService } from './database/database.service';
import logger from './logger/Logger';
import { TableEntry } from "./models/TableEntry";
import { SinusBotService } from "./services/sinusbot.service";
@@ -7,7 +9,8 @@ import { SinusBotService } from "./services/sinusbot.service";
export class AppController {
constructor(
private readonly appService: AppService,
private readonly sinusBotService: SinusBotService
private readonly sinusBotService: SinusBotService,
private readonly databaseService: DatabaseService
) {}
@Get()
@@ -15,8 +18,21 @@ export class AppController {
return this.appService.getHello();
}
@Get('/stats')
async getStats(): Promise<TableEntry[]> {
@Get('/stats-old')
async getStatsOld(): Promise<TableEntry[]> {
return await this.sinusBotService.fetchStats();
}
@Get('/stats')
async getStats(): Promise<TableEntry[]> {
return this.databaseService.fetchStats()
.then(value => { return value; })
.catch(err => {
logger.error(`Error occured when fetching stats.`, err);
throw new HttpException(
'Error when fetching stats. Contact administrator or try again later!',
HttpStatus.INTERNAL_SERVER_ERROR
);
});
}
}

View File

@@ -2,10 +2,11 @@ import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SinusBotService } from "./services/sinusbot.service";
import { DatabaseService } from './database/database.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService, SinusBotService],
providers: [AppService, SinusBotService, DatabaseService],
})
export class AppModule {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DatabaseService } from './database.service';
describe('DatabaseService', () => {
let service: DatabaseService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [DatabaseService],
}).compile();
service = module.get<DatabaseService>(DatabaseService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,35 @@
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import logger from 'src/logger/Logger';
import { TableEntry } from 'src/models/TableEntry';
import { TimeTrackerPredicate } from './timetracking.predicate';
@Injectable()
export class DatabaseService {
// private host = process.env.MYSQL_HOST
// private port = process.env.MYSQL_PORT
// private credentials = {
// username: process.env.MYSQL_USERNAME,
// password: process.env.MYSQL_PASSWORD
// }
// private database = process.env.MYSQL_DATABASE
constructor(
private readonly prismaClient: PrismaClient,
private readonly timetrackerPredicate: TimeTrackerPredicate
) {}
public fetchStats(): Promise<TableEntry[]> {
return new Promise((resolve, reject) => {
this.prismaClient.timetracker.findMany({
include: {
user: true,
ranks: true
}
})
.then(this.timetrackerPredicate.process)
.then(result => resolve(result))
.catch(err => reject(err));
});
}
}

View File

@@ -0,0 +1,23 @@
import { ranks, seasons, timetracker, user } from "@prisma/client";
import { Predicate } from "src/api/predicate";
import { Sort } from "src/api/sort";
import { TimeUtil } from "src/api/timeutil";
import { TableEntry } from "src/models/TableEntry";
type UserStats = timetracker & { user: user, ranks: ranks; };
export class TimeTrackerPredicate implements Predicate<UserStats[], TableEntry[]> {
process(input: UserStats[]): TableEntry[] {
return input.filter((userStats: UserStats) => userStats.time != null)
.map((userStats: UserStats) => {
return {
name: userStats.user.name,
rawTime: userStats.time,
onlineTime: TimeUtil.humanize(userStats.time),
rank: userStats.ranks.rank_name
}
})
.sort((lhs, rhs) => Sort.descending(lhs.rawTime, rhs.rawTime));
}
}

View File

@@ -65,6 +65,7 @@ export default class App extends React.Component {
<tr key={index} className={placementClassName}>
<td>{placement}</td>
<td>{entry.name}</td>
<td>{entry.rank}</td>
<td>{entry.onlineTime}</td>
</tr>
)
@@ -92,6 +93,7 @@ export default class App extends React.Component {
<tr>
<th>Placement</th>
<th>Name</th>
<th>Rank</th>
<th>Online time</th>
</tr>
</thead>

View File

@@ -1,4 +1,5 @@
export default interface TableEntry {
name: string;
rank: string;
onlineTime: string;
}