mirror of
https://github.com/spacebarchat/server.git
synced 2026-05-11 23:24:56 +00:00
Merge branch 'dev/cherry-plugins-improvements' into staging
This commit is contained in:
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=$(git hash-object -t tree /dev/null)
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf dist
|
||||
|
||||
#npx prettier -w .
|
||||
npx --yes -p prettier@latest -p pretty-quick pretty-quick
|
||||
git update-index --again
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
#exec git diff-index --check --cached $against --
|
||||
@@ -1,11 +1,11 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Fosscord Documentation
|
||||
url: https://docs.fosscord.com/
|
||||
about: Need documentation and examples for the Fosscord? Head over to Fosscord's official documentation.
|
||||
- name: Discord's Developer Documentation
|
||||
url: https://discord.com/developers/docs/intro
|
||||
about: Need help with the Discord resources? Head here instead of asking on Fosscord!
|
||||
- name: Fosscord' Official Discord server
|
||||
url: https://discord.com/invite/Ms5Ev7S6bF
|
||||
about: Need help with the server? Talk with us in our official server.
|
||||
- name: Fosscord Documentation
|
||||
url: https://docs.fosscord.com/
|
||||
about: Need documentation and examples for the Fosscord? Head over to Fosscord's official documentation.
|
||||
- name: Discord's Developer Documentation
|
||||
url: https://discord.com/developers/docs/intro
|
||||
about: Need help with the Discord resources? Head here instead of asking on Fosscord!
|
||||
- name: Fosscord' Official Discord server
|
||||
url: https://discord.com/invite/Ms5Ev7S6bF
|
||||
about: Need help with the server? Talk with us in our official server.
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
## Notes
|
||||
|
||||
## Additions
|
||||
-
|
||||
|
||||
-
|
||||
|
||||
## Fixes
|
||||
|
||||
-
|
||||
|
||||
## Download
|
||||
- [Windows]()
|
||||
- [MacOS]()
|
||||
- [Linux]()
|
||||
|
||||
- [Windows]()
|
||||
- [MacOS]()
|
||||
- [Linux]()
|
||||
|
||||
After (extracting) and starting the server executable you can access your own Fosscord server on http://localhost:3001/
|
||||
|
||||
+12
-1
@@ -19,5 +19,16 @@ api/assets/plugins/*.js
|
||||
bundle/depclean.*
|
||||
*.tmp
|
||||
tmp/
|
||||
assets/cache/
|
||||
*.generated
|
||||
initial.json
|
||||
.yarn/cache
|
||||
build.json
|
||||
|
||||
assets/cache/
|
||||
yarn.lock
|
||||
|
||||
.yarn/install-state.gz
|
||||
|
||||
dbconf.json
|
||||
|
||||
migrations.db
|
||||
|
||||
+4
-2
@@ -2,5 +2,7 @@
|
||||
"tabWidth": 4,
|
||||
"useTabs": true,
|
||||
"printWidth": 140,
|
||||
"trailingComma": "none"
|
||||
}
|
||||
"trailingComma": "none",
|
||||
"pluginSearchDirs": ["./node_modules"],
|
||||
"plugins": ["prettier-plugin-organize-imports"]
|
||||
}
|
||||
|
||||
Vendored
+12
-16
@@ -1,17 +1,13 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"program": "${file}",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/**/*.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"program": "${file}",
|
||||
"outFiles": ["${workspaceFolder}/**/*.js"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+783
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.2.2.cjs
|
||||
+45
-45
@@ -1,47 +1,47 @@
|
||||
const localStorage = window.localStorage;
|
||||
// TODO: remote auth
|
||||
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
|
||||
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
|
||||
localStorage.setItem(
|
||||
"DeveloperOptionsStore",
|
||||
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
|
||||
);
|
||||
const localStorage = window.localStorage;
|
||||
// TODO: remote auth
|
||||
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
|
||||
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
|
||||
localStorage.setItem(
|
||||
"DeveloperOptionsStore",
|
||||
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
|
||||
);
|
||||
|
||||
const supportedLocales = [
|
||||
"bg",
|
||||
"cs",
|
||||
"da",
|
||||
"de",
|
||||
"el",
|
||||
"en-GB",
|
||||
"es-ES",
|
||||
"fi",
|
||||
"fr",
|
||||
"hi",
|
||||
"hr",
|
||||
"hu",
|
||||
"it",
|
||||
"ja",
|
||||
"ko",
|
||||
"lt",
|
||||
"nl",
|
||||
"no",
|
||||
"pl",
|
||||
"pt-BR",
|
||||
"ro",
|
||||
"ru",
|
||||
"sv-SE",
|
||||
"th",
|
||||
"tr",
|
||||
"uk",
|
||||
"vi",
|
||||
"zh-CN",
|
||||
"zh-TW"
|
||||
];
|
||||
const supportedLocales = [
|
||||
"bg",
|
||||
"cs",
|
||||
"da",
|
||||
"de",
|
||||
"el",
|
||||
"en-GB",
|
||||
"es-ES",
|
||||
"fi",
|
||||
"fr",
|
||||
"hi",
|
||||
"hr",
|
||||
"hu",
|
||||
"it",
|
||||
"ja",
|
||||
"ko",
|
||||
"lt",
|
||||
"nl",
|
||||
"no",
|
||||
"pl",
|
||||
"pt-BR",
|
||||
"ro",
|
||||
"ru",
|
||||
"sv-SE",
|
||||
"th",
|
||||
"tr",
|
||||
"uk",
|
||||
"vi",
|
||||
"zh-CN",
|
||||
"zh-TW"
|
||||
];
|
||||
|
||||
const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
|
||||
if (settings && !supportedLocales.includes(settings.locale)) {
|
||||
// fix client locale wrong and client not loading at all
|
||||
settings.locale = "en-US";
|
||||
localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
|
||||
}
|
||||
const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
|
||||
if (settings && !supportedLocales.includes(settings.locale)) {
|
||||
// fix client locale wrong and client not loading at all
|
||||
settings.locale = "en-US";
|
||||
localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
|
||||
}
|
||||
|
||||
+37
-39
@@ -1,44 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="theme-dark" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no" name="viewport" />
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no" name="viewport" />
|
||||
<link rel="stylesheet" href="/assets/532.03aaeef88460fae60534.css" integrity="" />
|
||||
<link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico" />
|
||||
<title>Discord Test Client Developer Portal</title>
|
||||
<meta charset="utf-8" data-react-helmet="true" />
|
||||
</head>
|
||||
|
||||
<link rel="stylesheet" href="/assets/532.03aaeef88460fae60534.css" integrity="" />
|
||||
<link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico" />
|
||||
<title>Discord Test Client Developer Portal</title>
|
||||
<meta charset="utf-8" data-react-helmet="true" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-mount"></div>
|
||||
<script>
|
||||
window.GLOBAL_ENV = {
|
||||
API_VERSION: 9,
|
||||
API_ENDPOINT: "/api",
|
||||
WEBAPP_ENDPOINT: "",
|
||||
CDN_HOST: `${location.hostname}:3003`,
|
||||
|
||||
<body>
|
||||
<div id="app-mount"></div>
|
||||
<script>
|
||||
window.GLOBAL_ENV = {
|
||||
API_VERSION: 9,
|
||||
API_ENDPOINT: "/api",
|
||||
WEBAPP_ENDPOINT: "",
|
||||
CDN_HOST: `${location.hostname}:3003`,
|
||||
|
||||
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
|
||||
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
|
||||
MARKETING_ENDPOINT: "//discord.com",
|
||||
RELEASE_CHANNEL: "stable",
|
||||
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
|
||||
};
|
||||
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
|
||||
const localStorage = window.localStorage;
|
||||
// TODO: remote auth
|
||||
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
|
||||
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
|
||||
localStorage.setItem(
|
||||
"DeveloperOptionsStore",
|
||||
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
|
||||
);
|
||||
</script>
|
||||
<script src="/assets/38f40c32d3c8a2fdf73b.js" integrity=""></script>
|
||||
<script src="/assets/aa190934324e05fcc35c.js" integrity=""></script>
|
||||
<script src="/assets/45664a0209e828a528b4.js" integrity=""></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
|
||||
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
|
||||
MARKETING_ENDPOINT: "//discord.com",
|
||||
RELEASE_CHANNEL: "stable",
|
||||
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
|
||||
};
|
||||
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
|
||||
const localStorage = window.localStorage;
|
||||
// TODO: remote auth
|
||||
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
|
||||
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
|
||||
localStorage.setItem(
|
||||
"DeveloperOptionsStore",
|
||||
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
|
||||
);
|
||||
</script>
|
||||
<script src="/assets/38f40c32d3c8a2fdf73b.js" integrity=""></script>
|
||||
<script src="/assets/aa190934324e05fcc35c.js" integrity=""></script>
|
||||
<script src="/assets/45664a0209e828a528b4.js" integrity=""></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* replace tos acceptance popup */
|
||||
#app-mount > div:nth-child(7) > div > div > div.tooltipContent-bqVLWK {
|
||||
visibility: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
#app-mount > div:nth-child(7) > div > div > div.tooltipContent-bqVLWK::after{
|
||||
visibility: visible;
|
||||
display: block;
|
||||
content: "You need to agree to this instance's rules to continue";
|
||||
margin-top: -32px;
|
||||
#app-mount > div:nth-child(7) > div > div > div.tooltipContent-bqVLWK::after {
|
||||
visibility: visible;
|
||||
display: block;
|
||||
content: "You need to agree to this instance's rules to continue";
|
||||
margin-top: -32px;
|
||||
}
|
||||
/* replace login header */
|
||||
#app-mount > div.app-1q1i1E > div > div > div > div > form > div > div > div.mainLoginContainer-1ddwnR > h3 {
|
||||
|
||||
+57
-11
@@ -1,4 +1,3 @@
|
||||
|
||||
/* loading spinner */
|
||||
#app-mount > div.app-1q1i1E > div.container-16j22k.fixClipping-3qAKRb > div.content-1-zrf2 > video {
|
||||
filter: opacity(1);
|
||||
@@ -11,14 +10,62 @@
|
||||
}
|
||||
|
||||
/* home button icon */
|
||||
#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div
|
||||
{
|
||||
background-image: url(https://raw.githubusercontent.com/fosscord/fosscord/master/assets-rebrand/svg/Fosscord-Icon-Rounded-Subtract.svg);
|
||||
background-size: contain;
|
||||
border-radius: 50%;
|
||||
#app-mount
|
||||
> div.app-1q1i1E
|
||||
> div
|
||||
> div.layers-3iHuyZ.layers-3q14ss
|
||||
> div
|
||||
> div
|
||||
> nav
|
||||
> ul
|
||||
> div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih
|
||||
> div.tutorialContainer-2sGCg9
|
||||
> div
|
||||
> div.listItemWrapper-KhRmzM
|
||||
> div
|
||||
> svg
|
||||
> foreignObject
|
||||
> div
|
||||
> div {
|
||||
background-image: url(https://raw.githubusercontent.com/fosscord/fosscord/master/assets-rebrand/svg/Fosscord-Icon-Rounded-Subtract.svg);
|
||||
background-size: contain;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div, #app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div:hover {
|
||||
#app-mount
|
||||
> div.app-1q1i1E
|
||||
> div
|
||||
> div.layers-3iHuyZ.layers-3q14ss
|
||||
> div
|
||||
> div
|
||||
> nav
|
||||
> ul
|
||||
> div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih
|
||||
> div.tutorialContainer-2sGCg9
|
||||
> div
|
||||
> div.listItemWrapper-KhRmzM
|
||||
> div
|
||||
> svg
|
||||
> foreignObject
|
||||
> div
|
||||
> div,
|
||||
#app-mount
|
||||
> div.app-1q1i1E
|
||||
> div
|
||||
> div.layers-3iHuyZ.layers-3q14ss
|
||||
> div
|
||||
> div
|
||||
> nav
|
||||
> ul
|
||||
> div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih
|
||||
> div.tutorialContainer-2sGCg9
|
||||
> div
|
||||
> div.listItemWrapper-KhRmzM
|
||||
> div
|
||||
> svg
|
||||
> foreignObject
|
||||
> div
|
||||
> div:hover {
|
||||
background-color: white;
|
||||
}
|
||||
/* Login QR */
|
||||
@@ -40,7 +87,6 @@
|
||||
/* Thread permissions etc popups */
|
||||
#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > div > div.content-98HsJk > div.sidebar-2K8pFh.hasNotice-1XRy4h > nav > div.container-3O_wAf,
|
||||
/* home button icon */
|
||||
#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div > svg
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
#app-mount > div.app-1q1i1E > div > div.layers-3iHuyZ.layers-3q14ss > div > div > nav > ul > div.scroller-1Bvpku.none-2Eo-qx.scrollerBase-289Jih > div.tutorialContainer-2sGCg9 > div > div.listItemWrapper-KhRmzM > div > svg > foreignObject > div > div > svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
+76
-78
@@ -1,84 +1,82 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Discord Test Client</title>
|
||||
<link rel="stylesheet" href="/assets/fosscord.css" />
|
||||
<link id="logincss" rel="stylesheet" href="/assets/fosscord-login.css" />
|
||||
<link id="customcss" rel="stylesheet" href="/assets/user.css" />
|
||||
<!-- inline plugin marker -->
|
||||
<!-- preload plugin marker -->
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Discord Test Client</title>
|
||||
<link rel="stylesheet" href="/assets/fosscord.css" />
|
||||
<link id="logincss" rel="stylesheet" href="/assets/fosscord-login.css" />
|
||||
<link id="customcss" rel="stylesheet" href="/assets/user.css" />
|
||||
<!-- inline plugin marker -->
|
||||
<!-- preload plugin marker -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-mount"></div>
|
||||
<script>
|
||||
window.__OVERLAY__ = /overlay/.test(location.pathname);
|
||||
window.__BILLING_STANDALONE__ = /^\/billing/.test(location.pathname);
|
||||
window.GLOBAL_ENV = {
|
||||
API_ENDPOINT: "/api",
|
||||
API_VERSION: 9,
|
||||
GATEWAY_ENDPOINT: `${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}`,
|
||||
WEBAPP_ENDPOINT: "",
|
||||
CDN_HOST: `${location.hostname}:3003`,
|
||||
ASSET_ENDPOINT: "",
|
||||
MEDIA_PROXY_ENDPOINT: "https://media.discordapp.net",
|
||||
WIDGET_ENDPOINT: `//${location.host}/widget`,
|
||||
INVITE_HOST: `${location.hostname}/invite`,
|
||||
GUILD_TEMPLATE_HOST: "${location.host}",
|
||||
GIFT_CODE_HOST: "${location.hostname}",
|
||||
RELEASE_CHANNEL: "stable",
|
||||
MARKETING_ENDPOINT: "//discord.com",
|
||||
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
|
||||
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
|
||||
NETWORKING_ENDPOINT: "//router.discordapp.net",
|
||||
RTC_LATENCY_ENDPOINT: "//${location.hostname}/rtc",
|
||||
ACTIVITY_APPLICATION_HOST: "discordsays.com",
|
||||
PROJECT_ENV: "production",
|
||||
REMOTE_AUTH_ENDPOINT: "//localhost:3020",
|
||||
SENTRY_TAGS: { buildId: "75e36d9", buildType: "normal" },
|
||||
MIGRATION_SOURCE_ORIGIN: "https://${location.hostname}",
|
||||
MIGRATION_DESTINATION_ORIGIN: "https://${location.hostname}",
|
||||
HTML_TIMESTAMP: Date.now(),
|
||||
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
|
||||
};
|
||||
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
|
||||
const localStorage = window.localStorage;
|
||||
// TODO: remote auth
|
||||
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
|
||||
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
|
||||
localStorage.setItem(
|
||||
"DeveloperOptionsStore",
|
||||
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
|
||||
);
|
||||
|
||||
<body>
|
||||
<div id="app-mount"></div>
|
||||
<script>
|
||||
window.__OVERLAY__ = /overlay/.test(location.pathname);
|
||||
window.__BILLING_STANDALONE__ = /^\/billing/.test(location.pathname);
|
||||
window.GLOBAL_ENV = {
|
||||
API_ENDPOINT: "/api",
|
||||
API_VERSION: 9,
|
||||
GATEWAY_ENDPOINT: `${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}`,
|
||||
WEBAPP_ENDPOINT: "",
|
||||
CDN_HOST: `${location.hostname}:3003`,
|
||||
ASSET_ENDPOINT: "",
|
||||
MEDIA_PROXY_ENDPOINT: "https://media.discordapp.net",
|
||||
WIDGET_ENDPOINT: `//${location.host}/widget`,
|
||||
INVITE_HOST: `${location.hostname}/invite`,
|
||||
GUILD_TEMPLATE_HOST: "${location.host}",
|
||||
GIFT_CODE_HOST: "${location.hostname}",
|
||||
RELEASE_CHANNEL: "stable",
|
||||
MARKETING_ENDPOINT: "//discord.com",
|
||||
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
|
||||
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
|
||||
NETWORKING_ENDPOINT: "//router.discordapp.net",
|
||||
RTC_LATENCY_ENDPOINT: "//${location.hostname}/rtc",
|
||||
ACTIVITY_APPLICATION_HOST: 'discordsays.com',
|
||||
PROJECT_ENV: "production",
|
||||
REMOTE_AUTH_ENDPOINT: "//localhost:3020",
|
||||
SENTRY_TAGS: { buildId: "75e36d9", buildType: "normal" },
|
||||
MIGRATION_SOURCE_ORIGIN: "https://${location.hostname}",
|
||||
MIGRATION_DESTINATION_ORIGIN: "https://${location.hostname}",
|
||||
HTML_TIMESTAMP: Date.now(),
|
||||
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0",
|
||||
};
|
||||
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
|
||||
const localStorage = window.localStorage;
|
||||
// TODO: remote auth
|
||||
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
|
||||
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
|
||||
localStorage.setItem(
|
||||
"DeveloperOptionsStore",
|
||||
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
|
||||
);
|
||||
|
||||
setInterval(() => {
|
||||
let token = JSON.parse(localStorage.getItem("token"));
|
||||
if (token) {
|
||||
let logincss = document.querySelector('#logincss'),
|
||||
canRemove = logincss ? logincss : "";
|
||||
if (canRemove !== "") {
|
||||
document.querySelector("#logincss").remove();
|
||||
canRemove = "";
|
||||
setInterval(() => {
|
||||
let token = JSON.parse(localStorage.getItem("token"));
|
||||
if (token) {
|
||||
let logincss = document.querySelector("#logincss"),
|
||||
canRemove = logincss ? logincss : "";
|
||||
if (canRemove !== "") {
|
||||
document.querySelector("#logincss").remove();
|
||||
canRemove = "";
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
|
||||
if (settings && settings.locale.length <= 2) {
|
||||
// fix client locale wrong and client not loading at all
|
||||
settings.locale = "en-US";
|
||||
localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
|
||||
if (settings && settings.locale.length <= 2) {
|
||||
// fix client locale wrong and client not loading at all
|
||||
settings.locale = "en-US";
|
||||
localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
|
||||
}
|
||||
</script>
|
||||
<script src="/assets/checkLocale.js"></script>
|
||||
<script src="/assets/2f2e0c25e45eb2f5a6f1.js"></script>
|
||||
<script src="/assets/006e72c08a4c69cb66fc.js"></script>
|
||||
<script src="/assets/2f94a3ba801087653a38.js"></script>
|
||||
<script src="/assets/f7703f092bdbfc607cc7.js"></script>
|
||||
<!-- plugin marker -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</script>
|
||||
<script src="/assets/checkLocale.js"></script>
|
||||
<script src="/assets/2f2e0c25e45eb2f5a6f1.js"></script>
|
||||
<script src="/assets/006e72c08a4c69cb66fc.js"></script>
|
||||
<script src="/assets/2f94a3ba801087653a38.js"></script>
|
||||
<script src="/assets/f7703f092bdbfc607cc7.js"></script>
|
||||
<!-- plugin marker -->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
/* Your custom CSS goes here, enjoy! */
|
||||
/* Your custom CSS goes here, enjoy! */
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compiler": "tsc",
|
||||
"verbose": true,
|
||||
"writeBuildLog": true,
|
||||
"writeAnsiBuildLog": true,
|
||||
"logErrors": true,
|
||||
"tsc": {
|
||||
"prettyErrors": true
|
||||
},
|
||||
"clean": true,
|
||||
"quiet": false,
|
||||
"steps": {
|
||||
"pre": ["clean"],
|
||||
"post": ["remap_imports"]
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
The Docker image is coming with the dashboard. The planned release date is 2022-12-24.
|
||||
The Docker image is coming with the dashboard. The planned release date is 2022-12-24.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
version: '3.9'
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
|
||||
fosscord:
|
||||
entrypoint: [ "npm", "run", "setup" ]
|
||||
fosscord:
|
||||
entrypoint: ["npm", "run", "setup"]
|
||||
|
||||
+20
-21
@@ -1,25 +1,24 @@
|
||||
version: '3.9'
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
|
||||
fosscord:
|
||||
container_name: fosscord
|
||||
image: fosscord
|
||||
restart: on-failure:5
|
||||
build: .
|
||||
ports:
|
||||
- '3001-3005:3001-3005'
|
||||
volumes:
|
||||
- ./:/srv/fosscord-server/
|
||||
environment:
|
||||
THREADS: ${THREADS:-1}
|
||||
HTTP_PORT: 3001
|
||||
WS_PORT: 3002
|
||||
CDN_PORT: 3003
|
||||
RTC_PORT: 3004
|
||||
ADMIN_PORT: 3005
|
||||
fosscord:
|
||||
container_name: fosscord
|
||||
image: fosscord
|
||||
restart: on-failure:5
|
||||
build: .
|
||||
ports:
|
||||
- "3001-3005:3001-3005"
|
||||
volumes:
|
||||
- ./:/srv/fosscord-server/
|
||||
environment:
|
||||
THREADS: ${THREADS:-1}
|
||||
HTTP_PORT: 3001
|
||||
WS_PORT: 3002
|
||||
CDN_PORT: 3003
|
||||
RTC_PORT: 3004
|
||||
ADMIN_PORT: 3005
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: fosscord
|
||||
driver: bridge
|
||||
default:
|
||||
name: fosscord
|
||||
driver: bridge
|
||||
|
||||
+16
-16
@@ -1,18 +1,18 @@
|
||||
#Fosscord Environment Variables:
|
||||
|
||||
|NAME|VALUE|DESCRIPTION|
|
||||
|----|-----|-----------|
|
||||
|LOG\_REQUESTS | ports to include, or exclude (-) | logs requests |
|
||||
|PORT|number|sets port number to listen on|
|
||||
|CDN|string|CDN address|
|
||||
|GATEWAY|string|Gateway address|
|
||||
|NODE\_ENV|production/development|sets node environment|
|
||||
|DATABASE|database url|points to what database to use|
|
||||
|EVENT\_TRANSMISSION|string|event transmission type|
|
||||
|STORAGE\_PROVIDER|s3/file|How to store files for CDN|
|
||||
|STORAGE\_LOCATION|path|Directory to store files in|
|
||||
|STORAGE\_BUCKET|s3 bucket name|S3 bucket name|
|
||||
|DB\_UNSAFE|any|Ignores migrations for database, enabled if defined|
|
||||
|DB\_VERBOSE|any|Log database queries, enabled if defined|
|
||||
|DB\_MIGRATE|any|Exit fosscord after connecting to and migrating database, used internally|
|
||||
|LOG\_INVALID\_BODY|any|Log request method, path and body if invalid|
|
||||
| NAME | VALUE | DESCRIPTION |
|
||||
| ------------------ | -------------------------------- | ------------------------------------------------------------------------- |
|
||||
| LOG_REQUESTS | ports to include, or exclude (-) | logs requests |
|
||||
| PORT | number | sets port number to listen on |
|
||||
| CDN | string | CDN address |
|
||||
| GATEWAY | string | Gateway address |
|
||||
| NODE_ENV | production/development | sets node environment |
|
||||
| DATABASE | database url | points to what database to use |
|
||||
| EVENT_TRANSMISSION | string | event transmission type |
|
||||
| STORAGE_PROVIDER | s3/file | How to store files for CDN |
|
||||
| STORAGE_LOCATION | path | Directory to store files in |
|
||||
| STORAGE_BUCKET | s3 bucket name | S3 bucket name |
|
||||
| DB_UNSAFE | any | Ignores migrations for database, enabled if defined |
|
||||
| DB_VERBOSE | any | Log database queries, enabled if defined |
|
||||
| DB_MIGRATE | any | Exit fosscord after connecting to and migrating database, used internally |
|
||||
| LOG_INVALID_BODY | any | Log request method, path and body if invalid |
|
||||
|
||||
@@ -17,5 +17,22 @@
|
||||
"files.exclude": {
|
||||
"*.ansi": true,
|
||||
}
|
||||
},
|
||||
"launch": {
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm run start:bundle:vscode-dbg",
|
||||
"name": "Run Fosscord with debugger",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "kitty npm run start:bundle:vscode-dbg",
|
||||
"name": "Run Fosscord with debugger (kitty)",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
BIN
Binary file not shown.
+20
-22
@@ -4,18 +4,18 @@
|
||||
"description": "",
|
||||
"main": "src/start.js",
|
||||
"scripts": {
|
||||
"setup": "npm install --omit optional && ts-patch install -s && patch-package && npm run build",
|
||||
"depclean": "node scripts/depclean.js",
|
||||
"depcheck": "node scripts/depcheck.js",
|
||||
"build": "node scripts/build.js",
|
||||
"postinstall": "patch-package",
|
||||
"genschemas": "node scripts/generate_schemas.js",
|
||||
"start": "node scripts/build.js && node --enable-source-maps dist/start.js",
|
||||
"setup": "npm install --omit optional && patch-package && npm run build",
|
||||
"build": "node scripts/build_new.js",
|
||||
"start": "npm run build && npm run start:bundle",
|
||||
"start:bundle": "node --enable-source-maps dist/start.js",
|
||||
"start:bundle:dbg": "node --enable-source-maps --inspect dist/start.js",
|
||||
"start:bundle:vscode-dbg": "npm run build clean logerrors pretty-errors && node --enable-source-maps --inspect dist/start.js",
|
||||
"start:bundle:vscode-dbg": "npm run build && node --enable-source-maps --inspect dist/start.js",
|
||||
"depclean": "node scripts/depclean.js",
|
||||
"depcheck": "node scripts/depcheck.js",
|
||||
"tsnode": "npx ts-node --transpile-only -P tsnode.tsconfig.json src/start.ts",
|
||||
"genschemas": "node scripts/generate_schemas.js",
|
||||
"migrate": "cd ../util/ && npm i && node --require ts-node/register node_modules/typeorm/cli.js -f ../util/ormconfig.json migration:run",
|
||||
"tsnode": "npx ts-node --transpile-only -P tsnode.tsconfig.json src/start.ts"
|
||||
"postinstall": "patch-package && npx --yes node-git-hooks"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -28,44 +28,45 @@
|
||||
"url": "https://github.com/fosscord/fosscord-server/issues"
|
||||
},
|
||||
"homepage": "https://fosscord.com",
|
||||
"imports": {
|
||||
"#*": "./dist/*/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.9",
|
||||
"@babel/preset-env": "^7.18.9",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@types/amqplib": "^0.8.1",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/body-parser": "^1.19.0",
|
||||
"@types/dotenv": "^8.2.0",
|
||||
"@types/express": "^4.17.12",
|
||||
"@types/i18next-node-fs-backend": "^2.1.0",
|
||||
"@types/jsonwebtoken": "^8.5.8",
|
||||
"@types/morgan": "^1.9.3",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^18.7.3",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/node-os-utils": "^1.3.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"jest": "^28.1.3",
|
||||
"jest-expect-message": "^1.0.2",
|
||||
"prettier-plugin-organize-imports": "^3.0.3",
|
||||
"supertest": "^6.1.6",
|
||||
"ts-node": "^10.2.1",
|
||||
"ts-node-dev": "^2.0.0",
|
||||
"ts-patch": "^2.0.2",
|
||||
"typescript": "^4.2.3",
|
||||
"typescript-json-schema": "^0.54.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.137.0",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@ovos-media/ts-transform-paths": "^1.7.18-1",
|
||||
"@sentry/node": "^7.7.0",
|
||||
"@sentry/tracing": "^7.7.0",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"ajv": "^8.6.2",
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"amqplib": "^0.10.1",
|
||||
"bcrypt": "^5.0.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.19.0",
|
||||
"canvas": "^2.9.3",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"dotenv": "^16.0.1",
|
||||
"exif-be-gone": "^1.3.1",
|
||||
@@ -86,15 +87,12 @@
|
||||
"node-fetch": "^2.6.7",
|
||||
"patch-package": "^6.4.7",
|
||||
"picocolors": "^1.0.0",
|
||||
"prettier": "^2.7.1",
|
||||
"proxy-agent": "^5.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"typeorm": "^0.3.7",
|
||||
"typescript": "^4.1.2",
|
||||
"typescript": "^4.2.3",
|
||||
"ws": "^8.8.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"mysql2": "^2.3.3",
|
||||
"pg": "^8.7.3",
|
||||
"sqlite3": "^5.0.11"
|
||||
}
|
||||
"packageManager": "yarn@3.2.2"
|
||||
}
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
diff --git a/node_modules/ajv/dist/compile/jtd/parse.js b/node_modules/ajv/dist/compile/jtd/parse.js
|
||||
index 1eeb1be..7684121 100644
|
||||
--- a/node_modules/ajv/dist/compile/jtd/parse.js
|
||||
+++ b/node_modules/ajv/dist/compile/jtd/parse.js
|
||||
@@ -239,6 +239,9 @@ function parseType(cxt) {
|
||||
gen.if(fail, () => parsingError(cxt, codegen_1.str `invalid timestamp`));
|
||||
break;
|
||||
}
|
||||
+ case "bigint":
|
||||
+ parseBigInt(cxt);
|
||||
+ break
|
||||
case "float32":
|
||||
case "float64":
|
||||
parseNumber(cxt);
|
||||
@@ -284,6 +287,15 @@ function parseNumber(cxt, maxDigits) {
|
||||
skipWhitespace(cxt);
|
||||
gen.if(codegen_1._ `"-0123456789".indexOf(${jsonSlice(1)}) < 0`, () => jsonSyntaxError(cxt), () => parseWith(cxt, parseJson_1.parseJsonNumber, maxDigits));
|
||||
}
|
||||
+function parseBigInt(cxt, maxDigits) {
|
||||
+ const {gen} = cxt
|
||||
+ skipWhitespace(cxt)
|
||||
+ gen.if(
|
||||
+ _`"-0123456789".indexOf(${jsonSlice(1)}) < 0`,
|
||||
+ () => jsonSyntaxError(cxt),
|
||||
+ () => parseWith(cxt, parseJson_1.parseJsonBigInt, maxDigits)
|
||||
+ )
|
||||
+}
|
||||
function parseBooleanToken(bool, fail) {
|
||||
return (cxt) => {
|
||||
const { gen, data } = cxt;
|
||||
diff --git a/node_modules/ajv/dist/compile/rules.js b/node_modules/ajv/dist/compile/rules.js
|
||||
index 82a591f..1ebd8fe 100644
|
||||
--- a/node_modules/ajv/dist/compile/rules.js
|
||||
+++ b/node_modules/ajv/dist/compile/rules.js
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getRules = exports.isJSONType = void 0;
|
||||
-const _jsonTypes = ["string", "number", "integer", "boolean", "null", "object", "array"];
|
||||
+const _jsonTypes = ["string", "number", "integer", "boolean", "null", "object", "array","bigint"];
|
||||
const jsonTypes = new Set(_jsonTypes);
|
||||
function isJSONType(x) {
|
||||
return typeof x == "string" && jsonTypes.has(x);
|
||||
@@ -13,10 +13,11 @@ function getRules() {
|
||||
string: { type: "string", rules: [] },
|
||||
array: { type: "array", rules: [] },
|
||||
object: { type: "object", rules: [] },
|
||||
+ bigint: {type: "bigint", rules: []}
|
||||
};
|
||||
return {
|
||||
- types: { ...groups, integer: true, boolean: true, null: true },
|
||||
- rules: [{ rules: [] }, groups.number, groups.string, groups.array, groups.object],
|
||||
+ types: { ...groups, integer: true, boolean: true, null: true, bigint: true },
|
||||
+ rules: [{ rules: [] }, groups.number, groups.string, groups.array, groups.object, groups.bigint],
|
||||
post: { rules: [] },
|
||||
all: {},
|
||||
keywords: {},
|
||||
diff --git a/node_modules/ajv/dist/compile/validate/dataType.js b/node_modules/ajv/dist/compile/validate/dataType.js
|
||||
index 6319e76..8b50b4c 100644
|
||||
--- a/node_modules/ajv/dist/compile/validate/dataType.js
|
||||
+++ b/node_modules/ajv/dist/compile/validate/dataType.js
|
||||
@@ -52,7 +52,7 @@ function coerceAndCheckDataType(it, types) {
|
||||
return checkTypes;
|
||||
}
|
||||
exports.coerceAndCheckDataType = coerceAndCheckDataType;
|
||||
-const COERCIBLE = new Set(["string", "number", "integer", "boolean", "null"]);
|
||||
+const COERCIBLE = new Set(["string", "number", "integer", "boolean", "null","bigint"]);
|
||||
function coerceToTypes(types, coerceTypes) {
|
||||
return coerceTypes
|
||||
? types.filter((t) => COERCIBLE.has(t) || (coerceTypes === "array" && t === "array"))
|
||||
@@ -83,6 +83,14 @@ function coerceData(it, types, coerceTo) {
|
||||
});
|
||||
function coerceSpecificType(t) {
|
||||
switch (t) {
|
||||
+ case "bigint":
|
||||
+ gen
|
||||
+ .elseIf(
|
||||
+ codegen_1._`${dataType} == "boolean" || ${data} === null
|
||||
+ || (${dataType} == "string" && ${data} && ${data} == BigInt(${data}))`
|
||||
+ )
|
||||
+ .assign(coerced, codegen_1._`BigInt(${data})`)
|
||||
+ return
|
||||
case "string":
|
||||
gen
|
||||
.elseIf(codegen_1._ `${dataType} == "number" || ${dataType} == "boolean"`)
|
||||
@@ -143,6 +151,9 @@ function checkDataType(dataType, data, strictNums, correct = DataType.Correct) {
|
||||
case "number":
|
||||
cond = numCond();
|
||||
break;
|
||||
+ case "bigint":
|
||||
+ cond = codegen_1._`typeof ${data} == "bigint" && isFinite(${data})`
|
||||
+ break
|
||||
default:
|
||||
return codegen_1._ `typeof ${data} ${EQ} ${dataType}`;
|
||||
}
|
||||
diff --git a/node_modules/ajv/dist/refs/json-schema-2019-09/meta/validation.json b/node_modules/ajv/dist/refs/json-schema-2019-09/meta/validation.json
|
||||
index 7027a12..25679c8 100644
|
||||
--- a/node_modules/ajv/dist/refs/json-schema-2019-09/meta/validation.json
|
||||
+++ b/node_modules/ajv/dist/refs/json-schema-2019-09/meta/validation.json
|
||||
@@ -78,7 +78,7 @@
|
||||
"default": 0
|
||||
},
|
||||
"simpleTypes": {
|
||||
- "enum": ["array", "boolean", "integer", "null", "number", "object", "string"]
|
||||
+ "enum": ["array", "boolean", "integer", "null", "number", "object", "string","bigint"]
|
||||
},
|
||||
"stringArray": {
|
||||
"type": "array",
|
||||
diff --git a/node_modules/ajv/dist/refs/json-schema-2020-12/meta/validation.json b/node_modules/ajv/dist/refs/json-schema-2020-12/meta/validation.json
|
||||
index e0ae13d..57c9036 100644
|
||||
--- a/node_modules/ajv/dist/refs/json-schema-2020-12/meta/validation.json
|
||||
+++ b/node_modules/ajv/dist/refs/json-schema-2020-12/meta/validation.json
|
||||
@@ -78,7 +78,7 @@
|
||||
"default": 0
|
||||
},
|
||||
"simpleTypes": {
|
||||
- "enum": ["array", "boolean", "integer", "null", "number", "object", "string"]
|
||||
+ "enum": ["array", "boolean", "integer", "null", "number", "object", "string","bigint"]
|
||||
},
|
||||
"stringArray": {
|
||||
"type": "array",
|
||||
diff --git a/node_modules/ajv/dist/refs/json-schema-draft-06.json b/node_modules/ajv/dist/refs/json-schema-draft-06.json
|
||||
index 5410064..774435b 100644
|
||||
--- a/node_modules/ajv/dist/refs/json-schema-draft-06.json
|
||||
+++ b/node_modules/ajv/dist/refs/json-schema-draft-06.json
|
||||
@@ -16,7 +16,7 @@
|
||||
"allOf": [{"$ref": "#/definitions/nonNegativeInteger"}, {"default": 0}]
|
||||
},
|
||||
"simpleTypes": {
|
||||
- "enum": ["array", "boolean", "integer", "null", "number", "object", "string"]
|
||||
+ "enum": ["array", "boolean", "integer", "null", "number", "object", "string","bigint"]
|
||||
},
|
||||
"stringArray": {
|
||||
"type": "array",
|
||||
diff --git a/node_modules/ajv/dist/refs/json-schema-draft-07.json b/node_modules/ajv/dist/refs/json-schema-draft-07.json
|
||||
index 6a74851..fc6dd7d 100644
|
||||
--- a/node_modules/ajv/dist/refs/json-schema-draft-07.json
|
||||
+++ b/node_modules/ajv/dist/refs/json-schema-draft-07.json
|
||||
@@ -16,7 +16,7 @@
|
||||
"allOf": [{"$ref": "#/definitions/nonNegativeInteger"}, {"default": 0}]
|
||||
},
|
||||
"simpleTypes": {
|
||||
- "enum": ["array", "boolean", "integer", "null", "number", "object", "string"]
|
||||
+ "enum": ["array", "boolean", "integer", "null", "number", "object", "string","bigint"]
|
||||
},
|
||||
"stringArray": {
|
||||
"type": "array",
|
||||
diff --git a/node_modules/ajv/dist/refs/jtd-schema.js b/node_modules/ajv/dist/refs/jtd-schema.js
|
||||
index 1ee940a..1148887 100644
|
||||
--- a/node_modules/ajv/dist/refs/jtd-schema.js
|
||||
+++ b/node_modules/ajv/dist/refs/jtd-schema.js
|
||||
@@ -38,6 +38,7 @@ const typeForm = (root) => ({
|
||||
"uint16",
|
||||
"int32",
|
||||
"uint32",
|
||||
+ "bigint",
|
||||
],
|
||||
},
|
||||
},
|
||||
diff --git a/node_modules/ajv/dist/runtime/parseJson.js b/node_modules/ajv/dist/runtime/parseJson.js
|
||||
index 2576a6e..e7447b1 100644
|
||||
--- a/node_modules/ajv/dist/runtime/parseJson.js
|
||||
+++ b/node_modules/ajv/dist/runtime/parseJson.js
|
||||
@@ -97,6 +97,71 @@ exports.parseJsonNumber = parseJsonNumber;
|
||||
parseJsonNumber.message = undefined;
|
||||
parseJsonNumber.position = 0;
|
||||
parseJsonNumber.code = 'require("ajv/dist/runtime/parseJson").parseJsonNumber';
|
||||
+
|
||||
+function parseJsonBigInt(s, pos, maxDigits) {
|
||||
+ let numStr = "";
|
||||
+ let c;
|
||||
+ parseJsonBigInt.message = undefined;
|
||||
+ if (s[pos] === "-") {
|
||||
+ numStr += "-";
|
||||
+ pos++;
|
||||
+ }
|
||||
+ if (s[pos] === "0") {
|
||||
+ numStr += "0";
|
||||
+ pos++;
|
||||
+ }
|
||||
+ else {
|
||||
+ if (!parseDigits(maxDigits)) {
|
||||
+ errorMessage();
|
||||
+ return undefined;
|
||||
+ }
|
||||
+ }
|
||||
+ if (maxDigits) {
|
||||
+ parseJsonBigInt.position = pos;
|
||||
+ return BigInt(numStr);
|
||||
+ }
|
||||
+ if (s[pos] === ".") {
|
||||
+ numStr += ".";
|
||||
+ pos++;
|
||||
+ if (!parseDigits()) {
|
||||
+ errorMessage();
|
||||
+ return undefined;
|
||||
+ }
|
||||
+ }
|
||||
+ if (((c = s[pos]), c === "e" || c === "E")) {
|
||||
+ numStr += "e";
|
||||
+ pos++;
|
||||
+ if (((c = s[pos]), c === "+" || c === "-")) {
|
||||
+ numStr += c;
|
||||
+ pos++;
|
||||
+ }
|
||||
+ if (!parseDigits()) {
|
||||
+ errorMessage();
|
||||
+ return undefined;
|
||||
+ }
|
||||
+ }
|
||||
+ parseJsonBigInt.position = pos;
|
||||
+ return BigInt(numStr);
|
||||
+ function parseDigits(maxLen) {
|
||||
+ let digit = false;
|
||||
+ while (((c = s[pos]), c >= "0" && c <= "9" && (maxLen === undefined || maxLen-- > 0))) {
|
||||
+ digit = true;
|
||||
+ numStr += c;
|
||||
+ pos++;
|
||||
+ }
|
||||
+ return digit;
|
||||
+ }
|
||||
+ function errorMessage() {
|
||||
+ parseJsonBigInt.position = pos;
|
||||
+ parseJsonBigInt.message = pos < s.length ? `unexpected token ${s[pos]}` : "unexpected end";
|
||||
+ }
|
||||
+}
|
||||
+exports.parseJsonBigInt = parseJsonBigInt;
|
||||
+parseJsonBigInt.message = undefined;
|
||||
+parseJsonBigInt.position = 0;
|
||||
+parseJsonBigInt.code = 'require("ajv/dist/runtime/parseJson").parseJsonBigInt';
|
||||
+
|
||||
+
|
||||
const escapedChars = {
|
||||
b: "\b",
|
||||
f: "\f",
|
||||
diff --git a/node_modules/ajv/dist/vocabularies/jtd/type.js b/node_modules/ajv/dist/vocabularies/jtd/type.js
|
||||
index 428bddb..fbc3070 100644
|
||||
--- a/node_modules/ajv/dist/vocabularies/jtd/type.js
|
||||
+++ b/node_modules/ajv/dist/vocabularies/jtd/type.js
|
||||
@@ -45,6 +45,9 @@ const def = {
|
||||
cond = timestampCode(cxt);
|
||||
break;
|
||||
}
|
||||
+ case "bigint":
|
||||
+ cond = codegen_1._`typeof ${data} == "bigint" || typeof ${data} == "string"`
|
||||
+ break
|
||||
case "float32":
|
||||
case "float64":
|
||||
cond = codegen_1._ `typeof ${data} == "number"`;
|
||||
@@ -3,9 +3,7 @@ const Models = require("../dist/entities");
|
||||
const { PrimaryColumn } = require("typeorm");
|
||||
|
||||
function shouldIncludeEntity(name) {
|
||||
return ![Models.BaseClassWithoutId, PrimaryColumn, Models.BaseClass, Models.PrimaryGeneratedColumn]
|
||||
.map((x) => x?.name)
|
||||
.includes(name);
|
||||
return ![Models.BaseClassWithoutId, PrimaryColumn, Models.BaseClass, Models.PrimaryGeneratedColumn].map((x) => x?.name).includes(name);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
@@ -14,7 +12,7 @@ async function main() {
|
||||
type: "sqlite",
|
||||
database: ":memory:",
|
||||
entities: Object.values(Models).filter((x) => x.constructor.name == "Function" && shouldIncludeEntity(x.name)),
|
||||
synchronize: true,
|
||||
synchronize: true
|
||||
});
|
||||
await db.initialize();
|
||||
console.log("Initialized database");
|
||||
|
||||
@@ -8,7 +8,7 @@ let cores = 1;
|
||||
try {
|
||||
cores = Number(process.env.THREADS) || os.cpus().length;
|
||||
} catch {
|
||||
console.log("[Bundle] Failed to get thread count! Using 1...")
|
||||
console.log("[Bundle] Failed to get thread count! Using 1...");
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
@@ -46,8 +46,8 @@ function connect() {
|
||||
op: 2,
|
||||
d: {
|
||||
token,
|
||||
properties: {},
|
||||
},
|
||||
properties: {}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ async function main() {
|
||||
consent: true,
|
||||
date_of_birth: "2000-01-01",
|
||||
gift_code_sku_id: null,
|
||||
captcha_key: null,
|
||||
captcha_key: null
|
||||
}),
|
||||
headers: { "content-type": "application/json" },
|
||||
headers: { "content-type": "application/json" }
|
||||
});
|
||||
console.log(i);
|
||||
}
|
||||
|
||||
+80
-36
@@ -2,20 +2,22 @@ const { execSync } = require("child_process");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
const { execIn, parts } = require('./utils');
|
||||
const { execIn, parts, getDirs, walk, sanitizeVarName } = require("./utils");
|
||||
|
||||
if(argv.includes("help")) {
|
||||
if (argv.includes("help")) {
|
||||
console.log(`Fosscord build script help:
|
||||
Arguments:
|
||||
clean Cleans up previous builds
|
||||
verbose Enable verbose logging
|
||||
logerrors Log build errors to console
|
||||
pretty-errors Pretty-print build errors
|
||||
silent No output to console or files.`);
|
||||
silent No output to console or files.
|
||||
propagate-err Exit script with error code if build fails.`);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let steps = 1, i = 0;
|
||||
let steps = 5,
|
||||
i = 0;
|
||||
if (argv.includes("clean")) steps++;
|
||||
|
||||
const verbose = argv.includes("verbose") || argv.includes("v");
|
||||
@@ -23,7 +25,7 @@ const logerr = argv.includes("logerrors");
|
||||
const pretty = argv.includes("pretty-errors");
|
||||
const silent = argv.includes("silent");
|
||||
|
||||
if(silent) console.error = console.log = function(){}
|
||||
if (silent) console.error = console.log = function () {};
|
||||
|
||||
if (argv.includes("clean")) {
|
||||
console.log(`[${++i}/${steps}] Cleaning...`);
|
||||
@@ -36,37 +38,79 @@ if (argv.includes("clean")) {
|
||||
|
||||
console.log(`[${++i}/${steps}] Compiling src files ...`);
|
||||
|
||||
let buildFlags = ''
|
||||
if(pretty) buildFlags += '--pretty '
|
||||
let buildFlags = "";
|
||||
if (pretty) buildFlags += "--pretty ";
|
||||
|
||||
try {
|
||||
execSync(
|
||||
'node "' +
|
||||
path.join(__dirname, "..", "node_modules", "typescript", "lib", "tsc.js") +
|
||||
'" -p "' +
|
||||
path.join(__dirname, "..") +
|
||||
'" ' + buildFlags,
|
||||
{
|
||||
cwd: path.join(__dirname, ".."),
|
||||
shell: true,
|
||||
env: process.env,
|
||||
encoding: "utf8"
|
||||
}
|
||||
)
|
||||
} catch (error) {
|
||||
if(verbose || logerr) {
|
||||
error.stdout.split(/\r?\n/).forEach((line) => {
|
||||
let _line = line.replace('dist/','',1);
|
||||
if(!pretty && _line.includes('.ts(')) {
|
||||
//reformat file path for easy jumping
|
||||
_line = _line.replace('(',':',1).replace(',',':',1).replace(')','',1)
|
||||
console.log(`[${++i}/${steps}] Building plugin index...`);
|
||||
let pluginDir = path.join(__dirname, "..", "src", "plugins");
|
||||
let output = 'import { Plugin } from "util/plugin";\n';
|
||||
|
||||
const dirs = fs.readdirSync(pluginDir).filter((x) => {
|
||||
try {
|
||||
fs.readdirSync(path.join(pluginDir, x));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
dirs.forEach((x) => {
|
||||
let pluginManifest = require(path.join(pluginDir, x, "plugin.json"));
|
||||
output += `import * as ${sanitizeVarName(x)} from "./${x}/${pluginManifest.mainClass}";\n`;
|
||||
});
|
||||
output += `\nexport const PluginIndex: any = {\n`;
|
||||
dirs.forEach((x) => {
|
||||
output += ` "${x}": new ${sanitizeVarName(x)}.default(),\n`; //ctor test: '${path.resolve(path.join(pluginDir, x))}', require('./${x}/plugin.json')
|
||||
});
|
||||
output += `};`;
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, "..", "src", "plugins", "PluginIndex.ts"), output);
|
||||
|
||||
if (!argv.includes("copyonly")) {
|
||||
console.log(`[${++i}/${steps}] Compiling source code...`);
|
||||
|
||||
let buildFlags = "";
|
||||
if (pretty) buildFlags += "--pretty ";
|
||||
|
||||
try {
|
||||
execSync(
|
||||
'node "' +
|
||||
path.join(__dirname, "..", "node_modules", "typescript", "lib", "tsc.js") +
|
||||
'" -p "' +
|
||||
path.join(__dirname, "..") +
|
||||
'" ' +
|
||||
buildFlags,
|
||||
{
|
||||
cwd: path.join(__dirname, ".."),
|
||||
shell: true,
|
||||
env: process.env,
|
||||
encoding: "utf8"
|
||||
}
|
||||
console.error(_line);
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
if (verbose || logerr) {
|
||||
error.stdout.split(/\r?\n/).forEach((line) => {
|
||||
let _line = line.replace("dist/", "", 1);
|
||||
if (!pretty && _line.includes(".ts(")) {
|
||||
//reformat file path for easy jumping
|
||||
_line = _line.replace("(", ":", 1).replace(",", ":", 1).replace(")", "", 1);
|
||||
}
|
||||
console.error(_line);
|
||||
});
|
||||
}
|
||||
console.error(`Build failed! Please check build.log for info!`);
|
||||
if (!silent) {
|
||||
if (pretty) fs.writeFileSync("build.log.ansi", error.stdout);
|
||||
fs.writeFileSync(
|
||||
"build.log",
|
||||
error.stdout.replaceAll(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "")
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
console.error(`Build failed! Please check build.log for info!`);
|
||||
if(!silent){
|
||||
if(pretty) fs.writeFileSync("build.log.ansi", error.stdout);
|
||||
fs.writeFileSync("build.log", error.stdout.replaceAll(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[${++i}/${steps}] Copying plugin data...`);
|
||||
let pluginFiles = walk(pluginDir).filter((x) => !x.endsWith(".ts"));
|
||||
pluginFiles.forEach((x) => {
|
||||
fs.copyFileSync(x, x.replace("src", "dist"));
|
||||
});
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
const { execSync } = require("child_process");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
|
||||
|
||||
module.exports = function (config) {
|
||||
if (fs.existsSync(config.buildLog)) fs.rmSync(config.buildLog);
|
||||
if (fs.existsSync(config.buildLogAnsi)) fs.rmSync(config.buildLogAnsi);
|
||||
|
||||
if (config.clean) {
|
||||
console.log(`==> Cleaning...`);
|
||||
if (fs.existsSync(config.distDir)) {
|
||||
fs.rmSync(config.distDir, { recursive: true });
|
||||
if (config.verbose) console.log(`Deleted ${path.resolve(config.distDir)}!`);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
const { execSync } = require("child_process");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
|
||||
|
||||
module.exports = function (config) {
|
||||
console.log("==> Compiling source with tsc...");
|
||||
let buildFlags = "";
|
||||
if (config.pretty) buildFlags += "--pretty ";
|
||||
|
||||
try {
|
||||
execSync(
|
||||
'node "' +
|
||||
path.join(config.rootDir, "node_modules", "typescript", "lib", "tsc.js") +
|
||||
'" -p "' +
|
||||
path.join(config.rootDir) +
|
||||
'" ' +
|
||||
buildFlags,
|
||||
{
|
||||
cwd: path.join(config.rootDir),
|
||||
shell: true,
|
||||
env: process.env,
|
||||
encoding: "utf8"
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
if (config.verbose || config.logerr) {
|
||||
error.stdout.split(/\r?\n/).forEach((line) => {
|
||||
let _line = line.replace("dist/", "", 1);
|
||||
if (!config.pretty && _line.includes(".ts(")) {
|
||||
//reformat file path for easy jumping
|
||||
_line = _line.replace("(", ":", 1).replace(",", ":", 1).replace(")", "", 1);
|
||||
}
|
||||
console.error(_line);
|
||||
});
|
||||
}
|
||||
console.error(`Build failed! Please check build.log for info!`);
|
||||
if (!config.silent) {
|
||||
if (config.pretty) fs.writeFileSync(path.join(config.rootDir, "build.log.ansi"), error.stdout);
|
||||
fs.writeFileSync(
|
||||
path.join(config.rootDir, "build.log"),
|
||||
error.stdout.replaceAll(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "")
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
const { execSync } = require("child_process");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
|
||||
|
||||
module.exports = function (config) {
|
||||
console.log(`==> Building plugin index...`);
|
||||
let output = 'import { Plugin } from "util/plugin";\n';
|
||||
|
||||
const dirs = fs.readdirSync(config.pluginDir).filter((x) => {
|
||||
try {
|
||||
fs.readdirSync(path.join(config.pluginDir, x));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
dirs.forEach((x) => {
|
||||
let pluginManifest = require(path.join(config.pluginDir, x, "plugin.json"));
|
||||
console.log(` ==> Registering plugin: ${pluginManifest.name} (${pluginManifest.id}) by ${pluginManifest.authors}`);
|
||||
output += `import * as ${sanitizeVarName(x)} from "./${x}/${pluginManifest.mainClass}";\n`;
|
||||
});
|
||||
output += `\nexport const PluginIndex: any = {\n`;
|
||||
dirs.forEach((x) => {
|
||||
output += ` "${x}": new ${sanitizeVarName(x)}.default(),\n`; //ctor test: '${path.resolve(path.join(pluginDir, x))}', require('./${x}/plugin.json')
|
||||
});
|
||||
output += `};`;
|
||||
|
||||
fs.writeFileSync(path.join(config.pluginDir, "PluginIndex.ts"), output);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
const { execSync } = require("child_process");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
|
||||
|
||||
module.exports = function (config) {
|
||||
console.log(`==> Copying all plugin resources...`);
|
||||
let pluginFiles = walk(config.pluginDir).filter((x) => !x.endsWith(".ts"));
|
||||
pluginFiles.forEach((x) => {
|
||||
fs.copyFileSync(x, x.replace("src", "dist"));
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
const { execSync } = require("child_process");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
const { execIn, parts, getDirs, walk, sanitizeVarName } = require("../utils");
|
||||
|
||||
module.exports = function (config) {
|
||||
console.log(`==> Remapping module imports...`);
|
||||
let files = walk(config.distDir).filter((x) => x.endsWith(".js"));
|
||||
files.forEach((x) => {
|
||||
let fc = fs.readFileSync(x).toString();
|
||||
fc = fc.replaceAll("@fosscord/", "#");
|
||||
fs.writeFileSync(x, fc);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
const { execSync } = require("child_process");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
const { execIn, parts, getDirs, walk, sanitizeVarName } = require("./utils");
|
||||
|
||||
//file paths
|
||||
const rootDir = path.join(__dirname, "..");
|
||||
const srcDir = path.join(rootDir, "src");
|
||||
const distDir = path.join(rootDir, "dist");
|
||||
const scriptsDir = path.join(rootDir, "scripts");
|
||||
const configPath = path.join(rootDir, "build.json");
|
||||
const buildLog = path.join(rootDir, "build.log");
|
||||
const buildLogAnsi = path.join(rootDir, "build.log.ansi");
|
||||
const pluginDir = path.join(srcDir, "plugins");
|
||||
|
||||
//more, dont export
|
||||
const buildStepDir = path.join(scriptsDir, "build");
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
if (!fs.existsSync(path.join(configPath + ".default"))) {
|
||||
console.log("build.json.default not found! Exiting!");
|
||||
exit(1);
|
||||
}
|
||||
fs.copyFileSync(configPath + ".default", configPath);
|
||||
}
|
||||
let config = { rootDir, srcDir, distDir, configPath, buildLog, buildLogAnsi, pluginDir, ...require(configPath) };
|
||||
|
||||
config.steps.pre.forEach((step) => require(path.join(buildStepDir, step))(config));
|
||||
require(path.join(buildStepDir, "compile_" + config.compiler))(config);
|
||||
config.steps.post.forEach((step) => require(path.join(buildStepDir, step))(config));
|
||||
@@ -0,0 +1,75 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs").promises;
|
||||
const { execIn, getLines, walk, projectRoot } = require("./utils");
|
||||
|
||||
let printTodos = process.argv.includes("TODOS");
|
||||
|
||||
let root = path.resolve(path.join(__dirname, "..", "src"));
|
||||
let files = walk(root);
|
||||
let _files = [];
|
||||
let errors = 0,
|
||||
warnings = 0,
|
||||
todos = 0;
|
||||
|
||||
Promise.all(files.map(getFile)).then((f) => {
|
||||
Promise.all(Object.keys(_files).map(checkFile));
|
||||
console.log(`\n${errors} errors, ${warnings} warnings, ${todos} TODOs.`);
|
||||
|
||||
let loc = 0;
|
||||
Object.values(_files).forEach((x) => {
|
||||
loc += x.length;
|
||||
});
|
||||
console.log("\nStats:\n");
|
||||
console.log(`Lines of code: ${loc} lines in ${Object.values(_files).length} files.`);
|
||||
|
||||
debugger;
|
||||
});
|
||||
|
||||
async function getFile(name) {
|
||||
let contents = (await fs.readFile(name)).toString().split("\n");
|
||||
_files[name] = contents;
|
||||
}
|
||||
|
||||
async function checkFile(x) {
|
||||
_files[x].forEach((line) => scanLine(x, line));
|
||||
}
|
||||
|
||||
function log(file, line, msg) {
|
||||
let lineNum = _files[file].indexOf(line) + 1;
|
||||
console.log(msg, "File:", file.replace(root + "/", "") + ":" + lineNum);
|
||||
}
|
||||
|
||||
function scanLine(x, line) {
|
||||
if (/import/.test(line)) {
|
||||
if (/import {?.*}? from '.*'/.test(line)) {
|
||||
log(x, line, `[WARN] Inconsistent import syntax, please use double quotes!`);
|
||||
warnings++;
|
||||
}
|
||||
} else {
|
||||
if (line.trim().endsWith("TODO:")) {
|
||||
log(x, line, `[ERRO] Empty TODO!`);
|
||||
errors++;
|
||||
} else if (/\/\/\s{0,3}TODO:/.test(line)) {
|
||||
if (printTodos) log(x, line, `[TODO] Found a TODO: ${line.split("TODO:")[1].trim()}.`);
|
||||
todos++;
|
||||
}
|
||||
if (/(:|=)/.test(line)) {
|
||||
if (/(:|=) {2,}/.test(line)) {
|
||||
log(x, line, `[WARN] Multiple spaces in assignment!`);
|
||||
warnings++;
|
||||
}
|
||||
if (/(:|=)\t'/.test(line)) {
|
||||
log(x, line, `[WARN] Tab in assignment!`);
|
||||
warnings++;
|
||||
}
|
||||
if (/(:|=)\w'/.test(line)) {
|
||||
log(x, line, `[WARN] Missing space in assignment!`);
|
||||
warnings++;
|
||||
}
|
||||
if (/(:|=) undefined/.test(line) && !/(:|=){2,} undefined/.test(line)) {
|
||||
log(x, line, `[WARN] Use of undefined!`);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/node
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { stdout, exit } = require("process");
|
||||
const { execIn } = require("./utils.js");
|
||||
const { ask } = require("./utils/ask.js");
|
||||
|
||||
async function main() {
|
||||
let filename;
|
||||
if(process.argv[2]) filename = process.argv[2];
|
||||
else filename = await ask("Please enter the name of your migration: ");
|
||||
let dbconf;
|
||||
try {
|
||||
dbconf = JSON.parse(fs.readFileSync("dbconf.json"));
|
||||
} catch (e) {
|
||||
console.log("No dbconf.json found!");
|
||||
dbconf = {};
|
||||
}
|
||||
|
||||
if(!dbconf["sqlite"])
|
||||
dbconf.sqlite = {
|
||||
conn_str: "migrations.db",
|
||||
migrations_dir: "sqlite",
|
||||
package: "sqlite3"
|
||||
}
|
||||
if(!dbconf["postgres"] && process.env.FC_DB_POSTGRES) {
|
||||
console.log("Found FC_DB_POSTGRES environment variable. Using it!");
|
||||
dbconf.postgres = {
|
||||
conn_str: process.env.FC_DB_POSTGRES,
|
||||
migrations_dir: "postgres",
|
||||
package: "pg"
|
||||
}
|
||||
}
|
||||
if(!dbconf["mariadb"] && process.env.FC_DB_MARIADB){
|
||||
console.log("Found FC_DB_MARIADB environment variable. Using it!");
|
||||
dbconf.mariadb = {
|
||||
conn_str: process.env.FC_DB_MARIADB,
|
||||
migrations_dir: "mariadb",
|
||||
package: "mysql2"
|
||||
}
|
||||
}
|
||||
fs.writeFileSync("dbconf.json", JSON.stringify(dbconf, null, 4));
|
||||
|
||||
//build
|
||||
execIn(`node scripts/build_new.js`, process.cwd(), {stdio: "inherit"});
|
||||
|
||||
if(fs.existsSync(".env") && !fs.existsSync(".env.bak"))
|
||||
fs.renameSync(".env", ".env.bak");
|
||||
Object.keys(dbconf).forEach((db) => {
|
||||
console.log(`Applying migrations for ${db}`);
|
||||
if(!fs.existsSync(path.join("node_modules", dbconf[db].package)))
|
||||
execIn(`npm i ${dbconf[db].package}`, process.cwd());
|
||||
fs.writeFileSync(
|
||||
`.env`,
|
||||
`DATABASE=${dbconf[db].conn_str}
|
||||
THREADS=1
|
||||
DB_MIGRATE=true
|
||||
DB_VERBOSE=true`
|
||||
);
|
||||
execIn(`node dist/start.js`, process.cwd(), {stdio: "inherit"});
|
||||
});
|
||||
|
||||
Object.keys(dbconf).forEach((db) => {
|
||||
console.log(`Generating new migrations for ${db}`);
|
||||
fs.writeFileSync(
|
||||
`.env`,
|
||||
`DATABASE=${dbconf[db].conn_str}
|
||||
THREADS=1
|
||||
DB_MIGRATE=true
|
||||
DB_VERBOSE=true`
|
||||
);
|
||||
execIn(`node node_modules/typeorm/cli.js migration:generate "src/util/migrations/${db}/${filename}" -d dist/util/util/Database.js -p`, process.cwd(), {stdio: "inherit"});
|
||||
});
|
||||
if(fs.existsSync(".env.bak")) {
|
||||
fs.rmSync(".env");
|
||||
fs.renameSync(".env.bak", ".env");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
main();
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -z "$1" ]
|
||||
then
|
||||
FILENAME="$1"
|
||||
echo "Using filename: $FILENAME"
|
||||
else
|
||||
read -p "Enter migration filename: " FILENAME
|
||||
fi
|
||||
|
||||
[ -f ".env" ] && (
|
||||
mv .env .env.tmp 2>/dev/null
|
||||
source .env.tmp 2>/dev/null
|
||||
)
|
||||
npm run build clean logerrors pretty-errors
|
||||
|
||||
make_migration() {
|
||||
echo "Creating migrations for $2"
|
||||
mkdir "src/util/migrations/$2" 2>/dev/null
|
||||
# npm run build clean logerrors pretty-errors
|
||||
THREADS=1 DATABASE="$1" DB_MIGRATE=a npm run start:bundle
|
||||
THREADS=1 DATABASE="$1" DB_MIGRATE=a npx typeorm-ts-node-commonjs migration:generate "src/util/migrations/$2/$FILENAME" -d src/util/util/Database.ts -p
|
||||
#npm run build clean logerrors pretty-errors
|
||||
#THREADS=1 DATABASE="$1" DB_MIGRATE=a npm run start:bundle
|
||||
}
|
||||
|
||||
npm i sqlite3
|
||||
make_migration "database.db" "sqlite"
|
||||
|
||||
[ -z "$FC_DB_POSTGRES" ] || (
|
||||
npm i pg
|
||||
make_migration "$FC_DB_POSTGRES" "postgres"
|
||||
)
|
||||
|
||||
[ -z "$FC_DB_MARIADB" ] || (
|
||||
npm i mysql2
|
||||
make_migration "$FC_DB_MARIADB" "mariadb"
|
||||
)
|
||||
|
||||
[ -f ".env.tmp" ] && mv .env.tmp .env 2>/dev/null
|
||||
|
||||
+19
-25
@@ -9,22 +9,22 @@ const { execIn, getLines } = require("./utils");
|
||||
let npmi_extra_flags = "";
|
||||
|
||||
const resolveminor = argv.includes("resolveminor");
|
||||
if(argv.includes("nobuild")) npmi_extra_flags += "--ignore-scripts ";
|
||||
if (argv.includes("nobuild")) npmi_extra_flags += "--ignore-scripts ";
|
||||
|
||||
parts.forEach((part) => {
|
||||
let partDir = path.join(__dirname, "..", "..", part);
|
||||
let distDir = path.join(partDir, "dist");
|
||||
console.log(`Checking updates for ${part} (${partDir})`);
|
||||
if(part == "bundle") {
|
||||
execIn(`npm run syncdeps`, partDir)
|
||||
if (part == "bundle") {
|
||||
execIn(`npm run syncdeps`, partDir);
|
||||
}
|
||||
if(resolveminor) {
|
||||
fs.rmSync(path.join(partDir, "node_modules"), {
|
||||
if (resolveminor) {
|
||||
fs.rmSync(path.join(partDir, "node_modules"), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
force: true
|
||||
});
|
||||
execIn(`npm i --save --no-fund --no-audit --no-package-lock ${npmi_extra_flags}`, partDir)
|
||||
}
|
||||
execIn(`npm i --save --no-fund --no-audit --no-package-lock ${npmi_extra_flags}`, partDir);
|
||||
}
|
||||
let x = [
|
||||
[
|
||||
"pkg",
|
||||
@@ -33,24 +33,18 @@ parts.forEach((part) => {
|
||||
wanted: "2.0",
|
||||
latest: "2.0",
|
||||
dependent: "cdn",
|
||||
location: "/usr/src/fosscord/bundle/node_packages/pkg",
|
||||
},
|
||||
],
|
||||
location: "/usr/src/fosscord/bundle/node_packages/pkg"
|
||||
}
|
||||
]
|
||||
];
|
||||
x = Object.entries(
|
||||
JSON.parse(execIn("npm outdated --json", partDir))
|
||||
);
|
||||
x = Object.entries(JSON.parse(execIn("npm outdated --json", partDir)));
|
||||
x.forEach((a) => {
|
||||
let pkgname = a[0];
|
||||
let pkginfo = a[1];
|
||||
if(!pkginfo.current)
|
||||
console.log(`MISSING ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted} (latest: ${pkginfo.latest})`);
|
||||
else if(pkginfo.latest != pkginfo.wanted){
|
||||
if(pkginfo.current != pkginfo.wanted)
|
||||
console.log(`MINOR ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
|
||||
console.log(`MAJOR ${pkgname}: ${pkginfo.current} -> ${pkginfo.latest}`);
|
||||
}
|
||||
else
|
||||
console.log(`MINOR ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
|
||||
let pkgname = a[0];
|
||||
let pkginfo = a[1];
|
||||
if (!pkginfo.current) console.log(`MISSING ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted} (latest: ${pkginfo.latest})`);
|
||||
else if (pkginfo.latest != pkginfo.wanted) {
|
||||
if (pkginfo.current != pkginfo.wanted) console.log(`MINOR ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
|
||||
console.log(`MAJOR ${pkgname}: ${pkginfo.current} -> ${pkginfo.latest}`);
|
||||
} else console.log(`MINOR ${pkgname}: ${pkginfo.current} -> ${pkginfo.wanted}`);
|
||||
});
|
||||
});
|
||||
|
||||
+8
-17
@@ -3,8 +3,7 @@ const fs = require("fs");
|
||||
const { env } = require("process");
|
||||
const { execSync } = require("child_process");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
|
||||
const { execIn, getLines } = require('./utils');
|
||||
const { execIn, getLines } = require("./utils");
|
||||
|
||||
const bundleRequired = ["@ovos-media/ts-transform-paths"];
|
||||
const removeModules = argv.includes("cleanup");
|
||||
@@ -15,13 +14,11 @@ execIn("npm i", path.join(__dirname, ".."));
|
||||
let partDir = path.join(__dirname, "..");
|
||||
let distDir = path.join(partDir, "dist");
|
||||
let start = 0;
|
||||
start = getLines(
|
||||
execIn("npm ls --parseable --package-lock-only -a", partDir)
|
||||
);
|
||||
start = getLines(execIn("npm ls --parseable --package-lock-only -a", partDir));
|
||||
if (fs.existsSync(distDir))
|
||||
fs.rmSync(distDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
force: true
|
||||
});
|
||||
let x = {
|
||||
dependencies: [],
|
||||
@@ -29,17 +26,13 @@ let x = {
|
||||
invalidDirs: [],
|
||||
invalidFiles: [],
|
||||
missing: [],
|
||||
using: [],
|
||||
using: []
|
||||
};
|
||||
let dcproc = execIn("npx depcheck --json", partDir);
|
||||
if(dcproc.stdout) x = JSON.parse(dcproc.stdout);
|
||||
if (dcproc.stdout) x = JSON.parse(dcproc.stdout);
|
||||
else x = JSON.parse(dcproc);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(__dirname, "..", `depclean.out.json`),
|
||||
JSON.stringify(x, null, "\t"),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
fs.writeFileSync(path.join(__dirname, "..", `depclean.out.json`), JSON.stringify(x, null, "\t"), { encoding: "utf8" });
|
||||
|
||||
let depsToRemove = x.dependencies.join(" ");
|
||||
if (depsToRemove) execIn(`npm r --save ${depsToRemove}`, partDir);
|
||||
@@ -50,11 +43,9 @@ if (depsToRemove) execIn(`npm r --save --dev ${depsToRemove}`, partDir);
|
||||
if (removeModules && fs.existsSync(path.join(partDir, "node_modules")))
|
||||
fs.rmSync(path.join(partDir, "node_modules"), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
force: true
|
||||
});
|
||||
let end = getLines(
|
||||
execIn("npm ls --parseable --package-lock-only -a", partDir)
|
||||
);
|
||||
let end = getLines(execIn("npm ls --parseable --package-lock-only -a", partDir));
|
||||
console.log(`${part}: ${start} -> ${end} (diff: ${start - end})`);
|
||||
|
||||
console.log("Installing required packages for bundle...");
|
||||
|
||||
Executable
+272
@@ -0,0 +1,272 @@
|
||||
#!/usr/bin/node
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { stdout, exit } = require("process");
|
||||
const { execIn } = require("./utils.js");
|
||||
const { ask } = require("./utils/ask.js");
|
||||
|
||||
|
||||
const data = { env: [], config: { register: {} }, extra_pkgs: [] };
|
||||
let rights = [];
|
||||
|
||||
process.on("SIGINT", function () {
|
||||
console.log("Caught interrupt signal");
|
||||
process.exit();
|
||||
});
|
||||
|
||||
console.log("Welcome to Fosscord!");
|
||||
console.log("Please remember this is pre-release software!");
|
||||
console.log("We will guide you through some important setup steps.");
|
||||
console.log();
|
||||
|
||||
if (fs.existsSync("package-lock.json")) fs.rmSync("package-lock.json");
|
||||
if (fs.existsSync("yarn.lock")) fs.rmSync("yarn.lock");
|
||||
|
||||
async function main() {
|
||||
printTitle("Step 1: Database setup");
|
||||
console.log("1. PostgreSQL (recommended)");
|
||||
console.log("2. MariaDB/MySQL");
|
||||
console.log("3. SQLite (not recommended, but good for a simple test)");
|
||||
|
||||
while (!data.db) {
|
||||
let answer = await ask("Please select a database type: ");
|
||||
if (answer == "1") {
|
||||
data.db = "postgres";
|
||||
data.extra_pkgs.push("pg");
|
||||
} else if (answer == "2") {
|
||||
data.db = "mariadb";
|
||||
data.extra_pkgs.push("mysql2");
|
||||
} else if (answer == "3") {
|
||||
data.db = "sqlite";
|
||||
data.extra_pkgs.push("sqlite3");
|
||||
} else {
|
||||
console.log("Invalid choice!");
|
||||
}
|
||||
}
|
||||
|
||||
printTitle("Step 2: Database credentials");
|
||||
if (data.db != "sqlite") {
|
||||
console.log("Please enter your database credentials.");
|
||||
console.log("You can leave the password field empty if you don't want to set a password.");
|
||||
console.log();
|
||||
while (!data.db_host) {
|
||||
data.db_host = await ask("Host: ");
|
||||
}
|
||||
while (!data.db_port) {
|
||||
data.db_port = await ask("Port: ");
|
||||
}
|
||||
while (!data.db_user) {
|
||||
data.db_user = await ask("Username: ");
|
||||
}
|
||||
while (!data.db_pass) {
|
||||
data.db_pass = await ask("Password: ");
|
||||
}
|
||||
while (!data.db_name) {
|
||||
data.db_name = await ask("Database name: ");
|
||||
}
|
||||
} else {
|
||||
console.log("SQLite does not use credentials...");
|
||||
}
|
||||
|
||||
printTitle("Step 3: Domain setup");
|
||||
console.log("Please enter your domain.");
|
||||
console.log("You can leave the port field empty if you don't want to set a port.");
|
||||
console.log();
|
||||
|
||||
data.domain = await ask("Domain (default=localhost): ");
|
||||
if (!data.domain) data.domain = "localhost";
|
||||
else data.ssl = /y?/i.test(await ask("SSL/HTTPS (Y/n): "));
|
||||
|
||||
data.port = await ask("Port (default=3001): ");
|
||||
if (!data.port) data.port = "3001";
|
||||
|
||||
if (data.db != "sqlite")
|
||||
data.env.push(`DATABASE=${data.db}://${data.db_user}:${data.db_pass}@${data.db_host}:${data.db_port}/${data.db_name}`);
|
||||
data.env.push(`PORT=${data.port}`);
|
||||
data.env.push("THREADS=1");
|
||||
|
||||
printTitle("Step 4: Default rights");
|
||||
console.log("Please enter the default rights for new users.");
|
||||
console.log("Valid rights are: none, discord, full, custom.");
|
||||
console.log();
|
||||
let lines = fs.readFileSync(path.join(__dirname, "..", "src", "util", "util", "Rights.ts")).toString();
|
||||
let lines2 = lines.split("\n");
|
||||
let lines3 = lines2.filter((y) => y.includes(": BitFlag("));
|
||||
let lines4 = lines3.map((x) => x.split("//")[0].trim());
|
||||
|
||||
let maxRights = 0n;
|
||||
lines4.forEach((x) => {
|
||||
maxRights += eval(`rights.${x.replace(":", " = ").replace(",", ";")}`);
|
||||
});
|
||||
discordRights = maxRights;
|
||||
discordRights -= rights.SEND_BACKDATED_EVENTS;
|
||||
discordRights -= rights.MANAGE_GUILD_DIRECTORY;
|
||||
discordRights -= rights.CREDITABLE;
|
||||
discordRights -= rights.BYPASS_RATE_LIMITS;
|
||||
discordRights -= rights.ADD_MEMBERS;
|
||||
discordRights -= rights.MANAGE_RATE_LIMITS;
|
||||
discordRights -= rights.OPERATOR;
|
||||
|
||||
data.default_rights = await ask("Rights (default=none): ");
|
||||
if (!data.default_rights || data.defaultRights == "none") data.config.register.defaultRights = "0";
|
||||
else if (data.default_rights == "discord") data.config.register.defaultRights = discordRights.toString();
|
||||
else if (data.default_rights == "full") data.config.register.defaultRights = maxRights.toString();
|
||||
else if (data.default_rights == "custom") data.config.register.defaultRights = (await askRights()).toString();
|
||||
|
||||
if (data.domain != "localhost")
|
||||
data.config = {
|
||||
cdn: {
|
||||
endpointPrivate: `http://localhost:${data.port}`,
|
||||
endpointPublic: `${data.ssl ? "https" : "http"}://${data.domain}:${data.port}`
|
||||
},
|
||||
gateway: {
|
||||
endpointPrivate: `ws://localhost:${data.port}`,
|
||||
endpointPublic: `${data.ssl ? "wss" : "ws"}://${data.domain}:${data.port}`
|
||||
},
|
||||
...data.config
|
||||
};
|
||||
printTitle("Step 5: extra options");
|
||||
|
||||
if (/y?/i.test(await ask("Use fast BCrypt implementation (requires a compiler) (Y/n): "))) data.extra_pkgs.push("bcrypt");
|
||||
if (/y?/i.test(await ask("Enable support for widgets (requires compiler, known to fail on some ARM devices.) (Y/n): ")))
|
||||
data.extra_pkgs.push("canvas");
|
||||
|
||||
printTitle("Step 6: finalizing...");
|
||||
//save
|
||||
console.log("==> Writing .env...");
|
||||
fs.writeFileSync(".env", data.env.join("\n"));
|
||||
console.log("==> Writing initial.json");
|
||||
fs.writeFileSync("initial.json", JSON.stringify(data.config, (space = 4)));
|
||||
//install packages...
|
||||
console.log("==> Installing packages...");
|
||||
console.log(" ==> Ensuring yarn is up to date (v3, not v1)...");
|
||||
execIn("npx yarn set version stable", process.cwd());
|
||||
console.log(" ==> Installing base packages");
|
||||
execIn("npx --yes yarn install", process.cwd(), { stdio: "inherit" });
|
||||
if (data.extra_pkgs.length > 0) {
|
||||
console.log(" ==> Checking dependencies...");
|
||||
checkCompilers();
|
||||
if (data.extra_pkgs.includes("canvas")) checkCanvasDeps();
|
||||
if (data.extra_pkgs.includes("bcrypt")) checkBcryptDeps();
|
||||
|
||||
console.log(` ==> Installing extra packages: ${data.extra_pkgs.join(", ")}...`);
|
||||
execIn(`npx --yes yarn add -O ${data.extra_pkgs.join(" ")}`, process.cwd(), { stdio: "inherit" });
|
||||
}
|
||||
|
||||
console.log("==> Building...");
|
||||
execIn("npx --yes yarn run build", process.cwd(), { stdio: "inherit" });
|
||||
printTitle("Step 6: run your instance!");
|
||||
console.log("Installation is complete!");
|
||||
console.log("You can now start your instance by running 'npm run start:bundle'!");
|
||||
exit(0);
|
||||
}
|
||||
main();
|
||||
|
||||
async function askRights() {
|
||||
let w = 0;
|
||||
let brights = { ...eval(`rights`) };
|
||||
Object.keys(rights).forEach((x) => {
|
||||
brights[x] = false;
|
||||
let str = `[x] ${Object.keys(rights).length}: ${x}`;
|
||||
if (str.length > w) w = str.length;
|
||||
});
|
||||
|
||||
let resp = "";
|
||||
let selectedRights = 0n;
|
||||
while (resp != "q") {
|
||||
selectedRights = 0n;
|
||||
Object.keys(brights).forEach((x) => {
|
||||
if (brights[x]) selectedRights += rights[x];
|
||||
});
|
||||
console.clear();
|
||||
printTitle("Step 4: Default rights");
|
||||
printTitle(`Current rights: ${selectedRights} (0b${selectedRights.toString(2)}, 0x${selectedRights.toString(16)})`);
|
||||
let xpos = 0;
|
||||
Object.keys(rights).forEach((x) => {
|
||||
let str = `[${brights[x] ? "X" : " "}] ${Object.keys(rights).indexOf(x)}: ${x}`.padEnd(w + 1, " ");
|
||||
if (xpos + str.length > stdout.columns) {
|
||||
console.log();
|
||||
xpos = 0;
|
||||
}
|
||||
stdout.write(str);
|
||||
xpos += str.length;
|
||||
});
|
||||
|
||||
console.log();
|
||||
resp = await ask("Enter an option, or q to exit: ");
|
||||
if (/\d{1,}/.test(resp) && resp < Object.keys(rights).length && resp > -1) {
|
||||
brights[Object.keys(brights)[parseInt(resp)]] ^= true;
|
||||
}
|
||||
}
|
||||
return selectedRights;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function printTitle(input) {
|
||||
let width = stdout.columns / 2 - 1; //40
|
||||
console.log();
|
||||
console.log("-".repeat(width - input.length / 2), input, "-".repeat(width - input.length / 2));
|
||||
console.log();
|
||||
}
|
||||
|
||||
|
||||
function BitFlag(int) {
|
||||
return 1n << BigInt(int);
|
||||
}
|
||||
|
||||
function checkCanvasDeps() {
|
||||
if (
|
||||
!(
|
||||
checkDep("pixman", "/usr/include/pixman-1/pixman.h") &&
|
||||
checkDep("pixman", "/usr/lib/libpixman-1.so") &&
|
||||
checkDep("cairo", "/usr/include/cairo/cairo.h") &&
|
||||
checkDep("cairo", "/usr/lib/libcairo.so") &&
|
||||
checkDep("pango", "/usr/include/pango-1.0/pango/pangocairo.h") &&
|
||||
checkDep("pango", "/usr/lib/libpango-1.0.so") &&
|
||||
checkDep("pkgconfig", "/usr/bin/pkg-config")
|
||||
)
|
||||
) {
|
||||
console.log("Canvas requires the following dependencies to be installed: pixman, cairo, pango, pkgconfig");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
function checkBcryptDeps() {
|
||||
/*if (!(checkDep("bcrypt", "/usr/include/bcrypt.h") && checkDep("bcrypt", "/usr/lib/libbcrypt.so"))) {
|
||||
console.log("Bcrypt requires the following dependencies to be installed: bcrypt");
|
||||
exit(1);
|
||||
}*/
|
||||
//TODO: check if required
|
||||
}
|
||||
|
||||
function checkCompilers() {
|
||||
//check for gcc, grep, make, python-is-python3
|
||||
if (
|
||||
!(
|
||||
checkDep("gcc", "/usr/bin/gcc") &&
|
||||
checkDep("grep", "/usr/bin/grep") &&
|
||||
checkDep("make", "/usr/bin/make") &&
|
||||
checkDep("python3", "/usr/bin/python3")
|
||||
)
|
||||
) {
|
||||
console.log("Compiler requirements not met. Please install the following: gcc, grep, make, python3");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//check if /usr/bin/python is a symlink to /usr/bin/python3
|
||||
if (!fs.lstatSync("/usr/bin/python").isSymbolicLink()) {
|
||||
console.log("/usr/bin/python is not a symlink. Please make sure it is a symlink to /usr/bin/python3");
|
||||
if (fs.existsSync("/usr/bin/python3")) {
|
||||
console.log("Hint: sudo ln -s /usr/bin/python3 /usr/bin/python");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function checkDep(name, path, message) {
|
||||
if (!fs.existsSync(path)) {
|
||||
console.log(`${name} not found at ${path}! Installation of some modules may fail!`);
|
||||
console.log(message ?? `Please consult your distro's manual for installation instructions.`);
|
||||
}
|
||||
return fs.existsSync(path);
|
||||
}
|
||||
+25
-22
@@ -1,34 +1,37 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const { execIn, getLines, parts } = require('./utils');
|
||||
const { execIn, getLines } = require("./utils");
|
||||
|
||||
if (!process.argv[2] || !fs.existsSync(process.argv[2])) {
|
||||
console.log("Please pass a directory that exists!");
|
||||
process.exit(1);
|
||||
console.log("Please pass a directory that exists!");
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`// ${process.argv[2]}/index.ts`)
|
||||
const recurse = process.argv.includes("--recursive")
|
||||
console.log(`// ${process.argv[2]}/index.ts`);
|
||||
const recurse = process.argv.includes("--recursive");
|
||||
|
||||
const files = fs.readdirSync(process.argv[2]).filter(x => x.endsWith('.ts') && x != 'index.ts');
|
||||
const files = fs.readdirSync(process.argv[2]).filter((x) => x.endsWith(".ts") && x != "index.ts");
|
||||
|
||||
let output = '';
|
||||
let output = "";
|
||||
|
||||
files.forEach(x => output += `export * from "./${x.replaceAll('.ts','')}";\n`)
|
||||
files.forEach((x) => (output += `export * from "./${x.replaceAll(".ts", "")}";\n`));
|
||||
|
||||
const dirs = fs.readdirSync(process.argv[2]).filter(x => {
|
||||
try {
|
||||
fs.readdirSync(path.join(process.argv[2], x));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
const dirs = fs.readdirSync(process.argv[2]).filter((x) => {
|
||||
try {
|
||||
fs.readdirSync(path.join(process.argv[2], x));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
dirs.forEach((x) => {
|
||||
output += `export * from "./${x}/index";\n`;
|
||||
});
|
||||
dirs.forEach(x => {
|
||||
output += `export * from "./${x}/index";\n`
|
||||
})
|
||||
console.log(output);
|
||||
fs.writeFileSync(path.join(process.argv[2], "index.ts"), output)
|
||||
fs.writeFileSync(path.join(process.argv[2], "index.ts"), output);
|
||||
|
||||
dirs.forEach(x => {
|
||||
if(recurse) console.log(execIn([process.argv[0], process.argv[1], `"${path.join(process.argv[2], x)}"`, "--recursive"].join(' '), process.cwd()))
|
||||
})
|
||||
dirs.forEach((x) => {
|
||||
if (recurse)
|
||||
console.log(
|
||||
execIn([process.argv[0], process.argv[1], `"${path.join(process.argv[2], x)}"`, "--recursive"].join(" "), process.cwd())
|
||||
);
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ const Excluded = [
|
||||
"UncheckedPropertiesSchema",
|
||||
"PropertiesSchema",
|
||||
"AsyncSchema",
|
||||
"AnySchema",
|
||||
"AnySchema"
|
||||
];
|
||||
|
||||
function modify(obj) {
|
||||
@@ -48,13 +48,8 @@ function modify(obj) {
|
||||
}
|
||||
|
||||
function main() {
|
||||
const files = [
|
||||
...walk(path.join(__dirname, "..", "src", "util", "schemas")),
|
||||
];
|
||||
const program = TJS.getProgramFromFiles(
|
||||
files,
|
||||
compilerOptions
|
||||
);
|
||||
const files = [...walk(path.join(__dirname, "..", "src", "util", "schemas"))];
|
||||
const program = TJS.getProgramFromFiles(files, compilerOptions);
|
||||
const generator = TJS.buildGenerator(program, settings);
|
||||
if (!generator || !program) return;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ const {
|
||||
Template,
|
||||
User,
|
||||
VoiceState,
|
||||
Webhook,
|
||||
Webhook
|
||||
} = require("../../dist/entities/index");
|
||||
|
||||
async function main() {
|
||||
@@ -54,7 +54,7 @@ async function main() {
|
||||
VoiceState,
|
||||
Webhook,
|
||||
Message,
|
||||
Attachment,
|
||||
Attachment
|
||||
];
|
||||
|
||||
const oldDB = await initDatabase();
|
||||
@@ -69,7 +69,7 @@ async function main() {
|
||||
database: isSqlite ? process.env.TO : undefined,
|
||||
entities,
|
||||
name: "new",
|
||||
synchronize: true,
|
||||
synchronize: true
|
||||
});
|
||||
let i = 0;
|
||||
|
||||
|
||||
+9
-9
@@ -6,20 +6,20 @@ const { argv, stdout, exit } = require("process");
|
||||
|
||||
const { execIn, getLines, parts } = require("./utils");
|
||||
|
||||
let lines = fs.readFileSync(path.join(__dirname, "..", "src", "util", "util","Rights.ts")).toString()
|
||||
let lines = fs.readFileSync(path.join(__dirname, "..", "src", "util", "util", "Rights.ts")).toString();
|
||||
let lines2 = lines.split("\n");
|
||||
let lines3 = lines2.filter(y=>y.includes(": BitFlag("));
|
||||
let lines4 = lines3.map(x=>x.split("//")[0].trim())
|
||||
let lines3 = lines2.filter((y) => y.includes(": BitFlag("));
|
||||
let lines4 = lines3.map((x) => x.split("//")[0].trim());
|
||||
|
||||
function BitFlag(int) {
|
||||
return 1n << eval(`${int}n`);
|
||||
return 1n << BigInt(int);
|
||||
}
|
||||
|
||||
let rights = []
|
||||
let rights = [];
|
||||
let maxRights = 0n;
|
||||
lines4.forEach(x=>{
|
||||
maxRights += eval(`rights.${x.replace(':'," = ").replace(",",";")}`)
|
||||
})
|
||||
lines4.forEach((x) => {
|
||||
maxRights += eval(`rights.${x.replace(":", " = ").replace(",", ";")}`);
|
||||
});
|
||||
//max rights...
|
||||
console.log(`Maximum rights: ${maxRights}`);
|
||||
//discord rights...
|
||||
@@ -31,4 +31,4 @@ discordRights -= rights.BYPASS_RATE_LIMITS;
|
||||
discordRights -= rights.ADD_MEMBERS;
|
||||
discordRights -= rights.MANAGE_RATE_LIMITS;
|
||||
discordRights -= rights.OPERATOR;
|
||||
console.log(`Discord-like rights: ${discordRights}`);
|
||||
console.log(`Discord-like rights: ${discordRights}`);
|
||||
|
||||
@@ -6,4 +6,4 @@ const { argv, stdout, exit } = require("process");
|
||||
|
||||
const { execIn, getLines, parts } = require("./utils");
|
||||
|
||||
execIn("node scripts/generate_schema.js", path.join('.'));
|
||||
execIn("node scripts/generate_schema.js", path.join("."));
|
||||
|
||||
+42
-6
@@ -4,6 +4,8 @@ const { env } = require("process");
|
||||
const { execSync } = require("child_process");
|
||||
const { argv, stdout, exit } = require("process");
|
||||
|
||||
const projectRoot = path.resolve(path.join(__dirname, ".."));
|
||||
|
||||
function copyRecursiveSync(src, dest) {
|
||||
//if (verbose) console.log(`cpsync: ${src} -> ${dest}`);
|
||||
let exists = fs.existsSync(src);
|
||||
@@ -16,10 +18,7 @@ function copyRecursiveSync(src, dest) {
|
||||
if (isDirectory) {
|
||||
fs.mkdirSync(dest, { recursive: true });
|
||||
fs.readdirSync(src).forEach(function (childItemName) {
|
||||
copyRecursiveSync(
|
||||
path.join(src, childItemName),
|
||||
path.join(dest, childItemName)
|
||||
);
|
||||
copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
|
||||
});
|
||||
} else {
|
||||
fs.copyFileSync(src, dest);
|
||||
@@ -44,8 +43,45 @@ function getLines(output) {
|
||||
return output.split("\n").length;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
function getDirs(dir) {
|
||||
return fs.readdirSync(dir).filter((x) => {
|
||||
try {
|
||||
fs.readdirSync(dir.join(dir, x));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function walk(dir) {
|
||||
let results = [];
|
||||
let list = fs.readdirSync(dir);
|
||||
list.forEach(function (file) {
|
||||
file = dir + "/" + file;
|
||||
let stat = fs.statSync(file);
|
||||
if (stat && stat.isDirectory()) {
|
||||
/* Recurse into a subdirectory */
|
||||
results = results.concat(walk(file));
|
||||
} else {
|
||||
results.push(file);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
function sanitizeVarName(str) {
|
||||
return str.replace("-", "_").replace(/[^\w\s]/gi, "");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
//consts
|
||||
projectRoot,
|
||||
//functions
|
||||
copyRecursiveSync, execIn, getLines
|
||||
copyRecursiveSync,
|
||||
execIn,
|
||||
getLines,
|
||||
getDirs,
|
||||
walk,
|
||||
sanitizeVarName
|
||||
};
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
const readline = require("readline");
|
||||
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
async function ask(question) {
|
||||
return new Promise((resolve, _reject) => {
|
||||
return rl.question(question, (answer) => {
|
||||
resolve(answer);
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
async function askBool(question) {
|
||||
return /y?/i.test(await ask(question));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ask,
|
||||
askBool
|
||||
}
|
||||
+11
-45
@@ -1,15 +1,15 @@
|
||||
process.on("unhandledRejection", console.error);
|
||||
process.on("uncaughtException", console.error);
|
||||
|
||||
import http from "http";
|
||||
import * as Api from "@fosscord/api";
|
||||
import * as Gateway from "@fosscord/gateway";
|
||||
import { CDNServer } from "@fosscord/cdn";
|
||||
import express from "express";
|
||||
import { green, bold, yellow } from "picocolors";
|
||||
import * as Gateway from "@fosscord/gateway";
|
||||
import { Config, getOrInitialiseDatabase } from "@fosscord/util";
|
||||
import * as Sentry from "@sentry/node";
|
||||
import * as Tracing from "@sentry/tracing";
|
||||
import express from "express";
|
||||
import http from "http";
|
||||
import { bold, green, yellow } from "picocolors";
|
||||
// import { PluginLoader } from "@fosscord/util";
|
||||
|
||||
const app = express();
|
||||
@@ -26,59 +26,25 @@ const cdn = new CDNServer({ server, port, production, app });
|
||||
const gateway = new Gateway.Server({ server, port, production });
|
||||
|
||||
//this is what has been added for the /stop API route
|
||||
process.on('SIGTERM', () => {
|
||||
setTimeout(()=>process.exit(0), 3000)
|
||||
process.on("SIGTERM", () => {
|
||||
setTimeout(() => process.exit(0), 3000);
|
||||
server.close(() => {
|
||||
console.log("Stop API has been successfully POSTed, SIGTERM sent")
|
||||
})
|
||||
})
|
||||
console.log("Stop API has been successfully POSTed, SIGTERM sent");
|
||||
});
|
||||
});
|
||||
//this is what has been added for the /stop API route
|
||||
|
||||
async function main() {
|
||||
server.listen(port);
|
||||
await getOrInitialiseDatabase();
|
||||
await Config.init();
|
||||
// only set endpointPublic, if not already set
|
||||
await Config.set({
|
||||
cdn: {
|
||||
endpointClient: "${location.host}",
|
||||
endpointPrivate: `http://localhost:${port}`,
|
||||
},
|
||||
gateway: {
|
||||
endpointClient:
|
||||
'${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}',
|
||||
endpointPrivate: `ws://localhost:${port}`,
|
||||
...(!Config.get().gateway.endpointPublic && {
|
||||
endpointPublic: `ws://localhost:${port}`,
|
||||
}),
|
||||
},
|
||||
// regions: {
|
||||
// default: "fosscord",
|
||||
// useDefaultAsOptimal: true,
|
||||
// available: [
|
||||
// {
|
||||
// id: "fosscord",
|
||||
// name: "Fosscord",
|
||||
// endpoint: "127.0.0.1:3001",
|
||||
// vip: false,
|
||||
// custom: false,
|
||||
// deprecated: false,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
} as any);
|
||||
|
||||
//Sentry
|
||||
if (Config.get().sentry.enabled) {
|
||||
console.log(
|
||||
`[Bundle] ${yellow("You are using Sentry! This may slightly impact performance on large loads!")}`
|
||||
);
|
||||
console.log(`[Bundle] ${yellow("You are using Sentry! This may slightly impact performance on large loads!")}`);
|
||||
Sentry.init({
|
||||
dsn: Config.get().sentry.endpoint,
|
||||
integrations: [
|
||||
new Sentry.Integrations.Http({ tracing: true }),
|
||||
new Tracing.Integrations.Express({ app }),
|
||||
],
|
||||
integrations: [new Sentry.Integrations.Http({ tracing: true }), new Tracing.Integrations.Express({ app })],
|
||||
tracesSampleRate: Config.get().sentry.traceSampleRate,
|
||||
environment: Config.get().sentry.environment
|
||||
});
|
||||
|
||||
+15
-10
@@ -1,16 +1,16 @@
|
||||
import { Server, ServerOptions } from "lambert-server";
|
||||
import { Authentication, CORS } from "./middlewares/";
|
||||
import { Config, getOrInitialiseDatabase, initEvent, registerRoutes } from "@fosscord/util";
|
||||
import { ErrorHandler } from "./middlewares/ErrorHandler";
|
||||
import { BodyParser } from "./middlewares/BodyParser";
|
||||
import { Router, Request, Response, NextFunction } from "express";
|
||||
import { NextFunction, Request, Response, Router } from "express";
|
||||
import { Server, ServerOptions } from "lambert-server";
|
||||
import morgan from "morgan";
|
||||
import path from "path";
|
||||
import { red } from "picocolors";
|
||||
import { Authentication, CORS } from "./middlewares/";
|
||||
import { BodyParser } from "./middlewares/BodyParser";
|
||||
import { ErrorHandler } from "./middlewares/ErrorHandler";
|
||||
import { initRateLimits } from "./middlewares/RateLimit";
|
||||
import TestClient from "./middlewares/TestClient";
|
||||
import { initTranslation } from "./middlewares/Translation";
|
||||
import morgan from "morgan";
|
||||
import { initInstance } from "./util/handlers/Instance";
|
||||
import { red } from "picocolors"
|
||||
|
||||
export interface FosscordServerOptions extends ServerOptions {}
|
||||
|
||||
@@ -85,8 +85,13 @@ export class FosscordServer extends Server {
|
||||
this.app.use(ErrorHandler);
|
||||
TestClient(this.app);
|
||||
|
||||
if (logRequests) console.log(red(`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`));
|
||||
|
||||
if (logRequests)
|
||||
console.log(
|
||||
red(
|
||||
`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`
|
||||
)
|
||||
);
|
||||
|
||||
return super.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
export * from "./Server";
|
||||
export * from "./middlewares/";
|
||||
export * from "./Server";
|
||||
export * from "./util/";
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { checkToken, Config, HTTPError, Rights } from "@fosscord/util";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { checkToken, Config, Rights } from "@fosscord/util";
|
||||
|
||||
export const NO_AUTHORIZATION_ROUTES = [
|
||||
// Authentication routes
|
||||
@@ -10,7 +9,7 @@ export const NO_AUTHORIZATION_ROUTES = [
|
||||
"/auth/mfa/totp",
|
||||
// Routes with a seperate auth system
|
||||
"/webhooks/",
|
||||
// Public information endpoints
|
||||
// Public information endpoints
|
||||
"/ping",
|
||||
"/gateway",
|
||||
"/experiments",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import bodyParser, { OptionsJson } from "body-parser";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
|
||||
export function BodyParser(opts?: OptionsJson) {
|
||||
const jsonParser = bodyParser.json(opts);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ApiError, FieldError, HTTPError } from "@fosscord/util";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { ApiError, FieldError } from "@fosscord/util";
|
||||
const EntityNotFoundErrorRegex = /"(\w+)"/;
|
||||
|
||||
export function ErrorHandler(error: Error, req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Config, getRights, listenEvent, Rights } from "@fosscord/util";
|
||||
import { NextFunction, Request, Response, Router } from "express";
|
||||
import { getIpAdress } from "@fosscord/api";
|
||||
import { Config, getRights, listenEvent } from "@fosscord/util";
|
||||
import { NextFunction, Request, Response, Router } from "express";
|
||||
import { API_PREFIX_TRAILING_SLASH } from "./Authentication";
|
||||
|
||||
// Docs: https://discord.com/developers/docs/topics/rate-limits
|
||||
@@ -163,7 +163,7 @@ export async function initRateLimits(app: Router) {
|
||||
app.use("/auth/register", rateLimit({ onlyIp: true, success: true, ...routes.auth.register }));
|
||||
}
|
||||
|
||||
async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits: number; window: number; }) {
|
||||
async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits: number; window: number }) {
|
||||
const id = opts.executor_id + opts.bucket_id;
|
||||
let limit = Cache.get(id);
|
||||
if (!limit) {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import express, { Request, Response, Application } from "express";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import fetch, { Response as FetchResponse, Headers } from "node-fetch";
|
||||
import ProxyAgent from 'proxy-agent';
|
||||
import { Config } from "@fosscord/util";
|
||||
import { AssetCacheItem } from "../util/entities/AssetCacheItem"
|
||||
import express, { Application, Request, Response } from "express";
|
||||
import fs from "fs";
|
||||
import fetch, { Headers, Response as FetchResponse } from "node-fetch";
|
||||
import path from "path";
|
||||
import { green } from "picocolors";
|
||||
import ProxyAgent from "proxy-agent";
|
||||
import { AssetCacheItem } from "../util/entities/AssetCacheItem";
|
||||
|
||||
const AssetsPath = path.join(__dirname, "..", "..", "..", "assets")
|
||||
const AssetsPath = path.join(__dirname, "..", "..", "..", "assets");
|
||||
|
||||
export default function TestClient(app: Application) {
|
||||
const agent = new ProxyAgent();
|
||||
|
||||
|
||||
//build client page
|
||||
let html = fs.readFileSync(path.join(AssetsPath, "index.html"), { encoding: "utf8" });
|
||||
html = applyEnv(html);
|
||||
@@ -22,31 +22,29 @@ export default function TestClient(app: Application) {
|
||||
//load asset cache
|
||||
let newAssetCache: Map<string, AssetCacheItem> = new Map<string, AssetCacheItem>();
|
||||
let assetCacheDir = path.join(AssetsPath, "cache");
|
||||
if(process.env.ASSET_CACHE_DIR)
|
||||
assetCacheDir = process.env.ASSET_CACHE_DIR
|
||||
if (process.env.ASSET_CACHE_DIR) assetCacheDir = process.env.ASSET_CACHE_DIR;
|
||||
|
||||
console.log(`[TestClient] ${green(`Using asset cache path: ${assetCacheDir}`)}`)
|
||||
if(!fs.existsSync(assetCacheDir)) {
|
||||
console.log(`[TestClient] ${green(`Using asset cache path: ${assetCacheDir}`)}`);
|
||||
if (!fs.existsSync(assetCacheDir)) {
|
||||
fs.mkdirSync(assetCacheDir);
|
||||
}
|
||||
if(fs.existsSync(path.join(assetCacheDir, "index.json"))) {
|
||||
if (fs.existsSync(path.join(assetCacheDir, "index.json"))) {
|
||||
let rawdata = fs.readFileSync(path.join(assetCacheDir, "index.json"));
|
||||
newAssetCache = new Map<string, AssetCacheItem>(Object.entries(JSON.parse(rawdata.toString())));
|
||||
}
|
||||
|
||||
app.use("/assets", express.static(path.join(AssetsPath)));
|
||||
app.use("/assets", express.static(path.join(AssetsPath)));
|
||||
app.get("/assets/:file", async (req: Request, res: Response) => {
|
||||
delete req.headers.host;
|
||||
let response: FetchResponse;
|
||||
let buffer: Buffer;
|
||||
let assetCacheItem: AssetCacheItem = new AssetCacheItem(req.params.file);
|
||||
if(newAssetCache.has(req.params.file)){
|
||||
if (newAssetCache.has(req.params.file)) {
|
||||
assetCacheItem = newAssetCache.get(req.params.file)!;
|
||||
assetCacheItem.Headers.forEach((value: any, name: any) => {
|
||||
res.set(name, value);
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
console.log(`[TestClient] Downloading file not yet cached! Asset file: ${req.params.file}`);
|
||||
response = await fetch(`https://discord.com/assets/${req.params.file}`, {
|
||||
agent,
|
||||
@@ -55,7 +53,7 @@ export default function TestClient(app: Application) {
|
||||
...req.headers
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//set cache info
|
||||
assetCacheItem.Headers = Object.fromEntries(stripHeaders(response.headers));
|
||||
assetCacheItem.FilePath = path.join(assetCacheDir, req.params.file);
|
||||
@@ -66,7 +64,7 @@ export default function TestClient(app: Application) {
|
||||
//download file
|
||||
fs.writeFileSync(assetCacheItem.FilePath, await response.buffer());
|
||||
}
|
||||
|
||||
|
||||
assetCacheItem.Headers.forEach((value: string, name: string) => {
|
||||
res.set(name, value);
|
||||
});
|
||||
@@ -77,8 +75,8 @@ export default function TestClient(app: Application) {
|
||||
res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24);
|
||||
res.set("content-type", "text/html");
|
||||
|
||||
if(!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.")
|
||||
|
||||
if (!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.");
|
||||
|
||||
res.send(fs.readFileSync(path.join(__dirname, "..", "..", "..", "assets", "developers.html"), { encoding: "utf8" }));
|
||||
});
|
||||
app.get("*", (req: Request, res: Response) => {
|
||||
@@ -86,23 +84,18 @@ export default function TestClient(app: Application) {
|
||||
res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24);
|
||||
res.set("content-type", "text/html");
|
||||
|
||||
if(req.url.startsWith("/api") || req.url.startsWith("/__development")) return;
|
||||
if (req.url.startsWith("/api") || req.url.startsWith("/__development")) return;
|
||||
|
||||
if(!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.")
|
||||
if (!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.");
|
||||
if (req.url.startsWith("/invite")) return res.send(html.replace("9b2b7f0632acd0c5e781", "9f24f709a3de09b67c49"));
|
||||
|
||||
|
||||
res.send(html);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function applyEnv(html: string): string {
|
||||
const CDN_ENDPOINT = (Config.get().cdn.endpointClient || Config.get()?.cdn.endpointPublic || process.env.CDN || "").replace(
|
||||
/(https?)?(:\/\/?)/g,
|
||||
""
|
||||
);
|
||||
const GATEWAY_ENDPOINT = Config.get().gateway.endpointClient || Config.get()?.gateway.endpointPublic || process.env.GATEWAY || "";
|
||||
const CDN_ENDPOINT = (Config.get()?.cdn.endpointPublic || process.env.CDN || "").replace(/(https?)?(:\/\/?)/g, "");
|
||||
const GATEWAY_ENDPOINT = Config.get()?.gateway.endpointPublic || process.env.GATEWAY || "";
|
||||
|
||||
if (CDN_ENDPOINT) {
|
||||
html = html.replace(/CDN_HOST: .+/, `CDN_HOST: \`${CDN_ENDPOINT}\`,`);
|
||||
@@ -117,23 +110,29 @@ function applyPlugins(html: string): string {
|
||||
// plugins
|
||||
let files = fs.readdirSync(path.join(AssetsPath, "plugins"));
|
||||
let plugins = "";
|
||||
files.forEach(x =>{if(x.endsWith(".js")) plugins += `<script src='/assets/plugins/${x}'></script>\n`; });
|
||||
files.forEach((x) => {
|
||||
if (x.endsWith(".js")) plugins += `<script src='/assets/plugins/${x}'></script>\n`;
|
||||
});
|
||||
return html.replaceAll("<!-- plugin marker -->", plugins);
|
||||
}
|
||||
|
||||
function applyInlinePlugins(html: string): string{
|
||||
function applyInlinePlugins(html: string): string {
|
||||
// inline plugins
|
||||
let files = fs.readdirSync(path.join(AssetsPath, "inline-plugins"));
|
||||
let plugins = "";
|
||||
files.forEach(x =>{if(x.endsWith(".js")) plugins += `<script src='/assets/inline-plugins/${x}'></script>\n\n`; });
|
||||
files.forEach((x) => {
|
||||
if (x.endsWith(".js")) plugins += `<script src='/assets/inline-plugins/${x}'></script>\n\n`;
|
||||
});
|
||||
return html.replaceAll("<!-- inline plugin marker -->", plugins);
|
||||
}
|
||||
|
||||
function applyPreloadPlugins(html: string): string{
|
||||
function applyPreloadPlugins(html: string): string {
|
||||
//preload plugins
|
||||
let files = fs.readdirSync(path.join(AssetsPath, "preload-plugins"));
|
||||
let plugins = "";
|
||||
files.forEach(x =>{if(x.endsWith(".js")) plugins += `<script>${fs.readFileSync(path.join(AssetsPath, "preload-plugins", x))}</script>\n`; });
|
||||
files.forEach((x) => {
|
||||
if (x.endsWith(".js")) plugins += `<script>${fs.readFileSync(path.join(AssetsPath, "preload-plugins", x))}</script>\n`;
|
||||
});
|
||||
return html.replaceAll("<!-- preload plugin marker -->", plugins);
|
||||
}
|
||||
|
||||
@@ -147,7 +146,7 @@ function stripHeaders(headers: Headers): Headers {
|
||||
"expect-ct",
|
||||
"access-control-allow-origin",
|
||||
"content-encoding"
|
||||
].forEach(headerName => {
|
||||
].forEach((headerName) => {
|
||||
headers.delete(headerName);
|
||||
});
|
||||
return headers;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Router } from "express";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import i18next from "i18next";
|
||||
import i18nextMiddleware from "i18next-http-middleware";
|
||||
import i18nextBackend from "i18next-node-fs-backend";
|
||||
import { Router } from "express";
|
||||
import path from "path";
|
||||
|
||||
export async function initTranslation(router: Router) {
|
||||
const languages = fs.readdirSync(path.join(__dirname, "..", "..", "..", "assets", "locales"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Application, Config, FieldErrors, generateToken, OrmUtils, Snowflake, trimSpecial, User, handleFile } from "@fosscord/util";
|
||||
import { Application, Config, FieldErrors, generateToken, handleFile, OrmUtils, trimSpecial, User } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { verifyToken } from "node-2fa";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
router.post("/", route({}), async (req: Request, res: Response) => {
|
||||
const app = await Application.findOne({where: {id: req.params.id}});
|
||||
if(!app) return res.status(404);
|
||||
const app = await Application.findOne({ where: { id: req.params.id } });
|
||||
if (!app) return res.status(404);
|
||||
const username = trimSpecial(app.name);
|
||||
const discriminator = await User.generateDiscriminator(username);
|
||||
if (!discriminator) {
|
||||
@@ -16,8 +16,8 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
||||
throw FieldErrors({
|
||||
username: {
|
||||
code: "USERNAME_TOO_MANY_USERS",
|
||||
message: req?.t("auth:register.USERNAME_TOO_MANY_USERS"),
|
||||
},
|
||||
message: req?.t("auth:register.USERNAME_TOO_MANY_USERS")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -47,37 +47,37 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
||||
flags: "0",
|
||||
data: {
|
||||
hash: null,
|
||||
valid_tokens_since: new Date(),
|
||||
valid_tokens_since: new Date()
|
||||
},
|
||||
settings: {},
|
||||
extended_settings: {},
|
||||
fingerprints: [],
|
||||
notes: {},
|
||||
notes: {}
|
||||
});
|
||||
await user.save();
|
||||
app.bot = user;
|
||||
await app.save();
|
||||
res.send().status(204)
|
||||
res.send().status(204);
|
||||
});
|
||||
|
||||
router.post("/reset", route({}), async (req: Request, res: Response) => {
|
||||
let bot = await User.findOne({where: {id: req.params.id}});
|
||||
let owner = await User.findOne({where: {id: req.user_id}});
|
||||
if(!bot) return res.status(404);
|
||||
if(owner?.totp_secret && (!req.body.code || verifyToken(owner.totp_secret, req.body.code))) {
|
||||
let bot = await User.findOne({ where: { id: req.params.id } });
|
||||
let owner = await User.findOne({ where: { id: req.user_id } });
|
||||
if (!bot) return res.status(404);
|
||||
if (owner?.totp_secret && (!req.body.code || verifyToken(owner.totp_secret, req.body.code))) {
|
||||
throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
|
||||
}
|
||||
bot.data = { hash: undefined, valid_tokens_since: new Date() };
|
||||
await bot.save();
|
||||
let token = await generateToken(bot.id);
|
||||
res.json({token}).status(200);
|
||||
res.json({ token }).status(200);
|
||||
});
|
||||
|
||||
router.patch("/", route({}), async (req: Request, res: Response) => {
|
||||
if (req.body.avatar) req.body.avatar = await handleFile(`/avatars/${req.params.id}`, req.body.avatar as string);
|
||||
let app = OrmUtils.mergeDeep(await User.findOne({where: {id: req.params.id}}), req.body);
|
||||
let app = OrmUtils.mergeDeep(await User.findOne({ where: { id: req.params.id } }), req.body);
|
||||
await app.save();
|
||||
res.json(app).status(200);
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util";
|
||||
import { Application, OrmUtils } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
let results = await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"] });
|
||||
let results = await Application.findOne({ where: { id: req.params.id }, relations: ["owner", "bot"] });
|
||||
res.json(results).status(200);
|
||||
});
|
||||
|
||||
router.patch("/", route({}), async (req: Request, res: Response) => {
|
||||
delete req.body.icon;
|
||||
let app = OrmUtils.mergeDeep(await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"]}), req.body);
|
||||
if(app.bot) {
|
||||
app.bot.bio = req.body.description
|
||||
let app = OrmUtils.mergeDeep(await Application.findOne({ where: { id: req.params.id }, relations: ["owner", "bot"] }), req.body);
|
||||
if (app.bot) {
|
||||
app.bot.bio = req.body.description;
|
||||
app.bot?.save();
|
||||
}
|
||||
if(req.body.tags) app.tags = req.body.tags;
|
||||
if (req.body.tags) app.tags = req.body.tags;
|
||||
await app.save();
|
||||
res.json(app).status(200);
|
||||
});
|
||||
@@ -26,5 +26,4 @@ router.post("/delete", route({}), async (req: Request, res: Response) => {
|
||||
res.send().status(200);
|
||||
});
|
||||
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
@@ -8,4 +7,4 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
res.json([]).status(200);
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util";
|
||||
import { Application, OrmUtils, trimSpecial, User } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
@@ -11,14 +11,14 @@ export interface ApplicationCreateSchema {
|
||||
|
||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
//TODO
|
||||
let results = await Application.find({where: {owner: {id: req.user_id}}, relations: ["owner", "bot"] });
|
||||
let results = await Application.find({ where: { owner: { id: req.user_id } }, relations: ["owner", "bot"] });
|
||||
res.json(results).status(200);
|
||||
});
|
||||
|
||||
router.post("/", route({}), async (req: Request, res: Response) => {
|
||||
const body = req.body as ApplicationCreateSchema;
|
||||
const user = await User.findOne({where: {id: req.user_id}})
|
||||
if(!user) res.status(420);
|
||||
const user = await User.findOne({ where: { id: req.user_id } });
|
||||
if (!user) res.status(420);
|
||||
let app = OrmUtils.mergeDeep(new Application(), {
|
||||
name: trimSpecial(body.name),
|
||||
description: "",
|
||||
@@ -31,4 +31,4 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
||||
res.json(app).status(200);
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { getIpAdress, IPAnalysis } from "@fosscord/api";
|
||||
import { getIpAdress, IPAnalysis, route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
const router = Router();
|
||||
|
||||
router.get("/",route({}), async (req: Request, res: Response) => {
|
||||
//TODO
|
||||
//Note: It's most likely related to legal. At the moment Discord hasn't finished this too
|
||||
const country_code = (await IPAnalysis(getIpAdress(req))).country_code;
|
||||
res.json({ consent_required: false, country_code: country_code, promotional_email_opt_in: { required: true, pre_checked: false}});
|
||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
//TODO
|
||||
//Note: It's most likely related to legal. At the moment Discord hasn't finished this too
|
||||
const country_code = (await IPAnalysis(getIpAdress(req))).country_code;
|
||||
res.json({ consent_required: false, country_code: country_code, promotional_email_opt_in: { required: true, pre_checked: false } });
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import bcrypt from "bcrypt";
|
||||
import { Config, User, generateToken, adjustEmail, FieldErrors, LoginSchema } from "@fosscord/util";
|
||||
import { adjustEmail, Config, FieldErrors, generateToken, LoginSchema, User } from "@fosscord/util";
|
||||
import crypto from "crypto";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
let bcrypt: any;
|
||||
try {
|
||||
bcrypt = require("bcrypt");
|
||||
} catch {
|
||||
bcrypt = require("bcryptjs");
|
||||
console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
|
||||
}
|
||||
|
||||
const router: Router = Router();
|
||||
export default router;
|
||||
@@ -57,9 +64,9 @@ router.post("/", route({ body: "LoginSchema" }), async (req: Request, res: Respo
|
||||
return res.json({
|
||||
ticket: ticket,
|
||||
mfa: true,
|
||||
sms: false, // TODO
|
||||
token: null,
|
||||
})
|
||||
sms: false, // TODO
|
||||
token: null
|
||||
});
|
||||
}
|
||||
|
||||
const token = await generateToken(user.id);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { BackupCode, FieldErrors, generateToken, TotpSchema, User } from "@fosscord/util";
|
||||
import { verifyToken } from "node-2fa";
|
||||
import { BackupCode, generateToken, TotpSchema, User } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { verifyToken } from "node-2fa";
|
||||
const router = Router();
|
||||
|
||||
router.post("/", route({ body: "TotpSchema" }), async (req: Request, res: Response) => {
|
||||
@@ -10,23 +10,17 @@ router.post("/", route({ body: "TotpSchema" }), async (req: Request, res: Respon
|
||||
|
||||
const user = await User.findOneOrFail({
|
||||
where: {
|
||||
totp_last_ticket: ticket,
|
||||
totp_last_ticket: ticket
|
||||
},
|
||||
select: [
|
||||
"id",
|
||||
"totp_secret",
|
||||
"settings",
|
||||
],
|
||||
select: ["id", "totp_secret", "settings"]
|
||||
});
|
||||
|
||||
const backup = await BackupCode.findOne({ where: { code: code, expired: false, consumed: false, user: { id: user.id } } });
|
||||
|
||||
if (!backup) {
|
||||
const ret = verifyToken(user.totp_secret!, code);
|
||||
if (!ret || ret.delta != 0)
|
||||
throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
|
||||
}
|
||||
else {
|
||||
if (!ret || ret.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
|
||||
} else {
|
||||
backup.consumed = true;
|
||||
await backup.save();
|
||||
}
|
||||
@@ -35,7 +29,7 @@ router.post("/", route({ body: "TotpSchema" }), async (req: Request, res: Respon
|
||||
|
||||
return res.json({
|
||||
token: await generateToken(user.id),
|
||||
user_settings: user.settings,
|
||||
user_settings: user.settings
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { getIpAdress, IPAnalysis, isProxy, route } from "@fosscord/api";
|
||||
import { adjustEmail, Config, FieldErrors, generateToken, HTTPError, Invite, RegisterSchema, User } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { Config, generateToken, Invite, FieldErrors, User, adjustEmail, trimSpecial, RegisterSchema } from "@fosscord/util";
|
||||
import { route, getIpAdress, IPAnalysis, isProxy } from "@fosscord/api";
|
||||
import bcrypt from "bcrypt";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
|
||||
let bcrypt: any;
|
||||
try {
|
||||
bcrypt = require("bcrypt");
|
||||
} catch {
|
||||
bcrypt = require("bcryptjs");
|
||||
console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
|
||||
}
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Router } from "express";
|
||||
const router: Router = Router();
|
||||
// TODO:
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { route } from "@fosscord/api";
|
||||
import {
|
||||
Channel,
|
||||
ChannelDeleteEvent,
|
||||
ChannelPermissionOverwriteType,
|
||||
ChannelModifySchema,
|
||||
ChannelType,
|
||||
ChannelUpdateEvent,
|
||||
emitEvent,
|
||||
Recipient,
|
||||
handleFile,
|
||||
ChannelModifySchema
|
||||
OrmUtils,
|
||||
Recipient
|
||||
} from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { OrmUtils } from "@fosscord/util";
|
||||
|
||||
const router: Router = Router();
|
||||
// TODO: delete channel
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { random } from "@fosscord/api";
|
||||
import { Channel, Invite, InviteCreateEvent, emitEvent, User, Guild, PublicInviteRelation } from "@fosscord/util";
|
||||
import { Channel, emitEvent, Guild, HTTPError, Invite, InviteCreateEvent, OrmUtils, PublicInviteRelation, User } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { isTextChannel } from "./messages";
|
||||
import { OrmUtils } from "@fosscord/util";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
router.post("/", route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT_INVITE", right: "CREATE_INVITES" }),
|
||||
async (req: Request, res: Response) => {
|
||||
const { user_id } = req;
|
||||
const { channel_id } = req.params;
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id }, select: ["id", "name", "type", "guild_id"] });
|
||||
isTextChannel(channel.type);
|
||||
router.post(
|
||||
"/",
|
||||
route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT_INVITE", right: "CREATE_INVITES" }),
|
||||
async (req: Request, res: Response) => {
|
||||
const { user_id } = req;
|
||||
const { channel_id } = req.params;
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id }, select: ["id", "name", "type", "guild_id"] });
|
||||
isTextChannel(channel.type);
|
||||
|
||||
if (!channel.guild_id) {
|
||||
throw new HTTPError("This channel doesn't exist", 404);
|
||||
if (!channel.guild_id) {
|
||||
throw new HTTPError("This channel doesn't exist", 404);
|
||||
}
|
||||
const { guild_id } = channel;
|
||||
|
||||
const expires_at = new Date(req.body.max_age * 1000 + Date.now());
|
||||
|
||||
const invite = await OrmUtils.mergeDeep(new Invite(), {
|
||||
temporary: req.body.temporary || true,
|
||||
max_uses: req.body.max_uses,
|
||||
max_age: req.body.max_age,
|
||||
expires_at,
|
||||
guild_id,
|
||||
channel_id,
|
||||
inviter_id: user_id
|
||||
}).save();
|
||||
//TODO: check this, removed toJSON call
|
||||
const data = JSON.parse(JSON.stringify(invite));
|
||||
data.inviter = await User.getPublicUser(req.user_id);
|
||||
data.guild = await Guild.findOne({ where: { id: guild_id } });
|
||||
data.channel = channel;
|
||||
|
||||
await emitEvent({ event: "INVITE_CREATE", data, guild_id } as InviteCreateEvent);
|
||||
res.status(201).send(data);
|
||||
}
|
||||
const { guild_id } = channel;
|
||||
|
||||
const expires_at = new Date(req.body.max_age * 1000 + Date.now());
|
||||
|
||||
const invite = await OrmUtils.mergeDeep(new Invite(),{
|
||||
temporary: req.body.temporary || true,
|
||||
max_uses: req.body.max_uses,
|
||||
max_age: req.body.max_age,
|
||||
expires_at,
|
||||
guild_id,
|
||||
channel_id,
|
||||
inviter_id: user_id
|
||||
}).save();
|
||||
//TODO: check this, removed toJSON call
|
||||
const data = JSON.parse(JSON.stringify(invite));
|
||||
data.inviter = await User.getPublicUser(req.user_id);
|
||||
data.guild = await Guild.findOne({ where: { id: guild_id } });
|
||||
data.channel = channel;
|
||||
|
||||
await emitEvent({ event: "INVITE_CREATE", data, guild_id } as InviteCreateEvent);
|
||||
res.status(201).send(data);
|
||||
});
|
||||
);
|
||||
|
||||
router.get("/", route({ permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
|
||||
const { channel_id } = req.params;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { emitEvent, getPermission, MessageAckEvent, ReadState, Snowflake } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { OrmUtils } from "@fosscord/util";
|
||||
import { emitEvent, getPermission, MessageAckEvent, OrmUtils, ReadState } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,25 +1,22 @@
|
||||
import { handleMessage, postHandleMessage, route } from "@fosscord/api";
|
||||
import {
|
||||
Attachment,
|
||||
Channel,
|
||||
Embed,
|
||||
DiscordApiErrors,
|
||||
emitEvent,
|
||||
FosscordApiErrors,
|
||||
getPermission,
|
||||
getRights,
|
||||
Message,
|
||||
HTTPError,
|
||||
Message,
|
||||
MessageCreateEvent,
|
||||
MessageCreateSchema,
|
||||
MessageDeleteEvent,
|
||||
MessageUpdateEvent,
|
||||
Snowflake,
|
||||
uploadFile,
|
||||
MessageCreateSchema
|
||||
uploadFile
|
||||
} from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Request, Response, Router } from "express";
|
||||
import multer from "multer";
|
||||
import { route } from "@fosscord/api";
|
||||
import { handleMessage, postHandleMessage } from "@fosscord/api";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
|
||||
const router = Router();
|
||||
// TODO: message content/embed string length limit
|
||||
@@ -33,50 +30,53 @@ const messageUpload = multer({
|
||||
storage: multer.memoryStorage()
|
||||
}); // max upload 50 mb
|
||||
|
||||
router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_MESSAGES" }), async (req: Request, res: Response) => {
|
||||
const { message_id, channel_id } = req.params;
|
||||
let body = req.body as MessageCreateSchema;
|
||||
router.patch(
|
||||
"/",
|
||||
route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_MESSAGES" }),
|
||||
async (req: Request, res: Response) => {
|
||||
const { message_id, channel_id } = req.params;
|
||||
let body = req.body as MessageCreateSchema;
|
||||
|
||||
const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
|
||||
const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
|
||||
|
||||
const permissions = await getPermission(req.user_id, undefined, channel_id);
|
||||
|
||||
const rights = await getRights(req.user_id);
|
||||
const permissions = await getPermission(req.user_id, undefined, channel_id);
|
||||
|
||||
if ((req.user_id !== message.author_id)) {
|
||||
if (!rights.has("MANAGE_MESSAGES")) {
|
||||
permissions.hasThrow("MANAGE_MESSAGES");
|
||||
body = { flags: body.flags };
|
||||
// guild admins can only suppress embeds of other messages, no such restriction imposed to instance-wide admins
|
||||
}
|
||||
} else rights.hasThrow("SELF_EDIT_MESSAGES");
|
||||
const rights = await getRights(req.user_id);
|
||||
|
||||
const new_message = await handleMessage({
|
||||
...message,
|
||||
// TODO: should message_reference be overridable?
|
||||
// @ts-ignore
|
||||
message_reference: message.message_reference,
|
||||
...body,
|
||||
author_id: message.author_id,
|
||||
channel_id,
|
||||
id: message_id,
|
||||
edited_timestamp: new Date()
|
||||
});
|
||||
if (req.user_id !== message.author_id) {
|
||||
if (!rights.has("MANAGE_MESSAGES")) {
|
||||
permissions.hasThrow("MANAGE_MESSAGES");
|
||||
body = { flags: body.flags };
|
||||
// guild admins can only suppress embeds of other messages, no such restriction imposed to instance-wide admins
|
||||
}
|
||||
} else rights.hasThrow("SELF_EDIT_MESSAGES");
|
||||
|
||||
await Promise.all([
|
||||
new_message!.save(),
|
||||
await emitEvent({
|
||||
event: "MESSAGE_UPDATE",
|
||||
const new_message = await handleMessage({
|
||||
...message,
|
||||
// TODO: should message_reference be overridable?
|
||||
// @ts-ignore
|
||||
message_reference: message.message_reference,
|
||||
...body,
|
||||
author_id: message.author_id,
|
||||
channel_id,
|
||||
data: { ...new_message, nonce: undefined }
|
||||
} as MessageUpdateEvent)
|
||||
]);
|
||||
id: message_id,
|
||||
edited_timestamp: new Date()
|
||||
});
|
||||
|
||||
postHandleMessage(message);
|
||||
await Promise.all([
|
||||
new_message!.save(),
|
||||
await emitEvent({
|
||||
event: "MESSAGE_UPDATE",
|
||||
channel_id,
|
||||
data: { ...new_message, nonce: undefined }
|
||||
} as MessageUpdateEvent)
|
||||
]);
|
||||
|
||||
return res.json(message);
|
||||
});
|
||||
postHandleMessage(message);
|
||||
|
||||
return res.json(message);
|
||||
}
|
||||
);
|
||||
|
||||
// Backfill message with specific timestamp
|
||||
router.put(
|
||||
@@ -94,7 +94,7 @@ router.put(
|
||||
const { channel_id, message_id } = req.params;
|
||||
let body = req.body as MessageCreateSchema;
|
||||
const attachments: Attachment[] = [];
|
||||
|
||||
|
||||
const rights = await getRights(req.user_id);
|
||||
rights.hasThrow("SEND_MESSAGES");
|
||||
|
||||
@@ -103,13 +103,13 @@ router.put(
|
||||
throw new HTTPError("Message IDs must be positive integers", 400);
|
||||
}
|
||||
|
||||
const snowflake = Snowflake.deconstruct(message_id)
|
||||
const snowflake = Snowflake.deconstruct(message_id);
|
||||
if (Date.now() < snowflake.timestamp) {
|
||||
// message is in the future
|
||||
throw FosscordApiErrors.CANNOT_BACKFILL_TO_THE_FUTURE;
|
||||
}
|
||||
|
||||
const exists = await Message.findOne({ where: { id: message_id, channel_id: channel_id }});
|
||||
const exists = await Message.findOne({ where: { id: message_id, channel_id: channel_id } });
|
||||
if (exists) {
|
||||
throw FosscordApiErrors.CANNOT_REPLACE_BY_BACKFILL;
|
||||
}
|
||||
@@ -136,19 +136,19 @@ router.put(
|
||||
channel_id,
|
||||
attachments,
|
||||
edited_timestamp: undefined,
|
||||
timestamp: new Date(snowflake.timestamp),
|
||||
timestamp: new Date(snowflake.timestamp)
|
||||
});
|
||||
|
||||
//Fix for the client bug
|
||||
delete message.member
|
||||
|
||||
delete message.member;
|
||||
|
||||
await Promise.all([
|
||||
message.save(),
|
||||
emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent),
|
||||
channel.save()
|
||||
]);
|
||||
|
||||
postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
|
||||
postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
|
||||
|
||||
return res.json(message);
|
||||
}
|
||||
@@ -160,7 +160,7 @@ router.get("/", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res:
|
||||
const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
|
||||
|
||||
const permissions = await getPermission(req.user_id, undefined, channel_id);
|
||||
|
||||
|
||||
if (message.author_id !== req.user_id) permissions.hasThrow("READ_MESSAGE_HISTORY");
|
||||
|
||||
return res.json(message);
|
||||
@@ -171,10 +171,10 @@ router.delete("/", route({}), async (req: Request, res: Response) => {
|
||||
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
|
||||
const message = await Message.findOneOrFail({ where: { id: message_id } });
|
||||
|
||||
|
||||
const rights = await getRights(req.user_id);
|
||||
|
||||
if ((message.author_id !== req.user_id)) {
|
||||
if (message.author_id !== req.user_id) {
|
||||
if (!rights.has("MANAGE_MESSAGES")) {
|
||||
const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
|
||||
permission.hasThrow("MANAGE_MESSAGES");
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { route } from "@fosscord/api";
|
||||
import {
|
||||
Channel,
|
||||
emitEvent,
|
||||
Emoji,
|
||||
getPermission,
|
||||
HTTPError,
|
||||
Member,
|
||||
Message,
|
||||
MessageReactionAddEvent,
|
||||
@@ -13,9 +15,7 @@ import {
|
||||
PublicUserProjection,
|
||||
User
|
||||
} from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { In } from "typeorm";
|
||||
|
||||
const router = Router();
|
||||
@@ -101,48 +101,52 @@ router.get("/:emoji", route({ permission: "VIEW_CHANNEL" }), async (req: Request
|
||||
res.json(users);
|
||||
});
|
||||
|
||||
router.put("/:emoji/:user_id", route({ permission: "READ_MESSAGE_HISTORY", right: "SELF_ADD_REACTIONS" }), async (req: Request, res: Response) => {
|
||||
const { message_id, channel_id, user_id } = req.params;
|
||||
if (user_id !== "@me") throw new HTTPError("Invalid user");
|
||||
const emoji = getEmoji(req.params.emoji);
|
||||
router.put(
|
||||
"/:emoji/:user_id",
|
||||
route({ permission: "READ_MESSAGE_HISTORY", right: "SELF_ADD_REACTIONS" }),
|
||||
async (req: Request, res: Response) => {
|
||||
const { message_id, channel_id, user_id } = req.params;
|
||||
if (user_id !== "@me") throw new HTTPError("Invalid user");
|
||||
const emoji = getEmoji(req.params.emoji);
|
||||
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
|
||||
const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
|
||||
const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
|
||||
const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
|
||||
const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
|
||||
|
||||
if (!already_added) req.permission!.hasThrow("ADD_REACTIONS");
|
||||
if (!already_added) req.permission!.hasThrow("ADD_REACTIONS");
|
||||
|
||||
if (emoji.id) {
|
||||
const external_emoji = await Emoji.findOneOrFail({ where: { id: emoji.id } });
|
||||
if (!already_added) req.permission!.hasThrow("USE_EXTERNAL_EMOJIS");
|
||||
emoji.animated = external_emoji.animated;
|
||||
emoji.name = external_emoji.name;
|
||||
}
|
||||
|
||||
if (already_added) {
|
||||
if (already_added.user_ids.includes(req.user_id)) return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error
|
||||
already_added.count++;
|
||||
} else message.reactions.push({ count: 1, emoji, user_ids: [req.user_id] });
|
||||
|
||||
await message.save();
|
||||
|
||||
const member = channel.guild_id && (await Member.findOneOrFail({ where: { id: req.user_id } }));
|
||||
|
||||
await emitEvent({
|
||||
event: "MESSAGE_REACTION_ADD",
|
||||
channel_id,
|
||||
data: {
|
||||
user_id: req.user_id,
|
||||
channel_id,
|
||||
message_id,
|
||||
guild_id: channel.guild_id,
|
||||
emoji,
|
||||
member
|
||||
if (emoji.id) {
|
||||
const external_emoji = await Emoji.findOneOrFail({ where: { id: emoji.id } });
|
||||
if (!already_added) req.permission!.hasThrow("USE_EXTERNAL_EMOJIS");
|
||||
emoji.animated = external_emoji.animated;
|
||||
emoji.name = external_emoji.name;
|
||||
}
|
||||
} as MessageReactionAddEvent);
|
||||
|
||||
res.sendStatus(204);
|
||||
});
|
||||
if (already_added) {
|
||||
if (already_added.user_ids.includes(req.user_id)) return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error
|
||||
already_added.count++;
|
||||
} else message.reactions.push({ count: 1, emoji, user_ids: [req.user_id] });
|
||||
|
||||
await message.save();
|
||||
|
||||
const member = channel.guild_id && (await Member.findOneOrFail({ where: { id: req.user_id } }));
|
||||
|
||||
await emitEvent({
|
||||
event: "MESSAGE_REACTION_ADD",
|
||||
channel_id,
|
||||
data: {
|
||||
user_id: req.user_id,
|
||||
channel_id,
|
||||
message_id,
|
||||
guild_id: channel.guild_id,
|
||||
emoji,
|
||||
member
|
||||
}
|
||||
} as MessageReactionAddEvent);
|
||||
|
||||
res.sendStatus(204);
|
||||
}
|
||||
);
|
||||
|
||||
router.delete("/:emoji/:user_id", route({}), async (req: Request, res: Response) => {
|
||||
let { message_id, channel_id, user_id } = req.params;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Channel, Config, emitEvent, getPermission, getRights, MessageDeleteBulkEvent, Message } from "@fosscord/util";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Channel, Config, emitEvent, getPermission, getRights, HTTPError, Message, MessageDeleteBulkEvent } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { In } from "typeorm";
|
||||
|
||||
const router: Router = Router();
|
||||
@@ -13,7 +12,7 @@ export default router;
|
||||
// https://discord.com/developers/docs/resources/channel#bulk-delete-messages
|
||||
router.post("/", route({ body: "BulkDeleteSchema" }), async (req: Request, res: Response) => {
|
||||
const { channel_id } = req.params;
|
||||
const channel = await Channel.findOneOrFail({where:{ id: channel_id} });
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
|
||||
if (!channel.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400);
|
||||
|
||||
const rights = await getRights(req.user_id);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { handleMessage, postHandleMessage, route } from "@fosscord/api";
|
||||
import {
|
||||
Attachment,
|
||||
Channel,
|
||||
@@ -7,16 +7,15 @@ import {
|
||||
DmChannelDTO,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
getRights,
|
||||
HTTPError,
|
||||
Member,
|
||||
Message,
|
||||
MessageCreateEvent,
|
||||
MessageCreateSchema,
|
||||
Snowflake,
|
||||
uploadFile,
|
||||
Member,
|
||||
MessageCreateSchema
|
||||
uploadFile
|
||||
} from "@fosscord/util";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { handleMessage, postHandleMessage, route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
import multer from "multer";
|
||||
import { FindManyOptions, LessThan, MoreThan } from "typeorm";
|
||||
import { URL } from "url";
|
||||
@@ -69,23 +68,20 @@ router.get("/", async (req: Request, res: Response) => {
|
||||
permissions.hasThrow("VIEW_CHANNEL");
|
||||
if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);
|
||||
|
||||
let query: FindManyOptions<Message> & { where: { id?: any; }; } = {
|
||||
let query: FindManyOptions<Message> & { where: { id?: any } } = {
|
||||
order: { id: "DESC" },
|
||||
take: limit,
|
||||
where: { channel_id },
|
||||
relations: ["author", "webhook", "application", "mentions", "mention_roles", "mention_channels", "sticker_items", "attachments"]
|
||||
};
|
||||
|
||||
|
||||
if (after) {
|
||||
if (after > new Snowflake()) return res.status(422);
|
||||
query.where.id = MoreThan(after);
|
||||
}
|
||||
else if (before) {
|
||||
} else if (before) {
|
||||
if (before < req.params.channel_id) return res.status(422);
|
||||
query.where.id = LessThan(before);
|
||||
}
|
||||
else if (around) {
|
||||
} else if (around) {
|
||||
query.where.id = [
|
||||
MoreThan((BigInt(around) - BigInt(halfLimit)).toString()),
|
||||
LessThan((BigInt(around) + BigInt(halfLimit)).toString())
|
||||
@@ -110,15 +106,14 @@ router.get("/", async (req: Request, res: Response) => {
|
||||
const uri = y.proxy_url.startsWith("http") ? y.proxy_url : `https://example.org${y.proxy_url}`;
|
||||
y.proxy_url = `${endpoint == null ? "" : endpoint}${new URL(uri).pathname}`;
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
Some clients ( discord.js ) only check if a property exists within the response,
|
||||
which causes erorrs when, say, the `application` property is `null`.
|
||||
**/
|
||||
|
||||
|
||||
for (let curr in x) {
|
||||
if (x[curr] === null)
|
||||
delete x[curr];
|
||||
if (x[curr] === null) delete x[curr];
|
||||
}
|
||||
|
||||
return x;
|
||||
@@ -130,7 +125,7 @@ router.get("/", async (req: Request, res: Response) => {
|
||||
const messageUpload = multer({
|
||||
limits: {
|
||||
fileSize: 1024 * 1024 * 100,
|
||||
fields: 10,
|
||||
fields: 10
|
||||
// files: 1
|
||||
},
|
||||
storage: multer.memoryStorage()
|
||||
@@ -162,16 +157,15 @@ router.post(
|
||||
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients", "recipients.user"] });
|
||||
if (!channel.isWritable()) {
|
||||
throw new HTTPError(`Cannot send messages to channel of type ${channel.type}`, 400)
|
||||
throw new HTTPError(`Cannot send messages to channel of type ${channel.type}`, 400);
|
||||
}
|
||||
|
||||
const files = req.files as Express.Multer.File[] ?? [];
|
||||
const files = (req.files as Express.Multer.File[]) ?? [];
|
||||
for (let currFile of files) {
|
||||
try {
|
||||
const file: any = await uploadFile(`/attachments/${channel.id}`, currFile);
|
||||
attachments.push({ ...file, proxy_url: file.url });
|
||||
}
|
||||
catch (error) {
|
||||
} catch (error) {
|
||||
return res.status(400).json(error);
|
||||
}
|
||||
}
|
||||
@@ -212,11 +206,11 @@ router.post(
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
//Defining member fields
|
||||
|
||||
//Defining member fields
|
||||
var member = await Member.findOneOrFail({ where: { id: req.user_id }, relations: ["roles"] });
|
||||
// TODO: This doesn't work either
|
||||
// member.roles = member.roles.filter((role) => {
|
||||
// member.roles = member.roles.filter((role) => {
|
||||
// return role.id !== role.guild_id;
|
||||
// }).map((role) => {
|
||||
// return role.id;
|
||||
@@ -225,7 +219,7 @@ router.post(
|
||||
// TODO: Figure this out
|
||||
// delete message.member.last_message_id;
|
||||
// delete message.member.index;
|
||||
|
||||
|
||||
await Promise.all([
|
||||
message.save(),
|
||||
emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent),
|
||||
@@ -233,9 +227,8 @@ router.post(
|
||||
channel.save()
|
||||
]);
|
||||
|
||||
postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
|
||||
postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
|
||||
|
||||
return res.json(message);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import { route } from "@fosscord/api";
|
||||
import {
|
||||
Channel,
|
||||
ChannelPermissionOverwrite,
|
||||
ChannelPermissionOverwriteSchema,
|
||||
ChannelPermissionOverwriteType,
|
||||
ChannelUpdateEvent,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
HTTPError,
|
||||
Member,
|
||||
Role
|
||||
} from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
@@ -22,7 +20,7 @@ router.put(
|
||||
const { channel_id, overwrite_id } = req.params;
|
||||
const body = req.body as ChannelPermissionOverwriteSchema;
|
||||
|
||||
let channel = await Channel.findOneOrFail({ where: {id: channel_id} });
|
||||
let channel = await Channel.findOneOrFail({ where: { id: channel_id } });
|
||||
if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
|
||||
|
||||
if (body.type === 0) {
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
import {
|
||||
Channel,
|
||||
ChannelPinsUpdateEvent,
|
||||
Config,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
Message,
|
||||
MessageUpdateEvent,
|
||||
DiscordApiErrors
|
||||
} from "@fosscord/util";
|
||||
import { Router, Request, Response } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Channel, ChannelPinsUpdateEvent, Config, DiscordApiErrors, emitEvent, Message, MessageUpdateEvent } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import { HTTPError, PurgeSchema } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import {
|
||||
Channel,
|
||||
Config,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
getRights,
|
||||
HTTPError,
|
||||
Message,
|
||||
MessageDeleteBulkEvent,
|
||||
PurgeSchema
|
||||
} from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { Between, FindManyOptions, In, Not } from "typeorm";
|
||||
import { isTextChannel } from "./messages";
|
||||
import { FindManyOptions, Between, Not } from "typeorm";
|
||||
import { Channel, Config, emitEvent, getPermission, getRights, Message, MessageDeleteBulkEvent } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { In } from "typeorm";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
@@ -13,7 +21,12 @@ export default router;
|
||||
/**
|
||||
TODO: apply the delete bit by bit to prevent client and database stress
|
||||
**/
|
||||
router.post("/",route({ /*body: "PurgeSchema",*/ }), async (req: Request, res: Response) => {
|
||||
router.post(
|
||||
"/",
|
||||
route({
|
||||
/*body: "PurgeSchema",*/
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const { channel_id } = req.params;
|
||||
const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import {
|
||||
Channel,
|
||||
ChannelRecipientAddEvent,
|
||||
@@ -6,12 +6,12 @@ import {
|
||||
DiscordApiErrors,
|
||||
DmChannelDTO,
|
||||
emitEvent,
|
||||
OrmUtils,
|
||||
PublicUserProjection,
|
||||
Recipient,
|
||||
User
|
||||
} from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { OrmUtils } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Channel, emitEvent, Member, TypingStartEvent } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Router, Request, Response } from "express";
|
||||
import { Channel, emitEvent, Member, TypingStartEvent } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Channel, Config, getPermission, trimSpecial, Webhook } from "@fosscord/util";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { Channel, Config, DiscordApiErrors, HTTPError, trimSpecial, Webhook } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { isTextChannel } from "./messages/index";
|
||||
import { DiscordApiErrors } from "@fosscord/util";
|
||||
|
||||
const router: Router = Router();
|
||||
//TODO: implement webhooks
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Guild, Config } from "@fosscord/util";
|
||||
import { Config, Guild } from "@fosscord/util";
|
||||
|
||||
import { Router, Request, Response } from "express";
|
||||
import { route } from "..";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { Like } from "typeorm";
|
||||
import { route } from "..";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Categories } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "..";
|
||||
|
||||
const router = Router();
|
||||
@@ -10,7 +10,7 @@ router.get("/categories", route({}), async (req: Request, res: Response) => {
|
||||
|
||||
const { locale, primary_only } = req.query;
|
||||
|
||||
const out = primary_only ? await Categories.find() : await Categories.find({ where: {is_primary: true} });
|
||||
const out = primary_only ? await Categories.find() : await Categories.find({ where: { is_primary: true } });
|
||||
|
||||
res.send(out);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Config, Release } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "..";
|
||||
import { Release, Config } from "@fosscord/util";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -10,7 +10,7 @@ router.get("/:branch", route({}), async (req: Request, res: Response) => {
|
||||
const { platform } = req.query;
|
||||
//TODO
|
||||
|
||||
if(!platform || !["linux", "osx", "win"].includes(platform.toString())) return res.status(404)
|
||||
if (!platform || !["linux", "osx", "win"].includes(platform.toString())) return res.status(404);
|
||||
|
||||
const release = await Release.findOneOrFail({ where: { name: client.releases.upstreamVersion } });
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { route } from "..";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", route({}), (req: Request, res: Response) => {
|
||||
// TODO:
|
||||
res.send({ fingerprint: "", assignments: [], guild_experiments:[] });
|
||||
res.send({ fingerprint: "", assignments: [], guild_experiments: [] });
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Config } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route, RouteOptions } from "@fosscord/api";
|
||||
import { Config } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Config } from "@fosscord/util";
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route, RouteOptions } from "@fosscord/api";
|
||||
import { Config } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import fetch from "node-fetch";
|
||||
import ProxyAgent from 'proxy-agent';
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
import fetch from "node-fetch";
|
||||
import ProxyAgent from "proxy-agent";
|
||||
import { getGifApiKey, parseGifResult } from "./trending";
|
||||
|
||||
const router = Router();
|
||||
@@ -11,7 +11,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
const { q, media_format, locale } = req.query;
|
||||
|
||||
const apiKey = getGifApiKey();
|
||||
|
||||
|
||||
const agent = new ProxyAgent();
|
||||
|
||||
const response = await fetch(`https://g.tenor.com/v1/search?q=${q}&media_format=${media_format}&locale=${locale}&key=${apiKey}`, {
|
||||
@@ -20,7 +20,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
|
||||
const { results } = await response.json() as any;
|
||||
const { results } = (await response.json()) as any;
|
||||
|
||||
res.json(results.map(parseGifResult)).status(200);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import fetch from "node-fetch";
|
||||
import ProxyAgent from 'proxy-agent';
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
import fetch from "node-fetch";
|
||||
import ProxyAgent from "proxy-agent";
|
||||
import { getGifApiKey, parseGifResult } from "./trending";
|
||||
|
||||
const router = Router();
|
||||
@@ -11,7 +11,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
const { media_format, locale } = req.query;
|
||||
|
||||
const apiKey = getGifApiKey();
|
||||
|
||||
|
||||
const agent = new ProxyAgent();
|
||||
|
||||
const response = await fetch(`https://g.tenor.com/v1/trending?media_format=${media_format}&locale=${locale}&key=${apiKey}`, {
|
||||
@@ -20,7 +20,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
|
||||
const { results } = await response.json() as any;
|
||||
const { results } = (await response.json()) as any;
|
||||
|
||||
res.json(results.map(parseGifResult)).status(200);
|
||||
});
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import fetch from "node-fetch";
|
||||
import ProxyAgent from 'proxy-agent';
|
||||
import { route } from "@fosscord/api";
|
||||
import { Config } from "@fosscord/util";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { Config, HTTPError } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import fetch from "node-fetch";
|
||||
import ProxyAgent from "proxy-agent";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -34,7 +33,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
const { media_format, locale } = req.query;
|
||||
|
||||
const apiKey = getGifApiKey();
|
||||
|
||||
|
||||
const agent = new ProxyAgent();
|
||||
|
||||
const [responseSource, trendGifSource] = await Promise.all([
|
||||
@@ -50,8 +49,8 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
})
|
||||
]);
|
||||
|
||||
const { tags } = await responseSource.json() as any;
|
||||
const { results } = await trendGifSource.json() as any;
|
||||
const { tags } = (await responseSource.json()) as any;
|
||||
const { results } = (await trendGifSource.json()) as any;
|
||||
|
||||
res.json({
|
||||
categories: tags.map((x: any) => ({ name: x.searchterm, src: x.image })),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Guild, Config } from "@fosscord/util";
|
||||
import { Config, Guild } from "@fosscord/util";
|
||||
|
||||
import { Router, Request, Response } from "express";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { Like } from "typeorm";
|
||||
import { route } from "..";
|
||||
import {Like} from "typeorm"
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -13,12 +13,12 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
// TODO: implement this with default typeorm query
|
||||
// const guilds = await Guild.find({ where: { features: "DISCOVERABLE" } }); //, take: Math.abs(Number(limit)) });
|
||||
|
||||
const genLoadId = (size: Number) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
|
||||
const genLoadId = (size: Number) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join("");
|
||||
|
||||
const guilds = showAllGuilds
|
||||
? await Guild.find({ take: Math.abs(Number(limit || 24)) })
|
||||
: await Guild.find({ where: { features: Like('%DISCOVERABLE%') }, take: Math.abs(Number(limit || 24)) });
|
||||
res.send({ recommended_guilds: guilds, load_id: `server_recs/${genLoadId(32)}`}).status(200);
|
||||
: await Guild.find({ where: { features: Like("%DISCOVERABLE%") }, take: Math.abs(Number(limit || 24)) });
|
||||
res.send({ recommended_guilds: guilds, load_id: `server_recs/${genLoadId(32)}` }).status(200);
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
const router = Router();
|
||||
|
||||
//TODO: implement audit logs
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { DiscordApiErrors, emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, Guild, Ban, User, Member, BanRegistrySchema, BanModeratorSchema } from "@fosscord/util";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { getIpAdress, route } from "@fosscord/api";
|
||||
import { OrmUtils } from "@fosscord/util";
|
||||
import {
|
||||
Ban,
|
||||
BanModeratorSchema,
|
||||
BanRegistrySchema,
|
||||
DiscordApiErrors,
|
||||
emitEvent,
|
||||
GuildBanAddEvent,
|
||||
GuildBanRemoveEvent,
|
||||
HTTPError,
|
||||
Member,
|
||||
OrmUtils,
|
||||
User
|
||||
} from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router: Router = Router();
|
||||
|
||||
@@ -44,16 +54,16 @@ router.get("/:user", route({ permission: "BAN_MEMBERS" }), async (req: Request,
|
||||
const { guild_id } = req.params;
|
||||
const user_id = req.params.ban;
|
||||
|
||||
let ban = await Ban.findOneOrFail({ where: { guild_id, user_id } }) as BanRegistrySchema;
|
||||
|
||||
let ban = (await Ban.findOneOrFail({ where: { guild_id, user_id } })) as BanRegistrySchema;
|
||||
|
||||
if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
|
||||
// pretend self-bans don't exist to prevent victim chasing
|
||||
|
||||
|
||||
/* Filter secret from registry. */
|
||||
|
||||
|
||||
ban = ban as BanModeratorSchema;
|
||||
|
||||
delete ban.ip
|
||||
delete ban.ip;
|
||||
|
||||
return res.json(ban);
|
||||
});
|
||||
@@ -62,14 +72,14 @@ router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBER
|
||||
const { guild_id } = req.params;
|
||||
const banned_user_id = req.params.user_id;
|
||||
|
||||
if ( (req.user_id === banned_user_id) && (banned_user_id === req.permission!.cache.guild?.owner_id))
|
||||
if (req.user_id === banned_user_id && banned_user_id === req.permission!.cache.guild?.owner_id)
|
||||
throw new HTTPError("You are the guild owner, hence can't ban yourself", 403);
|
||||
|
||||
|
||||
if (req.permission!.cache.guild?.owner_id === banned_user_id) throw new HTTPError("You can't ban the owner", 400);
|
||||
|
||||
|
||||
const banned_user = await User.getPublicUser(banned_user_id);
|
||||
|
||||
const ban = OrmUtils.mergeDeep(new Ban(),{
|
||||
const ban = OrmUtils.mergeDeep(new Ban(), {
|
||||
user_id: banned_user_id,
|
||||
guild_id: guild_id,
|
||||
ip: getIpAdress(req),
|
||||
@@ -93,14 +103,14 @@ router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBER
|
||||
return res.json(ban);
|
||||
});
|
||||
|
||||
router.put("/@me", route({ body: "BanCreateSchema"}), async (req: Request, res: Response) => {
|
||||
router.put("/@me", route({ body: "BanCreateSchema" }), async (req: Request, res: Response) => {
|
||||
const { guild_id } = req.params;
|
||||
|
||||
const banned_user = await User.getPublicUser(req.params.user_id);
|
||||
|
||||
if (req.permission!.cache.guild?.owner_id === req.params.user_id)
|
||||
if (req.permission!.cache.guild?.owner_id === req.params.user_id)
|
||||
throw new HTTPError("You are the guild owner, hence can't ban yourself", 403);
|
||||
|
||||
|
||||
const ban = OrmUtils.mergeDeep(new Ban(), {
|
||||
user_id: req.params.user_id,
|
||||
guild_id: guild_id,
|
||||
@@ -129,12 +139,12 @@ router.delete("/:user_id", route({ permission: "BAN_MEMBERS" }), async (req: Req
|
||||
const { guild_id, user_id } = req.params;
|
||||
|
||||
let ban = await Ban.findOneOrFail({ where: { guild_id, user_id } });
|
||||
|
||||
|
||||
if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
|
||||
// make self-bans irreversible and hide them from view to avoid victim chasing
|
||||
|
||||
|
||||
const banned_user = await User.getPublicUser(user_id);
|
||||
|
||||
|
||||
await Promise.all([
|
||||
Ban.delete({
|
||||
user_id: user_id,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Router, Response, Request } from "express";
|
||||
import { Channel, ChannelUpdateEvent, getPermission, emitEvent, ChannelModifySchema, ChannelReorderSchema } from "@fosscord/util";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Channel, ChannelModifySchema, ChannelReorderSchema, ChannelUpdateEvent, emitEvent, HTTPError } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
const router = Router();
|
||||
|
||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Channel, emitEvent, GuildDeleteEvent, Guild, Member, Message, Role, Invite, Emoji } from "@fosscord/util";
|
||||
import { Router, Request, Response } from "express";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { emitEvent, Guild, GuildDeleteEvent, HTTPError } from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,38 +1,36 @@
|
||||
import { Guild, Config } from "@fosscord/util";
|
||||
|
||||
import { Router, Request, Response } from "express";
|
||||
import { route } from "@fosscord/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
const { guild_id } = req.params;
|
||||
// TODO:
|
||||
// Load from database
|
||||
// Admin control, but for now it allows anyone to be discoverable
|
||||
const { guild_id } = req.params;
|
||||
// TODO:
|
||||
// Load from database
|
||||
// Admin control, but for now it allows anyone to be discoverable
|
||||
|
||||
res.send({
|
||||
guild_id: guild_id,
|
||||
safe_environment: true,
|
||||
healthy: true,
|
||||
health_score_pending: false,
|
||||
size: true,
|
||||
nsfw_properties: {},
|
||||
protected: true,
|
||||
sufficient: true,
|
||||
sufficient_without_grace_period: true,
|
||||
valid_rules_channel: true,
|
||||
retention_healthy: true,
|
||||
engagement_healthy: true,
|
||||
age: true,
|
||||
minimum_age: 0,
|
||||
health_score: {
|
||||
avg_nonnew_participators: 0,
|
||||
avg_nonnew_communicators: 0,
|
||||
num_intentful_joiners: 0,
|
||||
perc_ret_w1_intentful: 0
|
||||
},
|
||||
minimum_size: 0
|
||||
healthy: true,
|
||||
health_score_pending: false,
|
||||
size: true,
|
||||
nsfw_properties: {},
|
||||
protected: true,
|
||||
sufficient: true,
|
||||
sufficient_without_grace_period: true,
|
||||
valid_rules_channel: true,
|
||||
retention_healthy: true,
|
||||
engagement_healthy: true,
|
||||
age: true,
|
||||
minimum_age: 0,
|
||||
health_score: {
|
||||
avg_nonnew_participators: 0,
|
||||
avg_nonnew_communicators: 0,
|
||||
num_intentful_joiners: 0,
|
||||
perc_ret_w1_intentful: 0
|
||||
},
|
||||
minimum_size: 0
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { Config, DiscordApiErrors, emitEvent, Emoji, EmojiCreateSchema, EmojiModifySchema, GuildEmojisUpdateEvent, handleFile, Member, Snowflake, User } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { OrmUtils } from "@fosscord/util";
|
||||
import {
|
||||
Config,
|
||||
DiscordApiErrors,
|
||||
emitEvent,
|
||||
Emoji,
|
||||
EmojiCreateSchema,
|
||||
EmojiModifySchema,
|
||||
GuildEmojisUpdateEvent,
|
||||
handleFile,
|
||||
Member,
|
||||
OrmUtils,
|
||||
Snowflake,
|
||||
User
|
||||
} from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import { DiscordApiErrors, emitEvent, getPermission, getRights, Guild, GuildUpdateEvent, GuildUpdateSchema, handleFile, Member } from "@fosscord/util";
|
||||
import { HTTPError } from "@fosscord/util";
|
||||
import { route } from "@fosscord/api";
|
||||
import { OrmUtils } from "@fosscord/util";
|
||||
import {
|
||||
DiscordApiErrors,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
getRights,
|
||||
Guild,
|
||||
GuildUpdateEvent,
|
||||
GuildUpdateSchema,
|
||||
handleFile,
|
||||
HTTPError,
|
||||
Member,
|
||||
OrmUtils
|
||||
} from "@fosscord/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -21,17 +31,16 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
return res.send(guild);
|
||||
});
|
||||
|
||||
router.patch("/", route({ body: "GuildUpdateSchema"}), async (req: Request, res: Response) => {
|
||||
router.patch("/", route({ body: "GuildUpdateSchema" }), async (req: Request, res: Response) => {
|
||||
const body = req.body as GuildUpdateSchema;
|
||||
const { guild_id } = req.params;
|
||||
|
||||
|
||||
|
||||
const rights = await getRights(req.user_id);
|
||||
const permission = await getPermission(req.user_id, guild_id);
|
||||
|
||||
if (!rights.has("MANAGE_GUILDS")||!permission.has("MANAGE_GUILD"))
|
||||
|
||||
if (!rights.has("MANAGE_GUILDS") || !permission.has("MANAGE_GUILD"))
|
||||
throw DiscordApiErrors.MISSING_PERMISSIONS.withParams("MANAGE_GUILD");
|
||||
|
||||
|
||||
// TODO: guild update check image
|
||||
|
||||
if (body.icon) body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user