mirror of
https://github.com/spacebarchat/server.git
synced 2024-11-22 18:32:29 +01:00
✨ update util
This commit is contained in:
parent
e99008a1a5
commit
766dcc24aa
1
util/.vscode/launch.json
vendored
1
util/.vscode/launch.json
vendored
@ -18,6 +18,7 @@
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeArgs": ["--inspect-brk", "${workspaceRoot}/node_modules/jest/bin/jest.js", "--runInBand"],
|
||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"port": 9229
|
||||
|
313
util/package-lock.json
generated
313
util/package-lock.json
generated
@ -16,10 +16,11 @@
|
||||
"dot-prop": "^6.0.1",
|
||||
"env-paths": "^2.2.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lambert-server": "^1.2.8",
|
||||
"missing-native-js-functions": "^1.2.10",
|
||||
"lambert-server": "^1.2.10",
|
||||
"missing-native-js-functions": "^1.2.11",
|
||||
"node-fetch": "^2.6.1",
|
||||
"patch-package": "^6.4.7",
|
||||
"pg": "^8.7.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"sqlite3": "^5.0.2",
|
||||
"typeorm": "^0.2.37",
|
||||
@ -1765,6 +1766,14 @@
|
||||
"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
|
||||
"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
|
||||
},
|
||||
"node_modules/buffer-writer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
||||
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||
@ -6098,16 +6107,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lambert-server": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/lambert-server/-/lambert-server-1.2.8.tgz",
|
||||
"integrity": "sha512-vi/Ku/QudY+WIdGO9bc0qLfVhfuJFWXk1+etesPW1vW29sPbmevLL6IwfvCtw+/MyzRAJLOyCBfQ310a68+2QQ==",
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/lambert-server/-/lambert-server-1.2.10.tgz",
|
||||
"integrity": "sha512-BHGPmpUrRklFJHPu0vAA8NBewtEd4IX80FRpV4nX9z8kHTUYHqnYHoBeUEWoUmxAeFQvQae1Axk5RQXRQk4VNw==",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"chalk": "^4.1.1",
|
||||
"express": "^4.17.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"helmet": "^4.4.1",
|
||||
"missing-native-js-functions": "^1.1.8"
|
||||
"missing-native-js-functions": "^1.2.11"
|
||||
}
|
||||
},
|
||||
"node_modules/leven": {
|
||||
@ -6329,9 +6338,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/missing-native-js-functions": {
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/missing-native-js-functions/-/missing-native-js-functions-1.2.10.tgz",
|
||||
"integrity": "sha512-sq+oAw/C3OtUyKopLNOf/+U85YNx7db6fy5nVfGVKlGdcV8tX24GjOSkcZeCAnAIjMEnlQBWTr17JXa3OJj22g=="
|
||||
"version": "1.2.11",
|
||||
"resolved": "https://registry.npmjs.org/missing-native-js-functions/-/missing-native-js-functions-1.2.11.tgz",
|
||||
"integrity": "sha512-U97IscNBL4Wg9adYjEBT46Hb0Ld5dPT8vbdwFX+TNzGrFQCc4WqoGAZouaLNFwUqxzzHZ9DVg59unwnQyeIIQg=="
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "1.0.4",
|
||||
@ -6916,6 +6925,11 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/packet-reader": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
|
||||
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
|
||||
},
|
||||
"node_modules/parent-require": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
|
||||
@ -7065,6 +7079,80 @@
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.7.1",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz",
|
||||
"integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==",
|
||||
"dependencies": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.4.1",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pg-native": ">=2.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"pg-native": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pg-connection-string": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
|
||||
},
|
||||
"node_modules/pg-int8": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
|
||||
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-pool": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz",
|
||||
"integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==",
|
||||
"peerDependencies": {
|
||||
"pg": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-protocol": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
|
||||
},
|
||||
"node_modules/pg-types": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||
"dependencies": {
|
||||
"pg-int8": "1.0.1",
|
||||
"postgres-array": "~2.0.0",
|
||||
"postgres-bytea": "~1.0.0",
|
||||
"postgres-date": "~1.0.4",
|
||||
"postgres-interval": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pgpass": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz",
|
||||
"integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==",
|
||||
"dependencies": {
|
||||
"split2": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
@ -7088,6 +7176,41 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-bytea": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
||||
"integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-date": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-interval": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||
"dependencies": {
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
@ -7604,6 +7727,35 @@
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
|
||||
"integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
|
||||
"dependencies": {
|
||||
"readable-stream": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/split2/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/split2/node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
@ -8492,6 +8644,14 @@
|
||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
@ -10030,6 +10190,11 @@
|
||||
"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
|
||||
"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
|
||||
},
|
||||
"buffer-writer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
||||
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw=="
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||
@ -13373,16 +13538,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"lambert-server": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/lambert-server/-/lambert-server-1.2.8.tgz",
|
||||
"integrity": "sha512-vi/Ku/QudY+WIdGO9bc0qLfVhfuJFWXk1+etesPW1vW29sPbmevLL6IwfvCtw+/MyzRAJLOyCBfQ310a68+2QQ==",
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/lambert-server/-/lambert-server-1.2.10.tgz",
|
||||
"integrity": "sha512-BHGPmpUrRklFJHPu0vAA8NBewtEd4IX80FRpV4nX9z8kHTUYHqnYHoBeUEWoUmxAeFQvQae1Axk5RQXRQk4VNw==",
|
||||
"requires": {
|
||||
"body-parser": "^1.19.0",
|
||||
"chalk": "^4.1.1",
|
||||
"express": "^4.17.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"helmet": "^4.4.1",
|
||||
"missing-native-js-functions": "^1.1.8"
|
||||
"missing-native-js-functions": "^1.2.11"
|
||||
}
|
||||
},
|
||||
"leven": {
|
||||
@ -13570,9 +13735,9 @@
|
||||
}
|
||||
},
|
||||
"missing-native-js-functions": {
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/missing-native-js-functions/-/missing-native-js-functions-1.2.10.tgz",
|
||||
"integrity": "sha512-sq+oAw/C3OtUyKopLNOf/+U85YNx7db6fy5nVfGVKlGdcV8tX24GjOSkcZeCAnAIjMEnlQBWTr17JXa3OJj22g=="
|
||||
"version": "1.2.11",
|
||||
"resolved": "https://registry.npmjs.org/missing-native-js-functions/-/missing-native-js-functions-1.2.11.tgz",
|
||||
"integrity": "sha512-U97IscNBL4Wg9adYjEBT46Hb0Ld5dPT8vbdwFX+TNzGrFQCc4WqoGAZouaLNFwUqxzzHZ9DVg59unwnQyeIIQg=="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "1.0.4",
|
||||
@ -14013,6 +14178,11 @@
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"packet-reader": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
|
||||
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
|
||||
},
|
||||
"parent-require": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
|
||||
@ -14136,6 +14306,61 @@
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
||||
"optional": true
|
||||
},
|
||||
"pg": {
|
||||
"version": "8.7.1",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz",
|
||||
"integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==",
|
||||
"requires": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.4.1",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
}
|
||||
},
|
||||
"pg-connection-string": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
|
||||
},
|
||||
"pg-int8": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
|
||||
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
|
||||
},
|
||||
"pg-pool": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz",
|
||||
"integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"pg-protocol": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
|
||||
},
|
||||
"pg-types": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||
"requires": {
|
||||
"pg-int8": "1.0.1",
|
||||
"postgres-array": "~2.0.0",
|
||||
"postgres-bytea": "~1.0.0",
|
||||
"postgres-date": "~1.0.4",
|
||||
"postgres-interval": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"pgpass": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz",
|
||||
"integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==",
|
||||
"requires": {
|
||||
"split2": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
@ -14150,6 +14375,29 @@
|
||||
"node-modules-regexp": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="
|
||||
},
|
||||
"postgres-bytea": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
||||
"integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU="
|
||||
},
|
||||
"postgres-date": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="
|
||||
},
|
||||
"postgres-interval": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||
"requires": {
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
@ -14564,6 +14812,34 @@
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"split2": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
|
||||
"integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
|
||||
"requires": {
|
||||
"readable-stream": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
@ -15187,6 +15463,11 @@
|
||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||
"dev": true
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
@ -9,8 +9,7 @@
|
||||
"patch": "patch-package",
|
||||
"test": "npm run build && jest",
|
||||
"postinstall": "npm run patch && npm run build",
|
||||
"build": "npx tsc -b .",
|
||||
"generate:schema": "npx typescript-json-schema tsconfig.json '*' -o src/entities/schema.json"
|
||||
"build": "npx tsc -b ."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -44,10 +43,11 @@
|
||||
"dot-prop": "^6.0.1",
|
||||
"env-paths": "^2.2.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lambert-server": "^1.2.8",
|
||||
"missing-native-js-functions": "^1.2.10",
|
||||
"lambert-server": "^1.2.10",
|
||||
"missing-native-js-functions": "^1.2.11",
|
||||
"node-fetch": "^2.6.1",
|
||||
"patch-package": "^6.4.7",
|
||||
"pg": "^8.7.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"sqlite3": "^5.0.2",
|
||||
"typeorm": "^0.2.37",
|
||||
|
@ -8,13 +8,13 @@ export class Application extends BaseClass {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
icon?: string;
|
||||
|
||||
@Column()
|
||||
description: string;
|
||||
|
||||
@Column("simple-array")
|
||||
@Column({ type: "simple-array", nullable: true })
|
||||
rpc_origins?: string[];
|
||||
|
||||
@Column()
|
||||
@ -23,16 +23,16 @@ export class Application extends BaseClass {
|
||||
@Column()
|
||||
bot_require_code_grant: boolean;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
terms_of_service_url?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
privacy_policy_url?: string;
|
||||
|
||||
@Column()
|
||||
owner_id: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
summary?: string;
|
||||
|
||||
@Column()
|
||||
@ -52,13 +52,13 @@ export class Application extends BaseClass {
|
||||
@ManyToOne(() => Guild, (guild: Guild) => guild.id)
|
||||
guild: Guild; // if this application is a game sold, this field will be the guild to which it has been linked
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
primary_sku_id?: string; // if this application is a game sold, this field will be the id of the "Game SKU" that is created,
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
cover_image?: string; // the application's default rich presence invite cover image hash
|
||||
|
||||
@Column()
|
||||
|
@ -46,7 +46,7 @@ export class AuditLogEntry extends BaseClass {
|
||||
@RelationId((auditlog: AuditLogEntry) => auditlog.target)
|
||||
target_id: string;
|
||||
|
||||
@JoinColumn({ name: "user_id" })
|
||||
@JoinColumn({ name: "target_id" })
|
||||
@ManyToOne(() => User, (user: User) => user.id)
|
||||
target?: User;
|
||||
|
||||
@ -63,7 +63,7 @@ export class AuditLogEntry extends BaseClass {
|
||||
})
|
||||
action_type: AuditLogEvents;
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json", nullable: true })
|
||||
options?: {
|
||||
delete_member_days?: string;
|
||||
members_removed?: string;
|
||||
@ -76,10 +76,10 @@ export class AuditLogEntry extends BaseClass {
|
||||
};
|
||||
|
||||
@Column()
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
changes: AuditLogChange[];
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,6 @@ export class Ban extends BaseClass {
|
||||
@Column()
|
||||
ip: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
reason?: string;
|
||||
}
|
||||
|
@ -1,34 +1,26 @@
|
||||
import "reflect-metadata";
|
||||
import { BaseEntity, BeforeInsert, BeforeUpdate, PrimaryColumn } from "typeorm";
|
||||
import {
|
||||
BaseEntity,
|
||||
BeforeInsert,
|
||||
BeforeUpdate,
|
||||
EntityMetadata,
|
||||
FindConditions,
|
||||
FindManyOptions,
|
||||
PrimaryColumn,
|
||||
} from "typeorm";
|
||||
import { Snowflake } from "../util/Snowflake";
|
||||
import Ajv, { ValidateFunction } from "ajv";
|
||||
import schema from "./schema.json";
|
||||
import "missing-native-js-functions";
|
||||
|
||||
// TODO use class-validator https://typeorm.io/#/validation with class annotators (isPhone/isEmail) combined with types from typescript-json-schema
|
||||
// btw. we don't use class-validator for everything, because we need to explicitly set the type instead of deriving it from typescript also it doesn't easily support nested objects
|
||||
|
||||
const ajv = new Ajv({
|
||||
removeAdditional: "all",
|
||||
useDefaults: true,
|
||||
coerceTypes: true,
|
||||
// @ts-ignore
|
||||
validateFormats: false,
|
||||
allowUnionTypes: true,
|
||||
});
|
||||
|
||||
export class BaseClass extends BaseEntity {
|
||||
@PrimaryColumn()
|
||||
id: string;
|
||||
|
||||
// @ts-ignore
|
||||
constructor(props?: any, public opts: { id?: string } = {}) {
|
||||
constructor(public props?: any, public opts: { id?: string } = {}) {
|
||||
super();
|
||||
this.assign(props);
|
||||
|
||||
if (!this.construct.schema) {
|
||||
this.construct.schema = ajv.compile({ ...schema, $ref: `#/definitions/${this.construct.name}` });
|
||||
}
|
||||
|
||||
this.id = this.opts.id || Snowflake.generate();
|
||||
}
|
||||
@ -38,19 +30,20 @@ export class BaseClass extends BaseEntity {
|
||||
}
|
||||
|
||||
get metadata() {
|
||||
return this.construct.getRepository().metadata;
|
||||
return this.construct.getRepository().metadata as EntityMetadata;
|
||||
}
|
||||
|
||||
assign(props: any) {
|
||||
if (!props || typeof props !== "object") return;
|
||||
|
||||
delete props.id;
|
||||
delete props.opts;
|
||||
delete props.props;
|
||||
|
||||
const properties = new Set(this.metadata.columns.map((x: any) => x.propertyName));
|
||||
// will not include relational properties (e.g. @RelationId @ManyToMany)
|
||||
|
||||
for (const key in props) {
|
||||
if (this.hasOwnProperty(key)) continue;
|
||||
if (!properties.has(key)) continue;
|
||||
// @ts-ignore
|
||||
const setter = this[`set${key.capitalize()}`];
|
||||
@ -66,8 +59,7 @@ export class BaseClass extends BaseEntity {
|
||||
@BeforeUpdate()
|
||||
@BeforeInsert()
|
||||
validate() {
|
||||
const valid = this.construct.schema(this.toJSON());
|
||||
if (!valid) throw ajv.errors;
|
||||
this.assign(this.props);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -75,4 +67,14 @@ export class BaseClass extends BaseEntity {
|
||||
// @ts-ignore
|
||||
return Object.fromEntries(this.metadata.columns.map((x) => [x.propertyName, this[x.propertyName]]));
|
||||
}
|
||||
|
||||
static increment<T extends BaseClass>(conditions: FindConditions<T>, propertyPath: string, value: number | string) {
|
||||
const repository = this.getRepository();
|
||||
return repository.increment(conditions, propertyPath, value);
|
||||
}
|
||||
|
||||
static decrement<T extends BaseClass>(conditions: FindConditions<T>, propertyPath: string, value: number | string) {
|
||||
const repository = this.getRepository();
|
||||
return repository.decrement(conditions, propertyPath, value);
|
||||
}
|
||||
}
|
||||
|
@ -60,25 +60,25 @@ export class Channel extends BaseClass {
|
||||
@ManyToOne(() => User, (user: User) => user.id)
|
||||
owner: User;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
last_pin_timestamp?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
default_auto_archive_duration?: number;
|
||||
|
||||
@Column()
|
||||
position: number;
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
permission_overwrites: ChannelPermissionOverwrite[];
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
video_quality_mode?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
bitrate?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
user_limit?: number;
|
||||
|
||||
@Column()
|
||||
@ -87,7 +87,7 @@ export class Channel extends BaseClass {
|
||||
@Column()
|
||||
rate_limit_per_user: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
topic?: string;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { Snowflake } from "../util/Snowflake";
|
||||
|
||||
@Entity("config")
|
||||
export class ConfigEntity extends BaseClass {
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
value: ConfigValue;
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,29 @@
|
||||
import { Column, Entity } from "typeorm";
|
||||
import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { User } from "./User";
|
||||
|
||||
@Entity("connected_accounts")
|
||||
export class ConnectedAccount extends BaseClass {
|
||||
@Column()
|
||||
@RelationId((account: ConnectedAccount) => account.user)
|
||||
user_id: string;
|
||||
|
||||
@JoinColumn({ name: "user_id" })
|
||||
@ManyToOne(() => User, (user: User) => user.connected_accounts)
|
||||
user: User;
|
||||
|
||||
@Column({ select: false })
|
||||
access_token: string;
|
||||
|
||||
@Column()
|
||||
@Column({ select: false })
|
||||
friend_sync: boolean;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
@Column({ select: false })
|
||||
revoked: boolean;
|
||||
|
||||
@Column()
|
||||
@Column({ select: false })
|
||||
show_activity: boolean;
|
||||
|
||||
@Column()
|
||||
@ -24,6 +32,6 @@ export class ConnectedAccount extends BaseClass {
|
||||
@Column()
|
||||
verifie: boolean;
|
||||
|
||||
@Column()
|
||||
@Column({ select: false })
|
||||
visibility: number;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export class Emoji extends BaseClass {
|
||||
animated: boolean;
|
||||
|
||||
@Column()
|
||||
available: boolean;
|
||||
available: boolean; // whether this emoji can be used, may be false due to loss of Server Boosts
|
||||
|
||||
@Column()
|
||||
guild_id: string;
|
||||
@ -27,9 +27,6 @@ export class Emoji extends BaseClass {
|
||||
@Column()
|
||||
require_colons: boolean;
|
||||
|
||||
@Column()
|
||||
url: string;
|
||||
|
||||
@RelationId((emoji: Emoji) => emoji.roles)
|
||||
role_ids: string[];
|
||||
|
||||
|
@ -17,51 +17,51 @@ export class Guild extends BaseClass {
|
||||
@ManyToOne(() => Channel, (channel: Channel) => channel.id)
|
||||
afk_channel?: Channel;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
afk_timeout?: number;
|
||||
|
||||
// * commented out -> use owner instead
|
||||
// application id of the guild creator if it is bot-created
|
||||
// @Column()
|
||||
// @Column({ nullable: true })
|
||||
// application?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
banner?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
default_message_notifications?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
discovery_splash?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
explicit_content_filter?: number;
|
||||
|
||||
@Column("simple-array")
|
||||
@Column({ type: "simple-array" })
|
||||
features: string[];
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
icon?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
large?: boolean;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
max_members?: number; // e.g. default 100.000
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
max_presences?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
max_video_channel_users?: number; // ? default: 25, is this max 25 streaming or watching
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
member_count?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
presence_count?: number; // users online
|
||||
|
||||
@RelationId((guild: Guild) => guild.members)
|
||||
@ -99,7 +99,7 @@ export class Guild extends BaseClass {
|
||||
@ManyToMany(() => VoiceState, (voicestate: VoiceState) => voicestate.id)
|
||||
voice_states: VoiceState[];
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
mfa_level?: number;
|
||||
|
||||
@Column()
|
||||
@ -112,13 +112,13 @@ export class Guild extends BaseClass {
|
||||
@ManyToOne(() => User, (user: User) => user.id)
|
||||
owner: User;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
preferred_locale?: string; // only community guilds can choose this
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
premium_subscription_count?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
premium_tier?: number; // nitro boost level
|
||||
|
||||
@RelationId((guild: Guild) => guild.public_updates_channel)
|
||||
@ -135,10 +135,10 @@ export class Guild extends BaseClass {
|
||||
@ManyToOne(() => Channel, (channel: Channel) => channel.id)
|
||||
rules_channel?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
region?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
splash?: string;
|
||||
|
||||
@RelationId((guild: Guild) => guild.system_channel)
|
||||
@ -148,10 +148,10 @@ export class Guild extends BaseClass {
|
||||
@ManyToMany(() => Channel, (channel: Channel) => channel.id)
|
||||
system_channel?: Channel;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
system_channel_flags?: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
unavailable?: boolean;
|
||||
|
||||
@RelationId((guild: Guild) => guild.vanity_url)
|
||||
@ -161,10 +161,10 @@ export class Guild extends BaseClass {
|
||||
@OneToOne(() => Invite, (invite: Invite) => invite.code)
|
||||
vanity_url?: Invite;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
verification_level?: number;
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
welcome_screen: {
|
||||
enabled: boolean;
|
||||
description: string;
|
||||
@ -183,6 +183,6 @@ export class Guild extends BaseClass {
|
||||
@ManyToOne(() => Channel, (channel: Channel) => channel.id)
|
||||
widget_channel?: Channel;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
widget_enabled?: boolean;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
|
||||
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { Channel } from "./Channel";
|
||||
import { Guild } from "./Guild";
|
||||
@ -6,7 +6,7 @@ import { User } from "./User";
|
||||
|
||||
@Entity("invites")
|
||||
export class Invite extends BaseClass {
|
||||
@Column()
|
||||
@PrimaryColumn()
|
||||
code: string;
|
||||
|
||||
@Column()
|
||||
@ -55,6 +55,6 @@ export class Invite extends BaseClass {
|
||||
@ManyToOne(() => User, (user: User) => user.id)
|
||||
target_user?: string; // could be used for "User specific invites" https://github.com/fosscord/fosscord/issues/62
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
target_user_type?: number;
|
||||
}
|
||||
|
@ -1,7 +1,17 @@
|
||||
import { PublicUser, User } from "./User";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
|
||||
import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, RelationId } from "typeorm";
|
||||
import { Guild } from "./Guild";
|
||||
import { Config, emitEvent } from "../util";
|
||||
import {
|
||||
GuildCreateEvent,
|
||||
GuildDeleteEvent,
|
||||
GuildMemberAddEvent,
|
||||
GuildMemberRemoveEvent,
|
||||
GuildMemberUpdateEvent,
|
||||
} from "../interfaces";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { Role } from "./Role";
|
||||
|
||||
@Entity("members")
|
||||
export class Member extends BaseClass {
|
||||
@ -19,16 +29,20 @@ export class Member extends BaseClass {
|
||||
@ManyToOne(() => Guild, (guild: Guild) => guild.id)
|
||||
guild: Guild;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
nick?: string;
|
||||
|
||||
@Column("simple-array")
|
||||
roles: string[];
|
||||
@RelationId((member: Member) => member.roles)
|
||||
role_ids: string[];
|
||||
|
||||
@JoinColumn({ name: "role_ids" })
|
||||
@ManyToMany(() => Role)
|
||||
roles: Role[];
|
||||
|
||||
@Column()
|
||||
joined_at: Date;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
premium_since?: number;
|
||||
|
||||
@Column()
|
||||
@ -40,12 +54,180 @@ export class Member extends BaseClass {
|
||||
@Column()
|
||||
pending: boolean;
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
settings: UserGuildSettings;
|
||||
|
||||
// TODO: update
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
read_state: Record<string, string | null>;
|
||||
|
||||
static async IsInGuildOrFail(user_id: string, guild_id: string) {
|
||||
if (await Member.count({ id: user_id, guild_id })) return true;
|
||||
throw new HTTPError("You are not member of this guild", 403);
|
||||
}
|
||||
|
||||
static async removeFromGuild(user_id: string, guild_id: string) {
|
||||
const guild = await Guild.findOneOrFail({ select: ["owner_id"], where: { id: guild_id } });
|
||||
if (guild.owner_id === user_id) throw new Error("The owner cannot be removed of the guild");
|
||||
const member = await Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user"] });
|
||||
|
||||
// use promise all to execute all promises at the same time -> save time
|
||||
return Promise.all([
|
||||
Member.delete({
|
||||
id: user_id,
|
||||
guild_id: guild_id,
|
||||
}),
|
||||
Guild.decrement({ id: guild_id }, "member_count", -1),
|
||||
|
||||
emitEvent({
|
||||
event: "GUILD_DELETE",
|
||||
data: {
|
||||
id: guild_id,
|
||||
},
|
||||
user_id: user_id,
|
||||
} as GuildDeleteEvent),
|
||||
emitEvent({
|
||||
event: "GUILD_MEMBER_REMOVE",
|
||||
data: {
|
||||
guild_id: guild_id,
|
||||
user: member.user,
|
||||
},
|
||||
guild_id: guild_id,
|
||||
} as GuildMemberRemoveEvent),
|
||||
]);
|
||||
}
|
||||
|
||||
static async addRole(user_id: string, guild_id: string, role_id: string) {
|
||||
const [member] = await Promise.all([
|
||||
Member.findOneOrFail({
|
||||
where: { id: user_id, guild_id: guild_id },
|
||||
relations: ["user"], // we don't want to load the role objects just the ids
|
||||
}),
|
||||
await Role.findOneOrFail({ id: role_id, guild_id: guild_id }),
|
||||
]);
|
||||
member.role_ids.push(role_id);
|
||||
member.save();
|
||||
|
||||
await emitEvent({
|
||||
event: "GUILD_MEMBER_UPDATE",
|
||||
data: {
|
||||
guild_id: guild_id,
|
||||
user: member.user,
|
||||
roles: member.role_ids,
|
||||
},
|
||||
guild_id: guild_id,
|
||||
} as GuildMemberUpdateEvent);
|
||||
}
|
||||
|
||||
static async removeRole(user_id: string, guild_id: string, role_id: string) {
|
||||
const [member] = await Promise.all([
|
||||
Member.findOneOrFail({
|
||||
where: { id: user_id, guild_id: guild_id },
|
||||
relations: ["user"], // we don't want to load the role objects just the ids
|
||||
}),
|
||||
await Role.findOneOrFail({ id: role_id, guild_id: guild_id }),
|
||||
]);
|
||||
member.role_ids.remove(role_id);
|
||||
member.save();
|
||||
|
||||
await emitEvent({
|
||||
event: "GUILD_MEMBER_UPDATE",
|
||||
data: {
|
||||
guild_id: guild_id,
|
||||
user: member.user,
|
||||
roles: member.role_ids,
|
||||
},
|
||||
guild_id: guild_id,
|
||||
} as GuildMemberUpdateEvent);
|
||||
}
|
||||
|
||||
static async changeNickname(user_id: string, guild_id: string, nickname: string) {
|
||||
const member = await Member.findOneOrFail({
|
||||
where: {
|
||||
id: user_id,
|
||||
guild_id: guild_id,
|
||||
},
|
||||
relations: ["user"],
|
||||
});
|
||||
member.nick = nickname;
|
||||
|
||||
await Promise.all([
|
||||
member.save(),
|
||||
|
||||
emitEvent({
|
||||
event: "GUILD_MEMBER_UPDATE",
|
||||
data: {
|
||||
guild_id: guild_id,
|
||||
user: member.user,
|
||||
nick: nickname,
|
||||
},
|
||||
guild_id: guild_id,
|
||||
} as GuildMemberUpdateEvent),
|
||||
]);
|
||||
}
|
||||
|
||||
static async addToGuild(user_id: string, guild_id: string) {
|
||||
const user = await User.getPublicUser(user_id);
|
||||
|
||||
const { maxGuilds } = Config.get().limits.user;
|
||||
const guild_count = await Member.count({ id: user_id });
|
||||
if (guild_count >= maxGuilds) {
|
||||
throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403);
|
||||
}
|
||||
|
||||
const guild = await Guild.findOneOrFail(guild_id, {
|
||||
relations: ["channels", "emojis", "members", "roles", "stickers"],
|
||||
});
|
||||
|
||||
if (await Member.count({ id: user.id, guild_id }))
|
||||
throw new HTTPError("You are already a member of this guild", 400);
|
||||
|
||||
const member = {
|
||||
id: user_id,
|
||||
guild_id: guild_id,
|
||||
nick: undefined,
|
||||
roles: [guild_id], // @everyone role
|
||||
joined_at: new Date(),
|
||||
premium_since: undefined,
|
||||
deaf: false,
|
||||
mute: false,
|
||||
pending: false,
|
||||
};
|
||||
// @ts-ignore
|
||||
guild.joined_at = member.joined_at;
|
||||
|
||||
await Promise.all([
|
||||
new Member({
|
||||
...member,
|
||||
read_state: {},
|
||||
settings: {
|
||||
channel_overrides: [],
|
||||
message_notifications: 0,
|
||||
mobile_push: true,
|
||||
mute_config: null,
|
||||
muted: false,
|
||||
suppress_everyone: false,
|
||||
suppress_roles: false,
|
||||
version: 0,
|
||||
},
|
||||
}).save(),
|
||||
Guild.increment({ id: guild_id }, "member_count", 1),
|
||||
emitEvent({
|
||||
event: "GUILD_MEMBER_ADD",
|
||||
data: {
|
||||
...member,
|
||||
user,
|
||||
guild_id: guild_id,
|
||||
},
|
||||
guild_id: guild_id,
|
||||
} as GuildMemberAddEvent),
|
||||
emitEvent({
|
||||
event: "GUILD_CREATE",
|
||||
data: guild,
|
||||
user_id,
|
||||
} as GuildCreateEvent),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserGuildSettings {
|
||||
@ -69,19 +251,31 @@ export interface MuteConfig {
|
||||
selected_time_window: number;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
export interface PublicMember extends Omit<Member, "settings" | "id" | "read_state"> {
|
||||
user: PublicUser;
|
||||
}
|
||||
export type PublicMemberKeys =
|
||||
| "id"
|
||||
| "guild_id"
|
||||
| "nick"
|
||||
| "roles"
|
||||
| "joined_at"
|
||||
| "pending"
|
||||
| "deaf"
|
||||
| "mute"
|
||||
| "premium_since";
|
||||
|
||||
export const PublicMemberProjection = {
|
||||
id: true,
|
||||
guild_id: true,
|
||||
nick: true,
|
||||
roles: true,
|
||||
joined_at: true,
|
||||
pending: true,
|
||||
deaf: true,
|
||||
mute: true,
|
||||
premium_since: true,
|
||||
export const PublicMemberProjection: PublicMemberKeys[] = [
|
||||
"id",
|
||||
"guild_id",
|
||||
"nick",
|
||||
"roles",
|
||||
"joined_at",
|
||||
"pending",
|
||||
"deaf",
|
||||
"mute",
|
||||
"premium_since",
|
||||
];
|
||||
|
||||
// @ts-ignore
|
||||
export type PublicMember = Pick<Member, Omit<PublicMemberKeys, "roles">> & {
|
||||
user: PublicUser;
|
||||
roles: string[]; // only role ids not objects
|
||||
};
|
||||
|
@ -17,6 +17,7 @@ import {
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { Guild } from "./Guild";
|
||||
import { Webhook } from "./Webhook";
|
||||
import { Sticker } from "./Sticker";
|
||||
|
||||
export enum MessageType {
|
||||
DEFAULT = 0,
|
||||
@ -51,7 +52,7 @@ export class Message extends BaseClass {
|
||||
channel: Channel;
|
||||
|
||||
@RelationId((message: Message) => message.guild)
|
||||
guild_id: string;
|
||||
guild_id?: string;
|
||||
|
||||
@JoinColumn({ name: "guild_id" })
|
||||
@ManyToOne(() => Guild, (guild: Guild) => guild.id)
|
||||
@ -85,7 +86,7 @@ export class Message extends BaseClass {
|
||||
@ManyToOne(() => Application, (application: Application) => application.id)
|
||||
application?: Application;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
content?: string;
|
||||
|
||||
@Column()
|
||||
@ -96,18 +97,18 @@ export class Message extends BaseClass {
|
||||
@UpdateDateColumn()
|
||||
edited_timestamp?: Date;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
tts?: boolean;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
mention_everyone?: boolean;
|
||||
|
||||
@RelationId((message: Message) => message.mention_users)
|
||||
@RelationId((message: Message) => message.mentions)
|
||||
mention_user_ids: string[];
|
||||
|
||||
@JoinColumn({ name: "mention_user_ids" })
|
||||
@ManyToMany(() => User, (user: User) => user.id)
|
||||
mention_users: User[];
|
||||
mentions: User[];
|
||||
|
||||
@RelationId((message: Message) => message.mention_roles)
|
||||
mention_role_ids: string[];
|
||||
@ -123,44 +124,52 @@ export class Message extends BaseClass {
|
||||
@ManyToMany(() => Channel, (channel: Channel) => channel.id)
|
||||
mention_channels: Channel[];
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
attachments: Attachment[];
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
embeds: Embed[];
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
reactions: Reaction[];
|
||||
|
||||
@Column({ type: "text" })
|
||||
@Column({ type: "text", nullable: true })
|
||||
nonce?: string | number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
pinned?: boolean;
|
||||
|
||||
@Column({ type: "simple-enum", enum: MessageType })
|
||||
type: MessageType;
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json", nullable: true })
|
||||
activity?: {
|
||||
type: number;
|
||||
party_id: string;
|
||||
};
|
||||
|
||||
@Column({ type: "bigint" })
|
||||
@Column({ type: "bigint", nullable: true })
|
||||
flags?: bigint;
|
||||
|
||||
@Column("simple-json")
|
||||
stickers?: any[];
|
||||
@RelationId((message: Message) => message.stickers)
|
||||
sticker_ids: string[];
|
||||
|
||||
@Column("simple-json")
|
||||
@JoinColumn({ name: "sticker_ids" })
|
||||
@ManyToMany(() => Sticker, (sticker: Sticker) => sticker.id)
|
||||
stickers?: Sticker[];
|
||||
|
||||
@Column({ type: "simple-json", nullable: true })
|
||||
message_reference?: {
|
||||
message_id: string;
|
||||
channel_id?: string;
|
||||
guild_id?: string;
|
||||
};
|
||||
|
||||
@Column("simple-json")
|
||||
@JoinColumn({ name: "message_reference_id" })
|
||||
@ManyToOne(() => Message, (message: Message) => message.id)
|
||||
referenced_message?: Message;
|
||||
|
||||
@Column({ type: "simple-json", nullable: true })
|
||||
interaction?: {
|
||||
id: string;
|
||||
type: InteractionType;
|
||||
@ -169,7 +178,7 @@ export class Message extends BaseClass {
|
||||
// user: User; // TODO: autopopulate user
|
||||
};
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
components: MessageComponent[];
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ export class ReadState extends BaseClass {
|
||||
@ManyToOne(() => Message, (message: Message) => message.id)
|
||||
last_message?: Message;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
last_pin_timestamp?: Date;
|
||||
|
||||
@Column()
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
|
||||
import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { User } from "./User";
|
||||
|
||||
@ -15,10 +15,10 @@ export class Relationship extends BaseClass {
|
||||
user_id: string;
|
||||
|
||||
@JoinColumn({ name: "user_id" })
|
||||
@ManyToOne(() => User, (user: User) => user.id)
|
||||
@ManyToOne(() => User, (user: User) => user.relationships)
|
||||
user: User;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
nickname?: string;
|
||||
|
||||
@Column({ type: "simple-enum", enum: RelationshipType })
|
||||
|
@ -32,7 +32,7 @@ export class Role extends BaseClass {
|
||||
@Column()
|
||||
position: number;
|
||||
|
||||
@Column({ type: "simple-json" })
|
||||
@Column({ type: "simple-json", nullable: true })
|
||||
tags?: {
|
||||
bot_id?: string;
|
||||
integration_id?: string;
|
||||
|
42
util/src/entities/Sticker.ts
Normal file
42
util/src/entities/Sticker.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { Guild } from "./Guild";
|
||||
|
||||
export enum StickerType {
|
||||
STANDARD = 1,
|
||||
GUILD = 2,
|
||||
}
|
||||
|
||||
export enum StickerFormatType {
|
||||
PNG = 1,
|
||||
APNG = 2,
|
||||
LOTTIE = 3,
|
||||
}
|
||||
|
||||
@Entity("stickers")
|
||||
export class Sticker extends BaseClass {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@Column()
|
||||
tags: string;
|
||||
|
||||
@Column()
|
||||
pack_id: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
guild_id?: string;
|
||||
|
||||
@JoinColumn({ name: "guild_id" })
|
||||
@ManyToOne(() => Guild, (guild: Guild) => guild.id)
|
||||
guild?: Guild;
|
||||
|
||||
@Column({ type: "simple-enum", enum: StickerType })
|
||||
type: StickerType;
|
||||
|
||||
@Column({ type: "simple-enum", enum: StickerFormatType })
|
||||
format_type: StickerFormatType;
|
||||
}
|
@ -5,7 +5,7 @@ import { User } from "./User";
|
||||
|
||||
@Entity("teams")
|
||||
export class Team extends BaseClass {
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
icon?: string;
|
||||
|
||||
@RelationId((team: Team) => team.members)
|
||||
|
@ -12,7 +12,7 @@ export class TeamMember extends BaseClass {
|
||||
@Column({ type: "simple-enum", enum: TeamMemberState })
|
||||
membership_state: TeamMemberState;
|
||||
|
||||
@Column("simple-array")
|
||||
@Column({ type: "simple-array" })
|
||||
permissions: string[];
|
||||
|
||||
@RelationId((member: TeamMember) => member.team)
|
||||
|
@ -11,10 +11,10 @@ export class Template extends BaseClass {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
usage_count?: number;
|
||||
|
||||
@RelationId((template: Template) => template.creator)
|
||||
@ -37,6 +37,6 @@ export class Template extends BaseClass {
|
||||
@ManyToOne(() => Guild, (guild: Guild) => guild.id)
|
||||
source_guild: Guild;
|
||||
|
||||
@Column("simple-json")
|
||||
@Column({ type: "simple-json" })
|
||||
serialized_source_guild: Guild;
|
||||
}
|
||||
|
@ -1,22 +1,34 @@
|
||||
import { Column, Entity, JoinColumn, OneToMany, RelationId } from "typeorm";
|
||||
import { Column, Entity, FindOneOptions, JoinColumn, OneToMany, RelationId } from "typeorm";
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { BitField } from "../util/BitField";
|
||||
import { Relationship } from "./Relationship";
|
||||
import { ConnectedAccount } from "./ConnectedAccount";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { Guild } from "./Guild";
|
||||
|
||||
export const PublicUserProjection = {
|
||||
username: true,
|
||||
discriminator: true,
|
||||
id: true,
|
||||
public_flags: true,
|
||||
avatar: true,
|
||||
accent_color: true,
|
||||
banner: true,
|
||||
bio: true,
|
||||
bot: true,
|
||||
};
|
||||
type PublicUserKeys =
|
||||
| "username"
|
||||
| "discriminator"
|
||||
| "id"
|
||||
| "public_flags"
|
||||
| "avatar"
|
||||
| "accent_color"
|
||||
| "banner"
|
||||
| "bio"
|
||||
| "bot";
|
||||
export const PublicUserProjection: PublicUserKeys[] = [
|
||||
"username",
|
||||
"discriminator",
|
||||
"id",
|
||||
"public_flags",
|
||||
"avatar",
|
||||
"accent_color",
|
||||
"banner",
|
||||
"bio",
|
||||
"bot",
|
||||
];
|
||||
|
||||
// Private user data that should never get sent to the client
|
||||
export type PublicUser = Pick<User, PublicUserKeys>;
|
||||
|
||||
@Entity("users")
|
||||
export class User extends BaseClass {
|
||||
@ -30,115 +42,145 @@ export class User extends BaseClass {
|
||||
const number = Number(val);
|
||||
if (isNaN(number)) throw new Error("invalid discriminator");
|
||||
if (number <= 0 || number > 10000) throw new Error("discriminator must be between 1 and 9999");
|
||||
this.discriminator = val.toString();
|
||||
this.discriminator = val.toString().padStart(4, "0");
|
||||
}
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
avatar?: string; // hash of the user avatar
|
||||
|
||||
@Column()
|
||||
accent_color?: number; // banner color of user
|
||||
@Column({ nullable: true })
|
||||
accent_color?: number = 0; // banner color of user
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
banner?: string; // hash of the user banner
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
phone?: string; // phone number of the user
|
||||
|
||||
@Column()
|
||||
desktop: boolean; // if the user has desktop app installed
|
||||
desktop: boolean = false; // if the user has desktop app installed
|
||||
|
||||
@Column()
|
||||
mobile: boolean; // if the user has mobile app installed
|
||||
mobile: boolean = false; // if the user has mobile app installed
|
||||
|
||||
@Column()
|
||||
premium: boolean; // if user bought nitro
|
||||
premium: boolean = false; // if user bought nitro
|
||||
|
||||
@Column()
|
||||
premium_type: number; // nitro level
|
||||
premium_type: number = 0; // nitro level
|
||||
|
||||
@Column()
|
||||
bot: boolean; // if user is bot
|
||||
bot: boolean = false; // if user is bot
|
||||
|
||||
@Column()
|
||||
bio: string; // short description of the user (max 190 chars -> should be configurable)
|
||||
bio: string = ""; // short description of the user (max 190 chars -> should be configurable)
|
||||
|
||||
@Column()
|
||||
system: boolean; // shouldn't be used, the api sents this field type true, if the generated message comes from a system generated author
|
||||
system: boolean = false; // shouldn't be used, the api sents this field type true, if the generated message comes from a system generated author
|
||||
|
||||
@Column()
|
||||
nsfw_allowed: boolean; // if the user is older than 18 (resp. Config)
|
||||
nsfw_allowed: boolean = false; // if the user is older than 18 (resp. Config)
|
||||
|
||||
@Column()
|
||||
mfa_enabled: boolean; // if multi factor authentication is enabled
|
||||
mfa_enabled: boolean = false; // if multi factor authentication is enabled
|
||||
|
||||
@Column()
|
||||
created_at: Date; // registration date
|
||||
created_at: Date = new Date(); // registration date
|
||||
|
||||
@Column()
|
||||
verified: boolean; // if the user is offically verified
|
||||
verified: boolean = false; // if the user is offically verified
|
||||
|
||||
@Column()
|
||||
disabled: boolean; // if the account is disabled
|
||||
disabled: boolean = false; // if the account is disabled
|
||||
|
||||
@Column()
|
||||
deleted: boolean; // if the user was deleted
|
||||
deleted: boolean = false; // if the user was deleted
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
email?: string; // email of the user
|
||||
|
||||
@Column({ type: "bigint" })
|
||||
flags: bigint; // UserFlags
|
||||
flags: bigint = BigInt(0); // UserFlags
|
||||
|
||||
@Column({ type: "bigint" })
|
||||
public_flags: bigint;
|
||||
|
||||
@RelationId((user: User) => user.guilds)
|
||||
guild_ids: string[]; // array of guild ids the user is part of
|
||||
|
||||
@JoinColumn({ name: "guild_ids" })
|
||||
@OneToMany(() => Guild, (guild: Guild) => guild.id)
|
||||
guilds: Guild[];
|
||||
public_flags: bigint = BigInt(0);
|
||||
|
||||
@RelationId((user: User) => user.relationships)
|
||||
relationship_ids: string[]; // array of guild ids the user is part of
|
||||
|
||||
@JoinColumn({ name: "relationship_ids" })
|
||||
@OneToMany(() => User, (user: User) => user.id)
|
||||
@OneToMany(() => Relationship, (relationship: Relationship) => relationship.user, { cascade: true })
|
||||
relationships: Relationship[];
|
||||
|
||||
@RelationId((user: User) => user.connected_accounts)
|
||||
connected_account_ids: string[]; // array of guild ids the user is part of
|
||||
|
||||
@JoinColumn({ name: "connected_account_ids" })
|
||||
@OneToMany(() => ConnectedAccount, (account: ConnectedAccount) => account.id)
|
||||
@OneToMany(() => ConnectedAccount, (account: ConnectedAccount) => account.user)
|
||||
connected_accounts: ConnectedAccount[];
|
||||
|
||||
@Column({ type: "simple-json", select: false })
|
||||
data: {
|
||||
valid_tokens_since: Date; // all tokens with a previous issue date are invalid
|
||||
hash: string; // hash of the password, salt is saved in password (bcrypt)
|
||||
};
|
||||
hash?: string; // hash of the password, salt is saved in password (bcrypt)
|
||||
} = { valid_tokens_since: new Date() };
|
||||
|
||||
@Column({ type: "simple-array" })
|
||||
fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts
|
||||
fingerprints: string[] = []; // array of fingerprints -> used to prevent multiple accounts
|
||||
|
||||
@Column("simple-json")
|
||||
settings: UserSettings;
|
||||
@Column({ type: "simple-json" })
|
||||
settings: UserSettings = defaultSettings;
|
||||
|
||||
static async getPublicUser(user_id: string, additional_fields?: any) {
|
||||
const user = await User.findOne(
|
||||
{ id: user_id },
|
||||
{
|
||||
...PublicUserProjection,
|
||||
...additional_fields,
|
||||
}
|
||||
);
|
||||
static async getPublicUser(user_id: string, opts?: FindOneOptions<User>) {
|
||||
const user = await User.findOne(user_id, {
|
||||
...opts,
|
||||
select: [...PublicUserProjection, ...(opts?.select || [])],
|
||||
});
|
||||
if (!user) throw new HTTPError("User not found", 404);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
export const defaultSettings: UserSettings = {
|
||||
afk_timeout: 300,
|
||||
allow_accessibility_detection: true,
|
||||
animate_emoji: true,
|
||||
animate_stickers: 0,
|
||||
contact_sync_enabled: false,
|
||||
convert_emoticons: false,
|
||||
custom_status: {
|
||||
emoji_id: undefined,
|
||||
emoji_name: undefined,
|
||||
expires_at: undefined,
|
||||
text: undefined,
|
||||
},
|
||||
default_guilds_restricted: false,
|
||||
detect_platform_accounts: true,
|
||||
developer_mode: false,
|
||||
disable_games_tab: false,
|
||||
enable_tts_command: true,
|
||||
explicit_content_filter: 0,
|
||||
friend_source_flags: { all: true },
|
||||
gateway_connected: false,
|
||||
gif_auto_play: true,
|
||||
guild_folders: [],
|
||||
guild_positions: [],
|
||||
inline_attachment_media: true,
|
||||
inline_embed_media: true,
|
||||
locale: "en",
|
||||
message_display_compact: false,
|
||||
native_phone_integration_enabled: true,
|
||||
render_embeds: true,
|
||||
render_reactions: true,
|
||||
restricted_guilds: [],
|
||||
show_current_game: true,
|
||||
status: "offline",
|
||||
stream_notifications_enabled: true,
|
||||
theme: "dark",
|
||||
timezone_offset: 0,
|
||||
// timezone_offset: // TODO: timezone from request
|
||||
};
|
||||
|
||||
export interface UserSettings {
|
||||
afk_timeout: number;
|
||||
allow_accessibility_detection: boolean;
|
||||
@ -184,18 +226,6 @@ export interface UserSettings {
|
||||
timezone_offset: number; // e.g -60
|
||||
}
|
||||
|
||||
// Private user data that should never get sent to the client
|
||||
export interface PublicUser {
|
||||
id: string;
|
||||
discriminator: string;
|
||||
username: string;
|
||||
avatar?: string;
|
||||
accent_color?: number;
|
||||
banner?: string;
|
||||
public_flags: bigint;
|
||||
bot: boolean;
|
||||
}
|
||||
|
||||
export class UserFlags extends BitField {
|
||||
static FLAGS = {
|
||||
DISCORD_EMPLOYEE: BigInt(1) << BigInt(0),
|
||||
|
@ -42,7 +42,7 @@ export class VoiceState extends BaseClass {
|
||||
@Column()
|
||||
self_mute: boolean;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
self_stream?: boolean;
|
||||
|
||||
@Column()
|
||||
|
@ -18,13 +18,13 @@ export class Webhook extends BaseClass {
|
||||
@Column({ type: "simple-enum", enum: WebhookType })
|
||||
type: WebhookType;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
name?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
avatar?: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
token?: string;
|
||||
|
||||
@RelationId((webhook: Webhook) => webhook.guild)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -259,22 +259,14 @@ export interface InviteDeleteEvent extends Event {
|
||||
};
|
||||
}
|
||||
|
||||
export type MessagePayload = Omit<Message, "author_id"> & {
|
||||
channel_id: string;
|
||||
guild_id?: string;
|
||||
author: PublicUser;
|
||||
member: PublicMember;
|
||||
mentions: (PublicUser & { member: PublicMember })[];
|
||||
};
|
||||
|
||||
export interface MessageCreateEvent extends Event {
|
||||
event: "MESSAGE_CREATE";
|
||||
data: MessagePayload;
|
||||
data: Message;
|
||||
}
|
||||
|
||||
export interface MessageUpdateEvent extends Event {
|
||||
event: "MESSAGE_UPDATE";
|
||||
data: MessagePayload;
|
||||
data: Message;
|
||||
}
|
||||
|
||||
export interface MessageDeleteEvent extends Event {
|
||||
|
19
util/src/tes.ts
Normal file
19
util/src/tes.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { performance } from "perf_hooks";
|
||||
import { Guild, Relationship, RelationshipType } from "./entities";
|
||||
import { User } from "./entities/User";
|
||||
import { initDatabase } from "./util";
|
||||
|
||||
initDatabase().then(async (x) => {
|
||||
try {
|
||||
const user = await new User(
|
||||
{ guilds: [], discriminator: "1", username: "test", flags: "0", public_flags: "0" },
|
||||
{ id: "0" }
|
||||
).save();
|
||||
|
||||
user.relationships = [new Relationship({ type: RelationshipType.friends })];
|
||||
|
||||
user.save();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
@ -40,6 +40,7 @@ export function enableAutoUpdate(opts: {
|
||||
console.log(`[Auto update] updating ...`);
|
||||
download(opts.downloadUrl, opts.path);
|
||||
} else {
|
||||
console.log(`[Auto update] aborted`);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -14,11 +14,17 @@ export function initDatabase() {
|
||||
console.log("[Database] connecting ...");
|
||||
// @ts-ignore
|
||||
promise = createConnection({
|
||||
type: "sqlite",
|
||||
database: "database.db",
|
||||
// type: "sqlite",
|
||||
// database: "database.db",
|
||||
type: "postgres",
|
||||
url: "postgres://fosscord:wb94SmuURM2Syv&@localhost/fosscord",
|
||||
//
|
||||
entities: Object.values(Models).filter((x) => x.constructor.name !== "Object"),
|
||||
synchronize: true,
|
||||
logging: false,
|
||||
logging: true,
|
||||
cache: {
|
||||
duration: 1000 * 3, // cache all find queries for 3 seconds
|
||||
},
|
||||
});
|
||||
|
||||
promise.then((connection) => {
|
||||
|
@ -198,50 +198,41 @@ export class Permissions extends BitField {
|
||||
}
|
||||
|
||||
export type PermissionCache = {
|
||||
channel?: Channel | null;
|
||||
member?: Member | null;
|
||||
guild?: Guild | null;
|
||||
roles?: Role[] | null;
|
||||
channel?: Channel | undefined;
|
||||
member?: Member | undefined;
|
||||
guild?: Guild | undefined;
|
||||
roles?: Role[] | undefined;
|
||||
user_id?: string;
|
||||
};
|
||||
|
||||
export async function getPermission(
|
||||
user_id?: string,
|
||||
guild_id?: string,
|
||||
channel_id?: string,
|
||||
cache: PermissionCache = {}
|
||||
) {
|
||||
var { channel, member, guild, roles } = cache;
|
||||
|
||||
export async function getPermission(user_id?: string, guild_id?: string, channel_id?: string) {
|
||||
if (!user_id) throw new HTTPError("User not found");
|
||||
var channel: Channel | undefined;
|
||||
var member: Member | undefined;
|
||||
var guild: Guild | undefined;
|
||||
|
||||
if (channel_id && !channel) {
|
||||
if (channel_id) {
|
||||
channel = await Channel.findOneOrFail(
|
||||
{ id: channel_id },
|
||||
{ select: ["permission_overwrites", "recipients", "owner", "guild"] }
|
||||
);
|
||||
if (!channel) throw new HTTPError("Channel not found", 404);
|
||||
if (channel.guild_id) guild_id = channel.guild_id;
|
||||
if (channel.guild_id) guild_id = channel.guild_id; // derive guild_id from the channel
|
||||
}
|
||||
|
||||
if (guild_id) {
|
||||
if (!guild) guild = await Guild.findOneOrFail({ id: guild_id }, { select: ["owner"] });
|
||||
if (!guild) throw new HTTPError("Guild not found");
|
||||
guild = await Guild.findOneOrFail({ id: guild_id }, { select: ["owner"] });
|
||||
if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR);
|
||||
|
||||
if (!member) member = await Member.findOneOrFail({ guild_id, id: user_id }, { select: ["roles"] });
|
||||
if (!member) throw new HTTPError("Member not found");
|
||||
|
||||
if (!roles) roles = await Role.find({ guild_id, id: In(member.roles) });
|
||||
member = await Member.findOneOrFail({ guild_id, id: user_id }, { select: ["roles"] });
|
||||
}
|
||||
|
||||
var permission = Permissions.finalPermission({
|
||||
user: {
|
||||
id: user_id,
|
||||
roles: member?.roles || [],
|
||||
roles: member?.role_ids || [],
|
||||
},
|
||||
guild: {
|
||||
roles: roles || [],
|
||||
roles: member?.roles || [],
|
||||
},
|
||||
channel: {
|
||||
overwrites: channel?.permission_overwrites,
|
||||
@ -253,7 +244,7 @@ export async function getPermission(
|
||||
const obj = new Permissions(permission);
|
||||
|
||||
// pass cache to permission for possible future getPermission calls
|
||||
obj.cache = { guild, member, channel, roles, user_id };
|
||||
obj.cache = { guild, member, channel, roles: member?.roles, user_id };
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
const { initDatabase, closeDatabase } = require("../dist/util/Database");
|
||||
const { User } = require("../dist/entities/User");
|
||||
jest.setTimeout(10000);
|
||||
jest.setTimeout(20000);
|
||||
|
||||
beforeAll((done) => {
|
||||
initDatabase().then(() => {
|
||||
new User().validate(); // warm up schema/model
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -28,4 +27,17 @@ describe("User", () => {
|
||||
new User({ discriminator: "0" }).validate();
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test("add guild", async () => {
|
||||
try {
|
||||
await new User({ guilds: [], discriminator: "1" }, { id: "0" }).save();
|
||||
const user = await User.find("0");
|
||||
|
||||
user.guilds.push(new Guild({ name: "test" }));
|
||||
|
||||
user.save();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,8 @@
|
||||
const { performance } = require("perf_hooks");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// fs.unlinkSync(path.join(__dirname, "..", "database.db"));
|
||||
|
||||
global.expect.extend({
|
||||
toBeFasterThan: async (func, target) => {
|
||||
|
@ -1,33 +0,0 @@
|
||||
const { initDatabase, closeDatabase } = require("../dist/util/Database");
|
||||
const { User } = require("../dist/entities/User");
|
||||
jest.setTimeout(10000);
|
||||
|
||||
beforeAll((done) => {
|
||||
initDatabase().then(() => {
|
||||
new User().validate(); // warm up schema/model
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
closeDatabase();
|
||||
});
|
||||
|
||||
describe("Validate model class properties", () => {
|
||||
test("object instead of string", async () => {
|
||||
expect(() => {
|
||||
new User({}, { id: {} }).validate();
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test("validation should be faster than 20ms", () => {
|
||||
expect(() => {
|
||||
new User().validate();
|
||||
}).toBeFasterThan(20);
|
||||
});
|
||||
|
||||
test("should not set opts", () => {
|
||||
const user = new User({ opts: { id: 0 } });
|
||||
expect(user.opts.id).not.toBe(0);
|
||||
});
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"include": ["src/**/*.ts"],
|
||||
"include": ["src/**/*.ts", "tests/Test.ts"],
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user