first commit
This commit is contained in:
commit
b923be2d69
34 changed files with 10343 additions and 0 deletions
399
.d.ts
vendored
Normal file
399
.d.ts
vendored
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
declare module "discord-dashboard" {
|
||||||
|
const licenseInfo: () => string | boolean
|
||||||
|
const useLicense: (licenseId: string) => Promise<string>
|
||||||
|
const UpdatedClass: () => Dashboard
|
||||||
|
|
||||||
|
let Dashboard: any
|
||||||
|
|
||||||
|
const initDashboard: (options: {
|
||||||
|
fileName: string
|
||||||
|
domain: string
|
||||||
|
port: number
|
||||||
|
token: string
|
||||||
|
clientSecret: string
|
||||||
|
clientId: string
|
||||||
|
}) => any
|
||||||
|
|
||||||
|
const formTypes: formTypes
|
||||||
|
const customPagesTypes: customPagesTypes
|
||||||
|
const DISCORD_FLAGS: {
|
||||||
|
Permissions: Permissions
|
||||||
|
}
|
||||||
|
|
||||||
|
const version: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Permissions {
|
||||||
|
CREATE_INSTANT_INVITE: ["CREATE_INSTANT_INVITE", 0x1]
|
||||||
|
KICK_MEMBERS: ["KICK_MEMBERS", 0x2]
|
||||||
|
BAN_MEMBERS: ["BAN_MEMBERS", 0x4]
|
||||||
|
ADMINISTRATOR: ["ADMINISTRATOR", 0x8]
|
||||||
|
MANAGE_CHANNELS: ["MANAGE_CHANNELS", 0x10]
|
||||||
|
MANAGE_GUILD: ["MANAGE_GUILD", 0x20]
|
||||||
|
ADD_REACTIONS: ["ADD_REACTIONS", 0x40]
|
||||||
|
VIEW_AUDIT_LOG: ["VIEW_AUDIT_LOG", 0x80]
|
||||||
|
PRIORITY_SPEAKER: ["PRIORITY_SPEAKER", 0x100]
|
||||||
|
STREAM: ["STREAM", 0x200]
|
||||||
|
VIEW_CHANNEL: ["VIEW_CHANNEL", 0x400]
|
||||||
|
SEND_MESSAGES: ["SEND_MESSAGES", 0x800]
|
||||||
|
SEND_TTS_MESSAGES: ["SEND_TTS_MESSAGES", 0x1000]
|
||||||
|
MANAGE_MESSAGES: ["MANAGE_MESSAGES", 0x2000]
|
||||||
|
EMBED_LINKS: ["EMBED_LINKS", 0x4000]
|
||||||
|
ATTACH_FILES: ["ATTACH_FILES", 0x8000]
|
||||||
|
READ_MESSAGE_HISTORY: ["READ_MESSAGE_HISTORY", 0x10000]
|
||||||
|
MENTION_EVERYONE: ["MENTION_EVERYONE", 0x20000]
|
||||||
|
USE_EXTERNAL_EMOJIS: ["USE_EXTERNAL_EMOJIS", 0x40000]
|
||||||
|
VIEW_GUILD_INSIGHTS: ["VIEW_GUILD_INSIGHTS", 0x80000]
|
||||||
|
CONNECT: ["CONNECT", 0x100000]
|
||||||
|
SPEAK: ["SPEAK", 0x200000]
|
||||||
|
MUTE_MEMBERS: ["MUTE_MEMBERS", 0x400000]
|
||||||
|
DEAFEN_MEMBERS: ["DEAFEN_MEMBERS", 0x800000]
|
||||||
|
MOVE_MEMBERS: ["MOVE_MEMBERS", 0x1000000]
|
||||||
|
USE_VAD: ["USE_VAD", 0x2000000]
|
||||||
|
CHANGE_NICKNAME: ["CHANGE_NICKNAME", 0x4000000]
|
||||||
|
MANAGE_NICKNAMES: ["MANAGE_NICKNAMES", 0x8000000]
|
||||||
|
MANAGE_ROLES: ["MANAGE_ROLES", 0x10000000]
|
||||||
|
MANAGE_WEBHOOKS: ["MANAGE_WEBHOOKS", 0x20000000]
|
||||||
|
MANAGE_EMOJIS_AND_STICKERS: ["MANAGE_EMOJIS_AND_STICKERS", 0x40000000]
|
||||||
|
USE_APPLICATION_COMMANDS: ["USE_APPLICATION_COMMANDS", 0x80000000]
|
||||||
|
REQUEST_TO_SPEAK: ["REQUEST_TO_SPEAK", 0x100000000]
|
||||||
|
MANAGE_EVENTS: ["MANAGE_EVENTS", 0x200000000]
|
||||||
|
MANAGE_THREADS: ["MANAGE_THREADS", 0x400000000]
|
||||||
|
CREATE_PUBLIC_THREADS: ["CREATE_PUBLIC_THREADS", 0x800000000]
|
||||||
|
CREATE_PRIVATE_THREADS: ["CREATE_PRIVATE_THREADS", 0x1000000000]
|
||||||
|
USE_EXTERNAL_STICKERS: ["USE_EXTERNAL_STICKERS", 0x2000000000]
|
||||||
|
SEND_MESSAGES_IN_THREADS: ["SEND_MESSAGES_IN_THREADS", 0x4000000000]
|
||||||
|
START_EMBEDDED_ACTIVITIES: ["START_EMBEDDED_ACTIVITIES", 0x8000000000]
|
||||||
|
MODERATE_MEMBERS: ["MODERATE_MEMBERS", 0x10000000000]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RateLimitSettingsObject {
|
||||||
|
windowMs: Number
|
||||||
|
max: Number
|
||||||
|
message: String
|
||||||
|
store?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dashboard {
|
||||||
|
new (config: {
|
||||||
|
port: number
|
||||||
|
client: {
|
||||||
|
id: string
|
||||||
|
secret: string
|
||||||
|
}
|
||||||
|
redirectUri: string
|
||||||
|
domain: string
|
||||||
|
bot: any
|
||||||
|
theme: any
|
||||||
|
settings: category[]
|
||||||
|
requiredPermissions?: object,
|
||||||
|
ownerIDs: array,
|
||||||
|
useTheme404: boolean,
|
||||||
|
useThemeMaintenance: boolean,
|
||||||
|
acceptPrivacyPolicy?: boolean
|
||||||
|
noCreateServer?: boolean
|
||||||
|
SSL?: {
|
||||||
|
enabled: boolean
|
||||||
|
key: string
|
||||||
|
cert: string
|
||||||
|
}
|
||||||
|
minimizedConsoleLogs?: boolean
|
||||||
|
rateLimits?: {
|
||||||
|
manage?: RateLimitSettingsObject
|
||||||
|
guildPage?: RateLimitSettingsObject
|
||||||
|
settingsUpdatePostAPI?: RateLimitSettingsObject
|
||||||
|
discordOAuth2?: RateLimitSettingsObject
|
||||||
|
}
|
||||||
|
invite?: {
|
||||||
|
clientId: string
|
||||||
|
scopes: object
|
||||||
|
permissions: string
|
||||||
|
redirectUri: string
|
||||||
|
otherParams: string
|
||||||
|
}
|
||||||
|
supportServer?: {
|
||||||
|
slash: string
|
||||||
|
inviteUrl: string
|
||||||
|
}
|
||||||
|
guildAfterAuthorization?: {
|
||||||
|
use: boolean
|
||||||
|
guildId: string
|
||||||
|
options?: {
|
||||||
|
nickname?: string
|
||||||
|
roles?: [string]
|
||||||
|
mute?: boolean
|
||||||
|
deaf?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reportError?: (where: string, what: any) => any
|
||||||
|
assistantsSecureStorageKey?: string
|
||||||
|
}): any
|
||||||
|
DBDEvents: () => any
|
||||||
|
init: () => Promise<any>
|
||||||
|
getApp: () => any
|
||||||
|
useThirdPartyModule: (module: any) => any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface category {
|
||||||
|
categoryId: string
|
||||||
|
categoryName: string
|
||||||
|
categoryDescription: string
|
||||||
|
categoryOptionsList: option[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface option {
|
||||||
|
optionId?: string
|
||||||
|
optionName?: string
|
||||||
|
optionDescription?: string
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
optionType:
|
||||||
|
| {
|
||||||
|
type: string
|
||||||
|
data?: string | null
|
||||||
|
function?: any
|
||||||
|
min?: number | null
|
||||||
|
max?: number | null
|
||||||
|
disabled?: boolean | null
|
||||||
|
required?: boolean | null
|
||||||
|
themeOptions?: object | null
|
||||||
|
}
|
||||||
|
| string
|
||||||
|
getActualSet?: (options: optionOptions) => Promise<any>
|
||||||
|
setNew?: (options: optionOptions) => Promise<any>
|
||||||
|
allowedCheck?: (options: allowedCheckOption) => Promise<any>
|
||||||
|
themeOptions?: Object
|
||||||
|
}
|
||||||
|
|
||||||
|
interface optionOptions {
|
||||||
|
guild: { id: string }
|
||||||
|
user: { id: string }
|
||||||
|
newData: any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface allowedCheckOption {
|
||||||
|
guild: { id: string }
|
||||||
|
user: { id: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
interface formTypes {
|
||||||
|
select: (
|
||||||
|
list: object,
|
||||||
|
disabled?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
data: {
|
||||||
|
keys: object
|
||||||
|
values: object
|
||||||
|
}
|
||||||
|
disabled: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
multiSelect: (
|
||||||
|
list: object,
|
||||||
|
disabled?: boolean,
|
||||||
|
required?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
data: {
|
||||||
|
keys: object
|
||||||
|
values: object
|
||||||
|
}
|
||||||
|
disabled: boolean | null
|
||||||
|
required: boolean | null
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
input: (
|
||||||
|
placeholder?: string,
|
||||||
|
min?: number,
|
||||||
|
max?: number,
|
||||||
|
disabled?: boolean,
|
||||||
|
required?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
data: string | null
|
||||||
|
min: number | null
|
||||||
|
max: number | null
|
||||||
|
disabled: boolean | null
|
||||||
|
required: boolean | null
|
||||||
|
themeOptions: object | null
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea: (
|
||||||
|
placeholder?: string,
|
||||||
|
min?: number,
|
||||||
|
max?: number,
|
||||||
|
disabled?: boolean,
|
||||||
|
required?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
data: string | null
|
||||||
|
min: number | null
|
||||||
|
max: number | null
|
||||||
|
disabled: boolean | null
|
||||||
|
required: boolean | null
|
||||||
|
themeOptions: object | null
|
||||||
|
}
|
||||||
|
|
||||||
|
switch: (
|
||||||
|
disabled?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
disabled: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
checkbox: (
|
||||||
|
disabled?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
disabled: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
channelsSelect: (
|
||||||
|
disabled?: boolean,
|
||||||
|
channelTypes?: string[],
|
||||||
|
hideNSFW?: boolean,
|
||||||
|
onlyNSFW?: boolean,
|
||||||
|
hideNoAccess?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
function: (client: string, guildid: string) => any
|
||||||
|
disabled: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
channelsMultiSelect: (
|
||||||
|
disabled?: boolean,
|
||||||
|
required?: boolean,
|
||||||
|
channelTypes?: string[],
|
||||||
|
hideNSFW?: boolean,
|
||||||
|
onlyNSFW?: boolean,
|
||||||
|
hideNoAccess?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
function: (client: string, guildid: string) => any
|
||||||
|
disabled: boolean
|
||||||
|
required: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
rolesSelect: (
|
||||||
|
includeBots: boolean,
|
||||||
|
disabled?: boolean,
|
||||||
|
hideHigherRoles?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
function: (client: string, guildid: string) => any
|
||||||
|
disabled: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
rolesMultiSelect: (
|
||||||
|
includeBots: boolean,
|
||||||
|
disabled?: boolean,
|
||||||
|
required?: boolean,
|
||||||
|
hideHigherRoles?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
function: (client: string, guildid: string) => any
|
||||||
|
disabled: boolean
|
||||||
|
required: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
colorSelect: (
|
||||||
|
defaultState: string,
|
||||||
|
disabled?: boolean,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
data: string
|
||||||
|
disabled: boolean
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
|
||||||
|
embedBuilder: (
|
||||||
|
defaultSettings: object,
|
||||||
|
themeOptions?: object
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
data: object
|
||||||
|
themeOptions: object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EmbedBuilder {
|
||||||
|
content?: string
|
||||||
|
embed: {
|
||||||
|
title?: string
|
||||||
|
description: string
|
||||||
|
color?: string | number
|
||||||
|
timestamp?: any
|
||||||
|
url?: string
|
||||||
|
author?: {
|
||||||
|
name?: string
|
||||||
|
url?: string
|
||||||
|
icon_url?: string
|
||||||
|
}
|
||||||
|
thumbnail?: {
|
||||||
|
url?: string
|
||||||
|
}
|
||||||
|
image?: {
|
||||||
|
url?: string
|
||||||
|
}
|
||||||
|
footer?: {
|
||||||
|
text?: string
|
||||||
|
icon_url?: string
|
||||||
|
}
|
||||||
|
fields?: EmbedBuilderField[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EmbedBuilderField {
|
||||||
|
name?: string
|
||||||
|
value?: string
|
||||||
|
inline?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface customPagesTypes {
|
||||||
|
redirectToUrl: (
|
||||||
|
endpoint: string,
|
||||||
|
getDataFunction: any
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
endpoint: string
|
||||||
|
getEndpoint: any
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHtml: (
|
||||||
|
endpoint: string,
|
||||||
|
getDataFunction: any
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
endpoint: string
|
||||||
|
getHtml: any
|
||||||
|
}
|
||||||
|
|
||||||
|
sendJson: (
|
||||||
|
endpoint: string,
|
||||||
|
getDataFunction: any
|
||||||
|
) => {
|
||||||
|
type: string
|
||||||
|
endpoint: string
|
||||||
|
getJson: any
|
||||||
|
}
|
||||||
|
}
|
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: #
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: ['https://paypal.me/breftejk', 'https://www.buymeacoffee.com/breftejk']
|
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
./node_modules/
|
||||||
|
node_modules/
|
||||||
|
test/
|
||||||
|
/test
|
||||||
|
./test/
|
||||||
|
./test/
|
||||||
|
./.idea
|
||||||
|
discord-dashboard-pp
|
||||||
|
./discord-dashboard-pp
|
||||||
|
.idea
|
||||||
|
.devChannel
|
||||||
|
./.devChannel
|
||||||
|
./ExternalStatistics/index_unobfuscated.js
|
||||||
|
ExternalStatistics/index_unobfuscated.js
|
||||||
|
./dev_project.json
|
||||||
|
dev_project.json
|
||||||
|
altometra-dashboard
|
||||||
|
./altometra-dashboard
|
||||||
|
index_unobf.js
|
||||||
|
./index_unobf.js
|
||||||
|
/altometra-dashoard
|
||||||
|
altometra-dashboard/
|
||||||
|
./altometra-dashboard/
|
||||||
|
/altometra-dashoard/
|
||||||
|
./licensedDashboardClass_unobfuscated.js
|
||||||
|
./npmPublish.js
|
||||||
|
licensedDashboardClass_unobfuscated.js
|
||||||
|
npmPublish.js
|
||||||
|
updateObfuscatedIndex.js
|
||||||
|
./updateObfuscatedIndex.js
|
||||||
|
.idea
|
||||||
|
.idea
|
||||||
|
yarn-error.log
|
6
.prettierrc.js
Normal file
6
.prettierrc.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
trailingComma: "es5",
|
||||||
|
tabWidth: 4,
|
||||||
|
semi: false,
|
||||||
|
singleQuote: false,
|
||||||
|
}
|
32
404pagedefault.js
Normal file
32
404pagedefault.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
module.exports = (websiteTitle) => `<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>${websiteTitle} - 404 Not Found</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Nunito:400,700" rel="stylesheet">
|
||||||
|
<link type="text/css" rel="stylesheet" href="https://assistants.ga/404publicstyle.css" />
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="notfound">
|
||||||
|
<div class="notfound">
|
||||||
|
<div class="notfound-404"></div>
|
||||||
|
<h1>404</h1>
|
||||||
|
<h2>Oops! Error 404 Page Not Found</h2>
|
||||||
|
<p>Sorry but the page you are looking for does not exist, have been removed. name changed or is temporarily unavailable</p>
|
||||||
|
<a href="/">Back to homepage</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
`
|
43
ExternalIntegration/index.js
Normal file
43
ExternalIntegration/index.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
class Client {
|
||||||
|
constructor({url,token}) {
|
||||||
|
this.url = url;
|
||||||
|
try {
|
||||||
|
//connect with socket using url specified
|
||||||
|
}catch(err){
|
||||||
|
throw new TypeError('Discord-Dashboard External Integration failure: URL specified is wrong or token specified is wrong.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
socket: ()=>{
|
||||||
|
//socket with 'settingUpdated', 'settingRequested'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Server {
|
||||||
|
constructor(config) {
|
||||||
|
this.app = ()=>{};
|
||||||
|
this.server = ({io,server,config,themeConfig}) => {
|
||||||
|
const ExternalSocket = io.of('/externalIntegration');
|
||||||
|
ExternalSocket.on('settingUpdated', (data) => {
|
||||||
|
console.log(`${data.action} got updated: ${JSON.stringify(data.)}`);
|
||||||
|
});
|
||||||
|
return ExternalSocket;
|
||||||
|
};
|
||||||
|
this.server.on('settingRequested', (data)=>{
|
||||||
|
console.log(`${data.option} has been requested.`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
UpdatedSettingEmit: (data)=>{
|
||||||
|
this.server.emit('settingUpdated', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
RequestDataEmit: (data)=>{
|
||||||
|
this.server.emit('settingsRequested', data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Client,
|
||||||
|
Server,
|
||||||
|
};
|
1
ExternalStatistics/index.js
Normal file
1
ExternalStatistics/index.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
const _0x1c811c=_0x109d;(function(_0x359c7e,_0x1eeab5){const _0x3573de=_0x109d,_0x418c34=_0x359c7e();while(!![]){try{const _0x23d247=parseInt(_0x3573de(0x1a3))/0x1*(-parseInt(_0x3573de(0x1b5))/0x2)+-parseInt(_0x3573de(0x1ac))/0x3+-parseInt(_0x3573de(0x1ab))/0x4+parseInt(_0x3573de(0x19e))/0x5+parseInt(_0x3573de(0x1b1))/0x6+parseInt(_0x3573de(0x1b3))/0x7+parseInt(_0x3573de(0x1aa))/0x8*(parseInt(_0x3573de(0x1b2))/0x9);if(_0x23d247===_0x1eeab5)break;else _0x418c34['push'](_0x418c34['shift']());}catch(_0x306517){_0x418c34['push'](_0x418c34['shift']());}}}(_0x3a2b,0xc3499));const fetch=require(_0x1c811c(0x1a6)),fs=require('fs'),DiscordDashboardPP=require(_0x1c811c(0x1af)),PPManager=new DiscordDashboardPP[(_0x1c811c(0x1a7))]({},{}),projectData=PPManager[_0x1c811c(0x1a1)]();function send(_0x5c317f,_0x2addc9){const _0x197388=_0x1c811c;try{fetch(_0x197388(0x1a2)+_0x5c317f,{'method':_0x197388(0x19f),'body':JSON[_0x197388(0x1a0)](_0x2addc9),'headers':{'Content-Type':'application/json'}})[_0x197388(0x1a8)](_0xf760df=>_0xf760df[_0x197388(0x1ad)]())[_0x197388(0x1a8)](_0x8029fe=>{})[_0x197388(0x1a4)](_0x53b4d3=>{});}catch(_0xaf8d52){}}function _0x109d(_0x584b3e,_0x1a74e2){const _0x3a2ba3=_0x3a2b();return _0x109d=function(_0x109dec,_0x14b473){_0x109dec=_0x109dec-0x19e;let _0x1dbfe7=_0x3a2ba3[_0x109dec];return _0x1dbfe7;},_0x109d(_0x584b3e,_0x1a74e2);}function _0x3a2b(){const _0x4a7b36=['PPManager','then','version','16qhVXeG','5948904oyFyVY','2301012dxNLDh','json','discord-dashboard','discord-dashboard-pp-system','exports','4292130gVGkAh','11997243GuMAAk','3220581tZFnbk','/registerProject','18tgqDOF','2422395VtzisY','POST','stringify','GetProjectData','https://dbd-external-stats.assistantscenter.com','141316gijWNs','catch','name','node-fetch'];_0x3a2b=function(){return _0x4a7b36;};return _0x3a2b();}module[_0x1c811c(0x1b0)]={'registerProject':(_0x57a975,_0x254002=projectData['id'],_0x37e8dd=projectData[_0x1c811c(0x1a5)],_0x263f96=require(_0x1c811c(0x1ae))[_0x1c811c(0x1a9)])=>{const _0x3aec38=_0x1c811c;send(_0x3aec38(0x1b4),{'cId':_0x57a975,'pId':_0x254002,'pN':_0x37e8dd,'v':_0x263f96});},'registerUser':(_0x4ae6ba,_0x4fbfb4=projectData['id'])=>{send('/registerUser',{'uId':_0x4ae6ba,'pId':_0x4fbfb4});},'pD':projectData};
|
36
HandlerIntegration/index.js
Normal file
36
HandlerIntegration/index.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
const prefix = "[DBD-Storage-Handler]"
|
||||||
|
const colors = require("colors")
|
||||||
|
const Keyv = require("keyv")
|
||||||
|
const { join } = require("path")
|
||||||
|
|
||||||
|
const err = (text) => {
|
||||||
|
return `🐧${text} Do you need help? Join our Discord server: ${"https://discord.gg/CzfMGtrdaA".blue
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
class Handler {
|
||||||
|
constructor(keyvAdapter) {
|
||||||
|
this.db = new Keyv(
|
||||||
|
keyvAdapter || `sqlite://${join(__dirname, "/database.sqlite")}`
|
||||||
|
)
|
||||||
|
|
||||||
|
this.db.on("error", (err) =>
|
||||||
|
console.error(`${prefix} ${`Keyv connection error: ${err}`.red}`)
|
||||||
|
)
|
||||||
|
|
||||||
|
this.Category = require(`${__dirname}/structures/Category`)(this.db)
|
||||||
|
this.Option = require(`${__dirname}/structures/Option`)(this.db)
|
||||||
|
|
||||||
|
console.log(`${prefix} Database successfully initialized!`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetch(guildId, optionId) {
|
||||||
|
return await this.db.get(`${guildId}.options.${optionId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
db() {
|
||||||
|
return this.db
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Handler
|
104
HandlerIntegration/structures/Category.js
Normal file
104
HandlerIntegration/structures/Category.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
module.exports = (db) => {
|
||||||
|
return class Category {
|
||||||
|
constructor(
|
||||||
|
options = { categoryId: "", categoryName: "", categoryDescription: "" }
|
||||||
|
) {
|
||||||
|
this.categoryId = options.categoryId
|
||||||
|
this.categoryName = options.categoryName
|
||||||
|
this.categoryDescription = options.categoryDescription
|
||||||
|
this.categoryOptionsList = []
|
||||||
|
|
||||||
|
// const db = Handler.getDB()
|
||||||
|
this.db = db
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} id - The id of the category, must be unique
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setId(id) {
|
||||||
|
this.categoryId = id
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} name - The name of the category displayed in the dashboard
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setName(name) {
|
||||||
|
this.categoryName = name
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} description - The description of the category displayed in the dashboard
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setDescription(description) {
|
||||||
|
this.categoryDescription = description
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} image - Set the image for a Soft UI category, must be a link
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setImage(image) {
|
||||||
|
this.categoryImageURL = image
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {boolean} toggleable - Allows Soft UI category to be toggleable
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setToggleable(toggleable) {
|
||||||
|
this.toggleable = toggleable
|
||||||
|
|
||||||
|
this.getActualSet = async ({ guild }) => {
|
||||||
|
return await this.db.get(
|
||||||
|
`${guild.id}.categories.${this.categoryId}.toggle`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setNew = async ({ guild, newData }) => {
|
||||||
|
await this.db.set(
|
||||||
|
`${guild.id}.categories.${this.categoryId}.toggle`,
|
||||||
|
newData
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./Option')[]} options - The options of the category
|
||||||
|
* @example
|
||||||
|
* new Category()
|
||||||
|
* .setId('setup')
|
||||||
|
* .setName("Setup")
|
||||||
|
* .setDescription("Setup your bot with default settings!")
|
||||||
|
* .addOptions(
|
||||||
|
* new Option()
|
||||||
|
* .setId('lang')
|
||||||
|
* .setName("Language")
|
||||||
|
* .setDescription("Change bot's language easily")
|
||||||
|
* .setType(dbd.formTypes.select({"Polish": 'pl', "English": 'en', "French": 'fr'}))
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
addOptions() {
|
||||||
|
this.categoryOptionsList.push(...arguments)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
HandlerIntegration/structures/Option.js
Normal file
95
HandlerIntegration/structures/Option.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
const { formTypes } = require("discord-dashboard")
|
||||||
|
|
||||||
|
const ids = []
|
||||||
|
|
||||||
|
const err = (text) => {
|
||||||
|
return `🐧${text} Do you need help? Join our Discord server: ${
|
||||||
|
"https://discord.gg/CzfMGtrdaA".blue
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (db) => {
|
||||||
|
return class Option {
|
||||||
|
constructor(
|
||||||
|
options = {
|
||||||
|
optionId: "",
|
||||||
|
optionName: "",
|
||||||
|
optionDescription: "",
|
||||||
|
optionType: formTypes,
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
this.optionId = options.optionId
|
||||||
|
this.optionName = options.optionName
|
||||||
|
this.optionDescription = options.optionDescription
|
||||||
|
this.optionType = options.optionType
|
||||||
|
|
||||||
|
this.categoryId = "default"
|
||||||
|
|
||||||
|
this.setNew = async ({ guild, newData }) => {
|
||||||
|
await db.set(`${guild.id}.options.${this.optionId}`, newData)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getActualSet = async ({ guild }) => {
|
||||||
|
return await db.get(`${guild.id}.options.${this.optionId}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} id - The id of the option, must be unique
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setId(id) {
|
||||||
|
this.optionId = id
|
||||||
|
|
||||||
|
if (ids.includes(id))
|
||||||
|
throw new Error(err(`Option id ${id} already exists`))
|
||||||
|
else ids.push(this.optionId)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} name - The name of the option displayed in the dashboard
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setName(name) {
|
||||||
|
this.optionName = name
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} description - The description of the option displayed in the dashboard
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setDescription(description) {
|
||||||
|
this.optionDescription = description
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {object} options - Set custom options for the formType
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setOptions(options) {
|
||||||
|
this.themeOptions = options
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {formTypes} type - The type of the option
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
setType(type) {
|
||||||
|
this.optionType = type
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
133
InitFunctions/initExampleDash.js
Normal file
133
InitFunctions/initExampleDash.js
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
module.exports = ({
|
||||||
|
fileName,
|
||||||
|
domain,
|
||||||
|
port,
|
||||||
|
token,
|
||||||
|
licenseId,
|
||||||
|
clientSecret,
|
||||||
|
clientId,
|
||||||
|
}) => {
|
||||||
|
require("fs").writeFileSync(
|
||||||
|
`${fileName}.js`,
|
||||||
|
`
|
||||||
|
|
||||||
|
/* --- DISCORD.JS CLIENT --- */
|
||||||
|
|
||||||
|
const {Client, Intents} = require('discord.js');
|
||||||
|
const client = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
||||||
|
client.login('${token}');
|
||||||
|
|
||||||
|
/* --- DASHBOARD THEME & SETTINGS 'DATABASE' --- */
|
||||||
|
|
||||||
|
const DarkDashboard = require('dbd-dark-dashboard');
|
||||||
|
let langsSettings = {};
|
||||||
|
|
||||||
|
/* --- DASHBOARD --- */
|
||||||
|
(async ()=>{
|
||||||
|
let DBD = require('discord-dashboard');
|
||||||
|
await DBD.useLicense('${licenseId}');
|
||||||
|
DBD.Dashboard = DBD.UpdatedClass();
|
||||||
|
|
||||||
|
const Dashboard = new DBD.Dashboard({
|
||||||
|
port: ${port || 80},
|
||||||
|
client: {
|
||||||
|
id: '${clientId}',
|
||||||
|
secret: '${clientSecret}'
|
||||||
|
},
|
||||||
|
redirectUri: '${domain}/discord/callback',
|
||||||
|
domain: '${domain}',
|
||||||
|
bot: client,
|
||||||
|
theme: DarkDashboard({
|
||||||
|
information: {
|
||||||
|
createdBy: "Assistants Center",
|
||||||
|
websiteTitle: "Assistants Center",
|
||||||
|
websiteName: "Discord-Dashboard",
|
||||||
|
websiteUrl: "${domain}",
|
||||||
|
dashboardUrl: "${domain}",
|
||||||
|
supporteMail: "support@${domain}",
|
||||||
|
supportServer: "",
|
||||||
|
imageFavicon: "https://www.imidnight.ml/assets/img/logo-circular.png",
|
||||||
|
iconURL: "https://www.imidnight.ml/assets/img/logo-circular.png",
|
||||||
|
pageBackGround: "linear-gradient(#2CA8FF, #155b8d)",
|
||||||
|
loggedIn: "Successfully signed in.",
|
||||||
|
mainColor: "#2CA8FF",
|
||||||
|
subColor: "#ebdbdb",
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
card: {
|
||||||
|
category: "Assistants Center - The center of everything",
|
||||||
|
title: "Welcome to the iMidnight discord where you can control the core features to the bot.",
|
||||||
|
image: "https://i.imgur.com/axnP93g.png",
|
||||||
|
footer: "Footer",
|
||||||
|
},
|
||||||
|
|
||||||
|
information: {
|
||||||
|
category: "Category",
|
||||||
|
title: "Information",
|
||||||
|
description: "This bot and panel is currently a work in progress so contact me if you find any issues on discord.",
|
||||||
|
footer: "Footer",
|
||||||
|
},
|
||||||
|
|
||||||
|
feeds: {
|
||||||
|
category: "Category",
|
||||||
|
title: "Information",
|
||||||
|
description: "This bot and panel is currently a work in progress so contact me if you find any issues on discord.",
|
||||||
|
footer: "Footer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
commands: [
|
||||||
|
{
|
||||||
|
category: "Starting Up",
|
||||||
|
subTitle: "All helpful commands",
|
||||||
|
list: [{
|
||||||
|
commandName: 'bug',
|
||||||
|
commandUsage: ";bug <bug>",
|
||||||
|
commandDescription: "test",
|
||||||
|
commandAlias: 'No aliases'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: "2nd command",
|
||||||
|
commandUsage: "oto.nd <arg> <arg2> [op]",
|
||||||
|
commandDescription: "Lorem ipsum dolor sth, arg sth arg2 stuff",
|
||||||
|
commandAlias: "Alias",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
commandName: "Test command",
|
||||||
|
commandUsage: "prefix.test <arg> [op]",
|
||||||
|
commandDescription: "Lorem ipsum dolor sth",
|
||||||
|
commandAlias: "Alias",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
settings: [
|
||||||
|
{
|
||||||
|
categoryId: 'setup',
|
||||||
|
categoryName: "Setup",
|
||||||
|
categoryDescription: "Setup your bot with default settings!",
|
||||||
|
categoryOptionsList: [
|
||||||
|
{
|
||||||
|
optionId: 'lang',
|
||||||
|
optionName: "Language",
|
||||||
|
optionDescription: "Change bot's language easily",
|
||||||
|
optionType: DBD.formTypes.select({"Polish": 'pl', "English": 'en', "French": 'fr'}),
|
||||||
|
getActualSet: async ({guild}) => {
|
||||||
|
return langsSettings[guild.id] || null;
|
||||||
|
},
|
||||||
|
setNew: async ({guild,newData}) => {
|
||||||
|
langsSettings[guild.id] = newData;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
Dashboard.init();
|
||||||
|
})();
|
||||||
|
|
||||||
|
`
|
||||||
|
)
|
||||||
|
}
|
105
InitFunctions/initPpCheck.js
Normal file
105
InitFunctions/initPpCheck.js
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
const DBDStats = require("../ExternalStatistics")
|
||||||
|
const fs = require("fs")
|
||||||
|
const { v4: uuidv4 } = require("uuid")
|
||||||
|
const readline = require("readline-sync")
|
||||||
|
|
||||||
|
const DiscordDashboardPP = require("discord-dashboard-pp-system")
|
||||||
|
|
||||||
|
module.exports = (
|
||||||
|
config,
|
||||||
|
themeConfig,
|
||||||
|
DBDStats,
|
||||||
|
secretInit,
|
||||||
|
modules,
|
||||||
|
aaThis,
|
||||||
|
license
|
||||||
|
) => {
|
||||||
|
let externalStatsDisabled = false
|
||||||
|
if (config.disableExternalStatistics) {
|
||||||
|
if (license.type == "production" || license.type == "personal") {
|
||||||
|
externalStatsDisabled = true
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`${"[Discord-dashboard v".red}${
|
||||||
|
`${require("../package.json").version}]:`.red
|
||||||
|
}: You can't disable External Stats without Personal/Production License.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const PPManager = new DiscordDashboardPP.PPManager(config, themeConfig)
|
||||||
|
PPManager.SaveProjectData()
|
||||||
|
if (!externalStatsDisabled) DBDStats.registerProject(config.client.id)
|
||||||
|
if (config.acceptPrivacyPolicy) return aaThis.secretInit(aaThis.modules)
|
||||||
|
const ppAccepted = PPManager.PP_GetAccepted()
|
||||||
|
if (ppAccepted == "accepted") return aaThis.secretInit(aaThis.modules)
|
||||||
|
let oThis = { secretInit, modules }
|
||||||
|
const readline = require("readline-sync")
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log(
|
||||||
|
`${"[Discord-dashboard v".blue}${
|
||||||
|
`${require("../package.json").version}]:`.blue
|
||||||
|
} Hello! First of all, we would like to thank you for your trust and choosing the ${
|
||||||
|
"discord-dashboard".rainbow
|
||||||
|
}.`
|
||||||
|
)
|
||||||
|
}, 2000)
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log(
|
||||||
|
`${"[Discord-dashboard v".blue}${
|
||||||
|
`${require("../package.json").version}]:`.blue
|
||||||
|
} However, we must familiarize you with our privacy policy and describe to you how we collect your data.`
|
||||||
|
)
|
||||||
|
}, 4000)
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log(`
|
||||||
|
${
|
||||||
|
"[Discord-dashboard v".blue
|
||||||
|
}${`${require("../package.json").version}]:`.blue} To maintain the quality of our services at the highest level, we collect from you:
|
||||||
|
${
|
||||||
|
"[Discord-dashboard v".blue
|
||||||
|
}${`${require("../package.json").version}]:`.blue} - The ID of your Discord-Client,
|
||||||
|
${
|
||||||
|
"[Discord-dashboard v".blue
|
||||||
|
}${`${require("../package.json").version}]:`.blue} - The number of users who log in to your panel (we also collect their IDs, but only to distinguish them from other, same login sessions),
|
||||||
|
${
|
||||||
|
"[Discord-dashboard v".blue
|
||||||
|
}${`${require("../package.json").version}]:`.blue} - The types of settings you use that go beyond the basic ones. It does not include settings such as sensitive settings, e.g. your bot data.
|
||||||
|
${
|
||||||
|
"[Discord-dashboard v".blue
|
||||||
|
}${`${require("../package.json").version}]:`.blue} We must add that your data is available only to the Project Administrator - breathtake. Nobody else can see it. Your data is not transferred anywhere either.
|
||||||
|
|
||||||
|
${
|
||||||
|
"[Discord-dashboard v".red
|
||||||
|
}${`${require("../package.json").version}]:`.red} If you can't type in the console, pass 'acceptPrivacyPolicy: true,' to the discord-dashboard config.`)
|
||||||
|
let iCount = 0
|
||||||
|
|
||||||
|
function ask() {
|
||||||
|
if (iCount > 0)
|
||||||
|
console.log(
|
||||||
|
`${"[Discord-dashboard v".red}${
|
||||||
|
`${require("../package.json").version}]:`.red
|
||||||
|
}: You must accept our privacy policy to be able to use the module. Otherwise, you must delete the module.`
|
||||||
|
)
|
||||||
|
iCount++
|
||||||
|
const rlResponse = readline.question(
|
||||||
|
`${"[Discord-dashboard v".blue}${
|
||||||
|
`${require("../package.json").version}]:`.blue
|
||||||
|
} Do you accept it? (y/n) `
|
||||||
|
)
|
||||||
|
|
||||||
|
if (rlResponse == "y" || rlResponse == "yes") {
|
||||||
|
console.log(
|
||||||
|
`${"[Discord-dashboard v".green}${
|
||||||
|
`${require("../package.json").version}]:`.green
|
||||||
|
} Thank you. Now we will run the module for you. You will not need to re-approve our privacy policy again.`
|
||||||
|
)
|
||||||
|
PPManager.PP_Accept()
|
||||||
|
setTimeout(function () {
|
||||||
|
aaThis.secretInit(aaThis.modules)
|
||||||
|
}, 1000)
|
||||||
|
} else ask()
|
||||||
|
}
|
||||||
|
ask()
|
||||||
|
}, 6000)
|
||||||
|
}
|
109
InitFunctions/initServer.js
Normal file
109
InitFunctions/initServer.js
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
const https = require("https")
|
||||||
|
const http = require("http")
|
||||||
|
const { Server: SocketServer } = require("socket.io")
|
||||||
|
|
||||||
|
const err = (text) => {
|
||||||
|
return (
|
||||||
|
text +
|
||||||
|
` Do you need help? Join our Discord server: ${
|
||||||
|
"https://discord.gg/CzfMGtrdaA".blue
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (app, config, themeConfig, modules) => {
|
||||||
|
if (config.noCreateServer) return { io: null, server: null }
|
||||||
|
let server
|
||||||
|
|
||||||
|
if (!config.SSL) config.SSL = {}
|
||||||
|
if (config.SSL.enabled) {
|
||||||
|
if (!config.SSL.key || !config.SSL.cert)
|
||||||
|
console.log(
|
||||||
|
err(
|
||||||
|
`${
|
||||||
|
"discord-dashboard issue:".red
|
||||||
|
} The SSL preference for Dashboard is selected (config.SSL.enabled), but config does not include key or cert (config.SSL.key, config.SSL.cert).`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
let options = {
|
||||||
|
key: config.SSL.key || "",
|
||||||
|
cert: config.SSL.cert || "",
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const https = require("https")
|
||||||
|
server = https.createServer(options, app)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(
|
||||||
|
err(
|
||||||
|
`${
|
||||||
|
"discord-dashboard issue:".red
|
||||||
|
} There's a problem while creating server, check if the port specified is already on use.`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const http = require("http")
|
||||||
|
server = http.createServer(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pport = ""
|
||||||
|
if (config.port != 80 && config.port != 443) {
|
||||||
|
pport = `:${config.port}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.minimizedConsoleLogs) {
|
||||||
|
console.log(
|
||||||
|
`
|
||||||
|
██████╗ ██████╗ ██████╗
|
||||||
|
██╔══██╗██╔══██╗██╔══██╗
|
||||||
|
██║ ██║██████╔╝██║ ██║
|
||||||
|
██║ ██║██╔══██╗██║ ██║
|
||||||
|
██████╔╝██████╔╝██████╔╝
|
||||||
|
╚═════╝ ╚═════╝ ╚═════╝
|
||||||
|
Discord Bot Dashboard
|
||||||
|
`.rainbow +
|
||||||
|
`
|
||||||
|
Thanks for using ${
|
||||||
|
"discord-dashboard".rainbow
|
||||||
|
} module! The server is up and running, so head over to the ${
|
||||||
|
`${(config.domain || "domain.com") + pport}`.blue
|
||||||
|
} website and start your fun.
|
||||||
|
|
||||||
|
Remember that there are ${
|
||||||
|
"themes".rainbow
|
||||||
|
} available to make the Dashboard look better: ${
|
||||||
|
"https://dbd-docs.assistantscenter.com/#/?id=themes".blue
|
||||||
|
}
|
||||||
|
|
||||||
|
If you need help with something or you don't understand something, please visit our ${
|
||||||
|
"Discord Support Server".rainbow
|
||||||
|
}: ${"https://discord.gg/CzfMGtrdaA".blue}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`DBD Dashboard running on ${
|
||||||
|
`${(config.domain || "domain.com") + pport}`.blue
|
||||||
|
} !`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const SocketServer = require("socket.io").Server
|
||||||
|
const io = new SocketServer(server, {
|
||||||
|
cors: {
|
||||||
|
origin: "*",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
modules.forEach((module) => {
|
||||||
|
module.server({
|
||||||
|
io: io,
|
||||||
|
server: server,
|
||||||
|
config: config,
|
||||||
|
themeConfig: themeConfig,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
server.listen(config.port)
|
||||||
|
return { server, io }
|
||||||
|
}
|
437
LICENSE
Normal file
437
LICENSE
Normal file
|
@ -0,0 +1,437 @@
|
||||||
|
Attribution-NonCommercial-ShareAlike 4.0 International
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||||
|
does not provide legal services or legal advice. Distribution of
|
||||||
|
Creative Commons public licenses does not create a lawyer-client or
|
||||||
|
other relationship. Creative Commons makes its licenses and related
|
||||||
|
information available on an "as-is" basis. Creative Commons gives no
|
||||||
|
warranties regarding its licenses, any material licensed under their
|
||||||
|
terms and conditions, or any related information. Creative Commons
|
||||||
|
disclaims all liability for damages resulting from their use to the
|
||||||
|
fullest extent possible.
|
||||||
|
|
||||||
|
Using Creative Commons Public Licenses
|
||||||
|
|
||||||
|
Creative Commons public licenses provide a standard set of terms and
|
||||||
|
conditions that creators and other rights holders may use to share
|
||||||
|
original works of authorship and other material subject to copyright
|
||||||
|
and certain other rights specified in the public license below. The
|
||||||
|
following considerations are for informational purposes only, are not
|
||||||
|
exhaustive, and do not form part of our licenses.
|
||||||
|
|
||||||
|
Considerations for licensors: Our public licenses are
|
||||||
|
intended for use by those authorized to give the public
|
||||||
|
permission to use material in ways otherwise restricted by
|
||||||
|
copyright and certain other rights. Our licenses are
|
||||||
|
irrevocable. Licensors should read and understand the terms
|
||||||
|
and conditions of the license they choose before applying it.
|
||||||
|
Licensors should also secure all rights necessary before
|
||||||
|
applying our licenses so that the public can reuse the
|
||||||
|
material as expected. Licensors should clearly mark any
|
||||||
|
material not subject to the license. This includes other CC-
|
||||||
|
licensed material, or material used under an exception or
|
||||||
|
limitation to copyright. More considerations for licensors:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensors
|
||||||
|
|
||||||
|
Considerations for the public: By using one of our public
|
||||||
|
licenses, a licensor grants the public permission to use the
|
||||||
|
licensed material under specified terms and conditions. If
|
||||||
|
the licensor's permission is not necessary for any reason--for
|
||||||
|
example, because of any applicable exception or limitation to
|
||||||
|
copyright--then that use is not regulated by the license. Our
|
||||||
|
licenses grant only permissions under copyright and certain
|
||||||
|
other rights that a licensor has authority to grant. Use of
|
||||||
|
the licensed material may still be restricted for other
|
||||||
|
reasons, including because others have copyright or other
|
||||||
|
rights in the material. A licensor may make special requests,
|
||||||
|
such as asking that all changes be marked or described.
|
||||||
|
Although not required by our licenses, you are encouraged to
|
||||||
|
respect those requests where reasonable. More_considerations
|
||||||
|
for the public:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensees
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||||
|
Public License
|
||||||
|
|
||||||
|
By exercising the Licensed Rights (defined below), You accept and agree
|
||||||
|
to be bound by the terms and conditions of this Creative Commons
|
||||||
|
Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||||
|
("Public License"). To the extent this Public License may be
|
||||||
|
interpreted as a contract, You are granted the Licensed Rights in
|
||||||
|
consideration of Your acceptance of these terms and conditions, and the
|
||||||
|
Licensor grants You such rights in consideration of benefits the
|
||||||
|
Licensor receives from making the Licensed Material available under
|
||||||
|
these terms and conditions.
|
||||||
|
|
||||||
|
|
||||||
|
Section 1 -- Definitions.
|
||||||
|
|
||||||
|
a. Adapted Material means material subject to Copyright and Similar
|
||||||
|
Rights that is derived from or based upon the Licensed Material
|
||||||
|
and in which the Licensed Material is translated, altered,
|
||||||
|
arranged, transformed, or otherwise modified in a manner requiring
|
||||||
|
permission under the Copyright and Similar Rights held by the
|
||||||
|
Licensor. For purposes of this Public License, where the Licensed
|
||||||
|
Material is a musical work, performance, or sound recording,
|
||||||
|
Adapted Material is always produced where the Licensed Material is
|
||||||
|
synched in timed relation with a moving image.
|
||||||
|
|
||||||
|
b. Adapter's License means the license You apply to Your Copyright
|
||||||
|
and Similar Rights in Your contributions to Adapted Material in
|
||||||
|
accordance with the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
c. BY-NC-SA Compatible License means a license listed at
|
||||||
|
creativecommons.org/compatiblelicenses, approved by Creative
|
||||||
|
Commons as essentially the equivalent of this Public License.
|
||||||
|
|
||||||
|
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||||
|
closely related to copyright including, without limitation,
|
||||||
|
performance, broadcast, sound recording, and Sui Generis Database
|
||||||
|
Rights, without regard to how the rights are labeled or
|
||||||
|
categorized. For purposes of this Public License, the rights
|
||||||
|
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||||
|
Rights.
|
||||||
|
|
||||||
|
e. Effective Technological Measures means those measures that, in the
|
||||||
|
absence of proper authority, may not be circumvented under laws
|
||||||
|
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||||
|
Treaty adopted on December 20, 1996, and/or similar international
|
||||||
|
agreements.
|
||||||
|
|
||||||
|
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||||
|
any other exception or limitation to Copyright and Similar Rights
|
||||||
|
that applies to Your use of the Licensed Material.
|
||||||
|
|
||||||
|
g. License Elements means the license attributes listed in the name
|
||||||
|
of a Creative Commons Public License. The License Elements of this
|
||||||
|
Public License are Attribution, NonCommercial, and ShareAlike.
|
||||||
|
|
||||||
|
h. Licensed Material means the artistic or literary work, database,
|
||||||
|
or other material to which the Licensor applied this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
i. Licensed Rights means the rights granted to You subject to the
|
||||||
|
terms and conditions of this Public License, which are limited to
|
||||||
|
all Copyright and Similar Rights that apply to Your use of the
|
||||||
|
Licensed Material and that the Licensor has authority to license.
|
||||||
|
|
||||||
|
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||||
|
under this Public License.
|
||||||
|
|
||||||
|
k. NonCommercial means not primarily intended for or directed towards
|
||||||
|
commercial advantage or monetary compensation. For purposes of
|
||||||
|
this Public License, the exchange of the Licensed Material for
|
||||||
|
other material subject to Copyright and Similar Rights by digital
|
||||||
|
file-sharing or similar means is NonCommercial provided there is
|
||||||
|
no payment of monetary compensation in connection with the
|
||||||
|
exchange.
|
||||||
|
|
||||||
|
l. Share means to provide material to the public by any means or
|
||||||
|
process that requires permission under the Licensed Rights, such
|
||||||
|
as reproduction, public display, public performance, distribution,
|
||||||
|
dissemination, communication, or importation, and to make material
|
||||||
|
available to the public including in ways that members of the
|
||||||
|
public may access the material from a place and at a time
|
||||||
|
individually chosen by them.
|
||||||
|
|
||||||
|
m. Sui Generis Database Rights means rights other than copyright
|
||||||
|
resulting from Directive 96/9/EC of the European Parliament and of
|
||||||
|
the Council of 11 March 1996 on the legal protection of databases,
|
||||||
|
as amended and/or succeeded, as well as other essentially
|
||||||
|
equivalent rights anywhere in the world.
|
||||||
|
|
||||||
|
n. You means the individual or entity exercising the Licensed Rights
|
||||||
|
under this Public License. Your has a corresponding meaning.
|
||||||
|
|
||||||
|
|
||||||
|
Section 2 -- Scope.
|
||||||
|
|
||||||
|
a. License grant.
|
||||||
|
|
||||||
|
1. Subject to the terms and conditions of this Public License,
|
||||||
|
the Licensor hereby grants You a worldwide, royalty-free,
|
||||||
|
non-sublicensable, non-exclusive, irrevocable license to
|
||||||
|
exercise the Licensed Rights in the Licensed Material to:
|
||||||
|
|
||||||
|
a. reproduce and Share the Licensed Material, in whole or
|
||||||
|
in part, for NonCommercial purposes only; and
|
||||||
|
|
||||||
|
b. produce, reproduce, and Share Adapted Material for
|
||||||
|
NonCommercial purposes only.
|
||||||
|
|
||||||
|
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||||
|
Exceptions and Limitations apply to Your use, this Public
|
||||||
|
License does not apply, and You do not need to comply with
|
||||||
|
its terms and conditions.
|
||||||
|
|
||||||
|
3. Term. The term of this Public License is specified in Section
|
||||||
|
6(a).
|
||||||
|
|
||||||
|
4. Media and formats; technical modifications allowed. The
|
||||||
|
Licensor authorizes You to exercise the Licensed Rights in
|
||||||
|
all media and formats whether now known or hereafter created,
|
||||||
|
and to make technical modifications necessary to do so. The
|
||||||
|
Licensor waives and/or agrees not to assert any right or
|
||||||
|
authority to forbid You from making technical modifications
|
||||||
|
necessary to exercise the Licensed Rights, including
|
||||||
|
technical modifications necessary to circumvent Effective
|
||||||
|
Technological Measures. For purposes of this Public License,
|
||||||
|
simply making modifications authorized by this Section 2(a)
|
||||||
|
(4) never produces Adapted Material.
|
||||||
|
|
||||||
|
5. Downstream recipients.
|
||||||
|
|
||||||
|
a. Offer from the Licensor -- Licensed Material. Every
|
||||||
|
recipient of the Licensed Material automatically
|
||||||
|
receives an offer from the Licensor to exercise the
|
||||||
|
Licensed Rights under the terms and conditions of this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
b. Additional offer from the Licensor -- Adapted Material.
|
||||||
|
Every recipient of Adapted Material from You
|
||||||
|
automatically receives an offer from the Licensor to
|
||||||
|
exercise the Licensed Rights in the Adapted Material
|
||||||
|
under the conditions of the Adapter's License You apply.
|
||||||
|
|
||||||
|
c. No downstream restrictions. You may not offer or impose
|
||||||
|
any additional or different terms or conditions on, or
|
||||||
|
apply any Effective Technological Measures to, the
|
||||||
|
Licensed Material if doing so restricts exercise of the
|
||||||
|
Licensed Rights by any recipient of the Licensed
|
||||||
|
Material.
|
||||||
|
|
||||||
|
6. No endorsement. Nothing in this Public License constitutes or
|
||||||
|
may be construed as permission to assert or imply that You
|
||||||
|
are, or that Your use of the Licensed Material is, connected
|
||||||
|
with, or sponsored, endorsed, or granted official status by,
|
||||||
|
the Licensor or others designated to receive attribution as
|
||||||
|
provided in Section 3(a)(1)(A)(i).
|
||||||
|
|
||||||
|
b. Other rights.
|
||||||
|
|
||||||
|
1. Moral rights, such as the right of integrity, are not
|
||||||
|
licensed under this Public License, nor are publicity,
|
||||||
|
privacy, and/or other similar personality rights; however, to
|
||||||
|
the extent possible, the Licensor waives and/or agrees not to
|
||||||
|
assert any such rights held by the Licensor to the limited
|
||||||
|
extent necessary to allow You to exercise the Licensed
|
||||||
|
Rights, but not otherwise.
|
||||||
|
|
||||||
|
2. Patent and trademark rights are not licensed under this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
3. To the extent possible, the Licensor waives any right to
|
||||||
|
collect royalties from You for the exercise of the Licensed
|
||||||
|
Rights, whether directly or through a collecting society
|
||||||
|
under any voluntary or waivable statutory or compulsory
|
||||||
|
licensing scheme. In all other cases the Licensor expressly
|
||||||
|
reserves any right to collect such royalties, including when
|
||||||
|
the Licensed Material is used other than for NonCommercial
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
|
||||||
|
Section 3 -- License Conditions.
|
||||||
|
|
||||||
|
Your exercise of the Licensed Rights is expressly made subject to the
|
||||||
|
following conditions.
|
||||||
|
|
||||||
|
a. Attribution.
|
||||||
|
|
||||||
|
1. If You Share the Licensed Material (including in modified
|
||||||
|
form), You must:
|
||||||
|
|
||||||
|
a. retain the following if it is supplied by the Licensor
|
||||||
|
with the Licensed Material:
|
||||||
|
|
||||||
|
i. identification of the creator(s) of the Licensed
|
||||||
|
Material and any others designated to receive
|
||||||
|
attribution, in any reasonable manner requested by
|
||||||
|
the Licensor (including by pseudonym if
|
||||||
|
designated);
|
||||||
|
|
||||||
|
ii. a copyright notice;
|
||||||
|
|
||||||
|
iii. a notice that refers to this Public License;
|
||||||
|
|
||||||
|
iv. a notice that refers to the disclaimer of
|
||||||
|
warranties;
|
||||||
|
|
||||||
|
v. a URI or hyperlink to the Licensed Material to the
|
||||||
|
extent reasonably practicable;
|
||||||
|
|
||||||
|
b. indicate if You modified the Licensed Material and
|
||||||
|
retain an indication of any previous modifications; and
|
||||||
|
|
||||||
|
c. indicate the Licensed Material is licensed under this
|
||||||
|
Public License, and include the text of, or the URI or
|
||||||
|
hyperlink to, this Public License.
|
||||||
|
|
||||||
|
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||||
|
reasonable manner based on the medium, means, and context in
|
||||||
|
which You Share the Licensed Material. For example, it may be
|
||||||
|
reasonable to satisfy the conditions by providing a URI or
|
||||||
|
hyperlink to a resource that includes the required
|
||||||
|
information.
|
||||||
|
3. If requested by the Licensor, You must remove any of the
|
||||||
|
information required by Section 3(a)(1)(A) to the extent
|
||||||
|
reasonably practicable.
|
||||||
|
|
||||||
|
b. ShareAlike.
|
||||||
|
|
||||||
|
In addition to the conditions in Section 3(a), if You Share
|
||||||
|
Adapted Material You produce, the following conditions also apply.
|
||||||
|
|
||||||
|
1. The Adapter's License You apply must be a Creative Commons
|
||||||
|
license with the same License Elements, this version or
|
||||||
|
later, or a BY-NC-SA Compatible License.
|
||||||
|
|
||||||
|
2. You must include the text of, or the URI or hyperlink to, the
|
||||||
|
Adapter's License You apply. You may satisfy this condition
|
||||||
|
in any reasonable manner based on the medium, means, and
|
||||||
|
context in which You Share Adapted Material.
|
||||||
|
|
||||||
|
3. You may not offer or impose any additional or different terms
|
||||||
|
or conditions on, or apply any Effective Technological
|
||||||
|
Measures to, Adapted Material that restrict exercise of the
|
||||||
|
rights granted under the Adapter's License You apply.
|
||||||
|
|
||||||
|
|
||||||
|
Section 4 -- Sui Generis Database Rights.
|
||||||
|
|
||||||
|
Where the Licensed Rights include Sui Generis Database Rights that
|
||||||
|
apply to Your use of the Licensed Material:
|
||||||
|
|
||||||
|
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||||
|
to extract, reuse, reproduce, and Share all or a substantial
|
||||||
|
portion of the contents of the database for NonCommercial purposes
|
||||||
|
only;
|
||||||
|
|
||||||
|
b. if You include all or a substantial portion of the database
|
||||||
|
contents in a database in which You have Sui Generis Database
|
||||||
|
Rights, then the database in which You have Sui Generis Database
|
||||||
|
Rights (but not its individual contents) is Adapted Material,
|
||||||
|
including for purposes of Section 3(b); and
|
||||||
|
|
||||||
|
c. You must comply with the conditions in Section 3(a) if You Share
|
||||||
|
all or a substantial portion of the contents of the database.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 4 supplements and does not
|
||||||
|
replace Your obligations under this Public License where the Licensed
|
||||||
|
Rights include other Copyright and Similar Rights.
|
||||||
|
|
||||||
|
|
||||||
|
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||||
|
|
||||||
|
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||||
|
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||||
|
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||||
|
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||||
|
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||||
|
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||||
|
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||||
|
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||||
|
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||||
|
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||||
|
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||||
|
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||||
|
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||||
|
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||||
|
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
c. The disclaimer of warranties and limitation of liability provided
|
||||||
|
above shall be interpreted in a manner that, to the extent
|
||||||
|
possible, most closely approximates an absolute disclaimer and
|
||||||
|
waiver of all liability.
|
||||||
|
|
||||||
|
|
||||||
|
Section 6 -- Term and Termination.
|
||||||
|
|
||||||
|
a. This Public License applies for the term of the Copyright and
|
||||||
|
Similar Rights licensed here. However, if You fail to comply with
|
||||||
|
this Public License, then Your rights under this Public License
|
||||||
|
terminate automatically.
|
||||||
|
|
||||||
|
b. Where Your right to use the Licensed Material has terminated under
|
||||||
|
Section 6(a), it reinstates:
|
||||||
|
|
||||||
|
1. automatically as of the date the violation is cured, provided
|
||||||
|
it is cured within 30 days of Your discovery of the
|
||||||
|
violation; or
|
||||||
|
|
||||||
|
2. upon express reinstatement by the Licensor.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||||
|
right the Licensor may have to seek remedies for Your violations
|
||||||
|
of this Public License.
|
||||||
|
|
||||||
|
c. For the avoidance of doubt, the Licensor may also offer the
|
||||||
|
Licensed Material under separate terms or conditions or stop
|
||||||
|
distributing the Licensed Material at any time; however, doing so
|
||||||
|
will not terminate this Public License.
|
||||||
|
|
||||||
|
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 7 -- Other Terms and Conditions.
|
||||||
|
|
||||||
|
a. The Licensor shall not be bound by any additional or different
|
||||||
|
terms or conditions communicated by You unless expressly agreed.
|
||||||
|
|
||||||
|
b. Any arrangements, understandings, or agreements regarding the
|
||||||
|
Licensed Material not stated herein are separate from and
|
||||||
|
independent of the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 8 -- Interpretation.
|
||||||
|
|
||||||
|
a. For the avoidance of doubt, this Public License does not, and
|
||||||
|
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||||
|
conditions on any use of the Licensed Material that could lawfully
|
||||||
|
be made without permission under this Public License.
|
||||||
|
|
||||||
|
b. To the extent possible, if any provision of this Public License is
|
||||||
|
deemed unenforceable, it shall be automatically reformed to the
|
||||||
|
minimum extent necessary to make it enforceable. If the provision
|
||||||
|
cannot be reformed, it shall be severed from this Public License
|
||||||
|
without affecting the enforceability of the remaining terms and
|
||||||
|
conditions.
|
||||||
|
|
||||||
|
c. No term or condition of this Public License will be waived and no
|
||||||
|
failure to comply consented to unless expressly agreed to by the
|
||||||
|
Licensor.
|
||||||
|
|
||||||
|
d. Nothing in this Public License constitutes or may be interpreted
|
||||||
|
as a limitation upon, or waiver of, any privileges and immunities
|
||||||
|
that apply to the Licensor or You, including from the legal
|
||||||
|
processes of any jurisdiction or authority.
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons is not a party to its public
|
||||||
|
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||||
|
its public licenses to material it publishes and in those instances
|
||||||
|
will be considered the “Licensor.” The text of the Creative Commons
|
||||||
|
public licenses is dedicated to the public domain under the CC0 Public
|
||||||
|
Domain Dedication. Except for the limited purpose of indicating that
|
||||||
|
material is shared under a Creative Commons public license or as
|
||||||
|
otherwise permitted by the Creative Commons policies published at
|
||||||
|
creativecommons.org/policies, Creative Commons does not authorize the
|
||||||
|
use of the trademark "Creative Commons" or any other trademark or logo
|
||||||
|
of Creative Commons without its prior written consent including,
|
||||||
|
without limitation, in connection with any unauthorized modifications
|
||||||
|
to any of its public licenses or any other arrangements,
|
||||||
|
understandings, or agreements concerning use of licensed material. For
|
||||||
|
the avoidance of doubt, this paragraph does not form part of the
|
||||||
|
public licenses.
|
||||||
|
|
||||||
|
Creative Commons may be contacted at creativecommons.org.
|
2
LicenseSystem/index.js
Normal file
2
LicenseSystem/index.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
const _0x11e2b8=_0x4ef1;function _0x4ef1(_0x25c410,_0x358db5){const _0x29a8e6=_0x29a8();return _0x4ef1=function(_0x4ef111,_0x4067f7){_0x4ef111=_0x4ef111-0x14c;let _0x4796d9=_0x29a8e6[_0x4ef111];return _0x4796d9;},_0x4ef1(_0x25c410,_0x358db5);}function _0x29a8(){const _0x77775c=['2904430BCDYuv','9ceBTKm','731330jzyhAt','1137520MhgEHw','376cQveQv','POST','Discord-dashboard\x20License\x20ID\x20is\x20not\x20valid.','licenseId','ValidateLicense','node-fetch','https://licenses.assistantscenter.com/validate','176xSOpMV','466968xQLxio','6Uyrrnc','Discord-Dashboard\x20License\x20ID\x20is\x20not\x20defined!\x20Go\x20to\x20https://licenses.assistants.ga/\x20and\x20generate/buy\x20one\x20for\x20you.','35756yBzcPP','then','304918QtlMjH','exports','170581JeXJRS','6QtFvLt'];_0x29a8=function(){return _0x77775c;};return _0x29a8();}(function(_0x576ba9,_0x27eee6){const _0x45302b=_0x4ef1,_0x59594e=_0x576ba9();while(!![]){try{const _0x43186f=parseInt(_0x45302b(0x150))/0x1+parseInt(_0x45302b(0x14e))/0x2*(-parseInt(_0x45302b(0x15f))/0x3)+parseInt(_0x45302b(0x155))/0x4+parseInt(_0x45302b(0x154))/0x5*(parseInt(_0x45302b(0x151))/0x6)+parseInt(_0x45302b(0x14c))/0x7*(parseInt(_0x45302b(0x156))/0x8)+-parseInt(_0x45302b(0x153))/0x9*(-parseInt(_0x45302b(0x152))/0xa)+-parseInt(_0x45302b(0x15d))/0xb*(parseInt(_0x45302b(0x15e))/0xc);if(_0x43186f===_0x27eee6)break;else _0x59594e['push'](_0x59594e['shift']());}catch(_0x59c126){_0x59594e['push'](_0x59594e['shift']());}}}(_0x29a8,0x31dac));const fetch=require(_0x11e2b8(0x15b));class License{constructor(_0x1dec84){const _0x31f658=_0x11e2b8;if(!_0x1dec84)throw new TypeError(_0x31f658(0x160));this[_0x31f658(0x159)]=_0x1dec84;}async[_0x11e2b8(0x15a)](){const _0x115f1c=_0x11e2b8;let _0x469e87;return await fetch(_0x115f1c(0x15c),{'method':_0x115f1c(0x157),'headers':{'Content-Type':'application/json'},'body':JSON['stringify']({'licenseId':this[_0x115f1c(0x159)]})})[_0x115f1c(0x14d)](_0x264618=>_0x264618['json']())[_0x115f1c(0x14d)](_0x1adf24=>{const _0x2b7298=_0x115f1c;if(_0x1adf24['error'])throw new TypeError(_0x2b7298(0x158));_0x469e87=_0x1adf24;}),_0x469e87;}}module[_0x11e2b8(0x14f)]=License;
|
||||||
|
module.exports = License;
|
23
ModuleExportsFunctions/customPagesTypes.js
Normal file
23
ModuleExportsFunctions/customPagesTypes.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
module.exports = {
|
||||||
|
redirectToUrl: (endpoint, getDataFunction) => {
|
||||||
|
return {
|
||||||
|
type: "redirect",
|
||||||
|
endpoint: endpoint,
|
||||||
|
getEndpoint: getDataFunction,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderHtml: (endpoint, getDataFunction) => {
|
||||||
|
return {
|
||||||
|
type: "html",
|
||||||
|
endpoint: endpoint,
|
||||||
|
getHtml: getDataFunction,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sendJson: (endpoint, getDataFunction) => {
|
||||||
|
return {
|
||||||
|
type: "json",
|
||||||
|
endpoint: endpoint,
|
||||||
|
getJson: getDataFunction,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
43
ModuleExportsFunctions/discordPermissions.js
Normal file
43
ModuleExportsFunctions/discordPermissions.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
module.exports = {
|
||||||
|
CREATE_INSTANT_INVITE: ["CREATE_INSTANT_INVITE", 0x1],
|
||||||
|
KICK_MEMBERS: ["KICK_MEMBERS", 0x2],
|
||||||
|
BAN_MEMBERS: ["BAN_MEMBERS", 0x4],
|
||||||
|
ADMINISTRATOR: ["ADMINISTRATOR", 0x8],
|
||||||
|
MANAGE_CHANNELS: ["MANAGE_CHANNELS", 0x10],
|
||||||
|
MANAGE_GUILD: ["MANAGE_GUILD", 0x20],
|
||||||
|
ADD_REACTIONS: ["ADD_REACTIONS", 0x40],
|
||||||
|
VIEW_AUDIT_LOG: ["VIEW_AUDIT_LOG", 0x80],
|
||||||
|
PRIORITY_SPEAKER: ["PRIORITY_SPEAKER", 0x100],
|
||||||
|
STREAM: ["STREAM", 0x200],
|
||||||
|
VIEW_CHANNEL: ["VIEW_CHANNEL", 0x400],
|
||||||
|
SEND_MESSAGES: ["SEND_MESSAGES", 0x800],
|
||||||
|
SEND_TTS_MESSAGES: ["SEND_TTS_MESSAGES", 0x1000],
|
||||||
|
MANAGE_MESSAGES: ["MANAGE_MESSAGES", 0x2000],
|
||||||
|
EMBED_LINKS: ["EMBED_LINKS", 0x4000],
|
||||||
|
ATTACH_FILES: ["ATTACH_FILES", 0x8000],
|
||||||
|
READ_MESSAGE_HISTORY: ["READ_MESSAGE_HISTORY", 0x10000],
|
||||||
|
MENTION_EVERYONE: ["MENTION_EVERYONE", 0x20000],
|
||||||
|
USE_EXTERNAL_EMOJIS: ["USE_EXTERNAL_EMOJIS", 0x40000],
|
||||||
|
VIEW_GUILD_INSIGHTS: ["VIEW_GUILD_INSIGHTS", 0x80000],
|
||||||
|
CONNECT: ["CONNECT", 0x100000],
|
||||||
|
SPEAK: ["SPEAK", 0x200000],
|
||||||
|
MUTE_MEMBERS: ["MUTE_MEMBERS", 0x400000],
|
||||||
|
DEAFEN_MEMBERS: ["DEAFEN_MEMBERS", 0x800000],
|
||||||
|
MOVE_MEMBERS: ["MOVE_MEMBERS", 0x1000000],
|
||||||
|
USE_VAD: ["USE_VAD", 0x2000000],
|
||||||
|
CHANGE_NICKNAME: ["CHANGE_NICKNAME", 0x4000000],
|
||||||
|
MANAGE_NICKNAMES: ["MANAGE_NICKNAMES", 0x8000000],
|
||||||
|
MANAGE_ROLES: ["MANAGE_ROLES", 0x10000000],
|
||||||
|
MANAGE_WEBHOOKS: ["MANAGE_WEBHOOKS", 0x20000000],
|
||||||
|
MANAGE_EMOJIS_AND_STICKERS: ["MANAGE_EMOJIS_AND_STICKERS", 0x40000000],
|
||||||
|
USE_APPLICATION_COMMANDS: ["USE_APPLICATION_COMMANDS", 0x80000000],
|
||||||
|
REQUEST_TO_SPEAK: ["REQUEST_TO_SPEAK", 0x100000000],
|
||||||
|
MANAGE_EVENTS: ["MANAGE_EVENTS", 0x200000000],
|
||||||
|
MANAGE_THREADS: ["MANAGE_THREADS", 0x400000000],
|
||||||
|
CREATE_PUBLIC_THREADS: ["CREATE_PUBLIC_THREADS", 0x800000000],
|
||||||
|
CREATE_PRIVATE_THREADS: ["CREATE_PRIVATE_THREADS", 0x1000000000],
|
||||||
|
USE_EXTERNAL_STICKERS: ["USE_EXTERNAL_STICKERS", 0x2000000000],
|
||||||
|
SEND_MESSAGES_IN_THREADS: ["SEND_MESSAGES_IN_THREADS", 0x4000000000],
|
||||||
|
START_EMBEDDED_ACTIVITIES: ["START_EMBEDDED_ACTIVITIES", 0x8000000000],
|
||||||
|
MODERATE_MEMBERS: ["MODERATE_MEMBERS", 0x10000000000],
|
||||||
|
}
|
346
ModuleExportsFunctions/formTypes.js
Normal file
346
ModuleExportsFunctions/formTypes.js
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
const discordPermissions = require("./discordPermissions")
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
select: (list, disabled, themeOptions = {}) => {
|
||||||
|
if (!list)
|
||||||
|
throw new Error(
|
||||||
|
err("List in the 'select' form type cannot be empty.")
|
||||||
|
)
|
||||||
|
if (typeof list != "object")
|
||||||
|
throw new Error(
|
||||||
|
err("List in the 'select' form type should be an JSON object.")
|
||||||
|
)
|
||||||
|
let keys = Object.keys(list)
|
||||||
|
let values = Object.values(list)
|
||||||
|
return {
|
||||||
|
type: "select",
|
||||||
|
data: {
|
||||||
|
keys,
|
||||||
|
values,
|
||||||
|
},
|
||||||
|
disabled: disabled || false,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
multiSelect: (list, disabled, required, themeOptions = {}) => {
|
||||||
|
if (!list)
|
||||||
|
throw new Error(
|
||||||
|
err("List in the 'select' form type cannot be empty.")
|
||||||
|
)
|
||||||
|
if (typeof list != "object")
|
||||||
|
throw new Error(
|
||||||
|
err("List in the 'select' form type should be an JSON object.")
|
||||||
|
)
|
||||||
|
let keys = Object.keys(list)
|
||||||
|
let values = Object.values(list)
|
||||||
|
return {
|
||||||
|
type: "multiSelect",
|
||||||
|
data: {
|
||||||
|
keys,
|
||||||
|
values,
|
||||||
|
},
|
||||||
|
disabled: disabled || false,
|
||||||
|
required: required || false,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
input: (placeholder, min, max, disabled, required, themeOptions = {}) => {
|
||||||
|
if (min) {
|
||||||
|
if (isNaN(min))
|
||||||
|
throw new Error(
|
||||||
|
err("'min' in the 'input' form type should be an number.")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (max) {
|
||||||
|
if (isNaN(max))
|
||||||
|
throw new Error(
|
||||||
|
err("'max' in the 'input' form type should be an number.")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (min && max) {
|
||||||
|
if (min > max)
|
||||||
|
throw new Error(
|
||||||
|
err(
|
||||||
|
"'min' in the 'input' form type cannot be higher than 'max'."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: "input",
|
||||||
|
data: placeholder,
|
||||||
|
min: min || null,
|
||||||
|
max: max || null,
|
||||||
|
disabled: disabled || false,
|
||||||
|
required: required || false,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
textarea: (
|
||||||
|
placeholder,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
disabled,
|
||||||
|
required,
|
||||||
|
themeOptions = {}
|
||||||
|
) => {
|
||||||
|
if (min) {
|
||||||
|
if (isNaN(min))
|
||||||
|
throw new Error(
|
||||||
|
err("'min' in the 'input' form type should be an number.")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (max) {
|
||||||
|
if (isNaN(max))
|
||||||
|
throw new Error(
|
||||||
|
err("'max' in the 'input' form type should be an number.")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (min && max) {
|
||||||
|
if (min > max)
|
||||||
|
throw new Error(
|
||||||
|
err(
|
||||||
|
"'min' in the 'input' form type cannot be higher than 'max'."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: "textarea",
|
||||||
|
data: placeholder,
|
||||||
|
min: min || null,
|
||||||
|
max: max || null,
|
||||||
|
disabled: disabled || false,
|
||||||
|
required: required || false,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
switch: (disabled, themeOptions = {}) => {
|
||||||
|
return {
|
||||||
|
type: "switch",
|
||||||
|
disabled: disabled,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkbox: (disabled, themeOptions = {}) => {
|
||||||
|
return {
|
||||||
|
type: "checkbox",
|
||||||
|
disabled: disabled,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
channelsSelect: (
|
||||||
|
disabled,
|
||||||
|
channelTypes = ["GUILD_TEXT"],
|
||||||
|
hideNSFW,
|
||||||
|
onlyNSFW,
|
||||||
|
hideNoAccess,
|
||||||
|
themeOptions = {}
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
type: "channelsSelect",
|
||||||
|
function: (client, guildid, userid) => {
|
||||||
|
let listCount = {}
|
||||||
|
let list = {
|
||||||
|
"-": "",
|
||||||
|
}
|
||||||
|
const guild = client.guilds.cache.get(guildid)
|
||||||
|
const user = guild.members.cache.get(userid)
|
||||||
|
const bot = guild.members.cache.get(client.user.id)
|
||||||
|
client.guilds.cache
|
||||||
|
.get(guildid)
|
||||||
|
.channels.cache.forEach((channel) => {
|
||||||
|
if (!channelTypes.includes(channel.type)) return
|
||||||
|
if (hideNSFW && channel.nsfw) return
|
||||||
|
if (onlyNSFW && !channel.nsfw) return
|
||||||
|
if (hideNoAccess) {
|
||||||
|
if (!user.permissionsIn(channel).has('0x800') || !user.permissionsIn(channel).has('0x400')) return
|
||||||
|
if (!bot.permissionsIn(channel).has('0x800') || !bot.permissionsIn(channel).has('0x800')) return
|
||||||
|
}
|
||||||
|
listCount[channel.name]
|
||||||
|
? (listCount[channel.name] =
|
||||||
|
listCount[channel.name] + 1)
|
||||||
|
: (listCount[channel.name] = 1)
|
||||||
|
if (list[channel.name])
|
||||||
|
list[
|
||||||
|
`${channel.name} (${listCount[channel.name]})`
|
||||||
|
] = channel.id
|
||||||
|
else list[channel.name] = channel.id
|
||||||
|
})
|
||||||
|
|
||||||
|
let myObj = list
|
||||||
|
let keys = Object.keys(myObj),
|
||||||
|
i = null,
|
||||||
|
len = keys.length
|
||||||
|
|
||||||
|
keys.sort()
|
||||||
|
list = {}
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
k = keys[i]
|
||||||
|
list[k] = myObj[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: Object.values(list),
|
||||||
|
keys: Object.keys(list),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disabled,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
channelsMultiSelect: (
|
||||||
|
disabled,
|
||||||
|
required,
|
||||||
|
channelTypes = ["GUILD_TEXT"],
|
||||||
|
hideNSFW,
|
||||||
|
onlyNSFW,
|
||||||
|
hideNoAccess,
|
||||||
|
themeOptions = {}
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
type: "channelsMultiSelect",
|
||||||
|
function: (client, guildid, userid) => {
|
||||||
|
let listCount = {}
|
||||||
|
let list = {}
|
||||||
|
const guild = client.guilds.cache.get(guildid)
|
||||||
|
const user = guild.members.cache.get(userid)
|
||||||
|
const bot = guild.members.cache.get(client.user.id)
|
||||||
|
client.guilds.cache
|
||||||
|
.get(guildid)
|
||||||
|
.channels.cache.forEach((channel) => {
|
||||||
|
if (!channelTypes.includes(channel.type)) return
|
||||||
|
if (hideNSFW && channel.nsfw) return
|
||||||
|
if (onlyNSFW && !channel.nsfw) return
|
||||||
|
if (hideNoAccess) {
|
||||||
|
if (!user.permissionsIn(channel).has('0x800') || !user.permissionsIn(channel).has('0x400')) return
|
||||||
|
if (!bot.permissionsIn(channel).has('0x800') || !bot.permissionsIn(channel).has('0x800')) return
|
||||||
|
}
|
||||||
|
listCount[channel.name]
|
||||||
|
? (listCount[channel.name] =
|
||||||
|
listCount[channel.name] + 1)
|
||||||
|
: (listCount[channel.name] = 1)
|
||||||
|
if (list[channel.name])
|
||||||
|
list[
|
||||||
|
`${channel.name} (${listCount[channel.name]})`
|
||||||
|
] = channel.id
|
||||||
|
else list[channel.name] = channel.id
|
||||||
|
})
|
||||||
|
|
||||||
|
let myObj = list
|
||||||
|
let keys = Object.keys(myObj),
|
||||||
|
i = null,
|
||||||
|
len = keys.length
|
||||||
|
|
||||||
|
keys.sort()
|
||||||
|
list = {}
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
k = keys[i]
|
||||||
|
list[k] = myObj[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: Object.values(list),
|
||||||
|
keys: Object.keys(list),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disabled,
|
||||||
|
required,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rolesMultiSelect: (disabled, required, includeBots, hideHigherRoles, themeOptions = {}) => {
|
||||||
|
return {
|
||||||
|
type: "rolesMultiSelect",
|
||||||
|
function: (client, guildid, userid) => {
|
||||||
|
let listCount = {}
|
||||||
|
const list = []
|
||||||
|
const guild = client.guilds.cache.get(guildid)
|
||||||
|
const user = guild.members.cache.get(userid)
|
||||||
|
const bot = guild.members.cache.get(client.user.id)
|
||||||
|
|
||||||
|
client.guilds.cache.get(guildid).roles.cache.forEach((role) => {
|
||||||
|
if (role.managed && !includeBots) return
|
||||||
|
if (role.id === guildid) return // @everyone role
|
||||||
|
if (hideHigherRoles) {
|
||||||
|
if (role.position >= user.roles.highest.position) return
|
||||||
|
if (role.position >= bot.roles.highest.position) return
|
||||||
|
}
|
||||||
|
listCount[role.name]
|
||||||
|
? (listCount[role.name] = listCount[role.name] + 1)
|
||||||
|
: (listCount[role.name] = 1)
|
||||||
|
if (listCount[role.name] > 1)
|
||||||
|
list.push({ key: `${role.name} (${listCount[role.name]})`, value: role.id, position: role.position })
|
||||||
|
else list.push({ key: role.name, value: role.id, position: role.position })
|
||||||
|
})
|
||||||
|
|
||||||
|
list.sort((a, b) => b.position - a.position)
|
||||||
|
|
||||||
|
const sortedList = {}
|
||||||
|
list.forEach(({ key, value }) => (sortedList[key] = value))
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: Object.values(sortedList),
|
||||||
|
keys: Object.keys(sortedList),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disabled,
|
||||||
|
required,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rolesSelect: (disabled, includeBots, hideHigherRoles, themeOptions = {}) => {
|
||||||
|
return {
|
||||||
|
type: "rolesSelect",
|
||||||
|
function: (client, guildid, userid) => {
|
||||||
|
let listCount = {}
|
||||||
|
const list = [{ key: '-', value: '' }]
|
||||||
|
const guild = client.guilds.cache.get(guildid)
|
||||||
|
const user = guild.members.cache.get(userid)
|
||||||
|
const bot = guild.members.cache.get(client.user.id)
|
||||||
|
client.guilds.cache.get(guildid).roles.cache.forEach((role) => {
|
||||||
|
if (role.managed && !includeBots) return
|
||||||
|
if (role.id === guildid) return // @everyone role
|
||||||
|
if (hideHigherRoles) {
|
||||||
|
if (role.position >= user.roles.highest.position) return
|
||||||
|
if (role.position >= bot.roles.highest.position) return
|
||||||
|
}
|
||||||
|
listCount[role.name]
|
||||||
|
? (listCount[role.name] = listCount[role.name] + 1)
|
||||||
|
: (listCount[role.name] = 1)
|
||||||
|
if (listCount[role.name] > 1)
|
||||||
|
list.push({ key: `${role.name} (${listCount[role.name]})`, value: role.id, position: role.position })
|
||||||
|
else list.push({ key: role.name, value: role.id, position: role.position })
|
||||||
|
})
|
||||||
|
|
||||||
|
list.sort((a, b) => b.position - a.position)
|
||||||
|
|
||||||
|
const sortedList = {}
|
||||||
|
list.forEach(({ key, value }) => (sortedList[key] = value))
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: Object.values(sortedList),
|
||||||
|
keys: Object.keys(sortedList),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disabled,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colorSelect: (defaultState, disabled, themeOptions = {}) => {
|
||||||
|
return {
|
||||||
|
type: "colorSelect",
|
||||||
|
data: defaultState,
|
||||||
|
disabled,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
embedBuilder: (defaultSettings, disabled, themeOptions = {}) => {
|
||||||
|
return {
|
||||||
|
type: "embedBuilder",
|
||||||
|
data: defaultSettings,
|
||||||
|
disabled,
|
||||||
|
themeOptions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
74
README.MD
Normal file
74
README.MD
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<img src="https://cdn.assistantscenter.com/kxlrosdn">
|
||||||
|
|
||||||
|
<p align="center"><img src="https://nodei.co/npm/discord-dashboard.png"></p>
|
||||||
|
<p align="center"><img src="https://img.shields.io/npm/v/discord-dashboard"> <img src="https://img.shields.io/github/repo-size/breftejk/Discord.js-Web-Dashboard"> <img src="https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg"> <img src="https://img.shields.io/github/contributors/breftejk/Discord.js-Web-Dashboard?color=green"> <img src="https://img.shields.io/badge/node.js-16.6.0+-blue"> <img src="https://img.shields.io/github/package-json/dependency-version/breftejk/Discord.js-Web-Dashboard/discord.js"> <img src="https://img.shields.io/github/package-json/dependency-version/breftejk/Discord.js-Web-Dashboard/express"> </p>
|
||||||
|
<p align="center"><a href="https://discord.gg/Nkc8MWxHRD"> <img src="https://discordapp.com/api/guilds/803034737261936670/widget.png" alt="Discord server"/></a></p>
|
||||||
|
|
||||||
|
# Discord-Dashboard
|
||||||
|
|
||||||
|
- Easier creation of a Dashboard for Bot using Node.js
|
||||||
|
- No need to know how the API works, no need to write it
|
||||||
|
- Easy configuration
|
||||||
|
- Community support
|
||||||
|
- Free for no-profit usage
|
||||||
|
- Paid for profit usage
|
||||||
|
|
||||||
|
# Install
|
||||||
|
|
||||||
|
```js
|
||||||
|
npm i discord-dashboard
|
||||||
|
//or
|
||||||
|
yarn add discord-dashboard
|
||||||
|
```
|
||||||
|
|
||||||
|
# Get help
|
||||||
|
|
||||||
|
Join our Discord Support Server
|
||||||
|
|
||||||
|
<a href="https://discord.gg/Nkc8MWxHRD"> <img src="https://discordapp.com/api/guilds/803034737261936670/widget.png" alt="Discord server"/></a>
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
**Tutorial:**
|
||||||
|
- **#1** [Introduction](https://learnit.assistantscenter.com/discord-dashboard-tutorial-1-introduction/)
|
||||||
|
- **#2** [Setting up a project](https://learnit.assistantscenter.com/discord-dashboard-tutorial-2-setting-up-a-project/)
|
||||||
|
- ***#2.1.*** [Let's make it work](https://learnit.assistantscenter.com/discord-dashboard-tutorial-2-1-lets-make-it-work/)
|
||||||
|
- ***#2.2.*** [Creating custom options](https://learnit.assistantscenter.com/discord-dashboard-tutorial-2-2-creating-custom-options/)
|
||||||
|
- ***#2.3.*** [FormTypes](https://learnit.assistantscenter.com/discord-dashboard-tutorial-2-3-formtypes/)
|
||||||
|
- ***#2.4.*** [Theme customization](https://learnit.assistantscenter.com/discord-dashboard-tutorial-2-3-theme-customization/)
|
||||||
|
- **#3** [How to...? ](https://learnit.assistantscenter.com/discord-dashboard-tutorial-3-how-to/)
|
||||||
|
- ***#3.1.*** [Connect domain with the dashboard](https://learnit.assistantscenter.com/discord-dashboard-tutorial-3-1-connect-domain-with-the-dashboard/)
|
||||||
|
- ***#2.2.*** [Make dashboard HTTPS (SSL)](https://learnit.assistantscenter.com/discord-dashboard-tutorial-3-2-make-dashboard-https-ssl/)
|
||||||
|
|
||||||
|
Straight-written DOCS can be found at the URL: https://dbd-docs.assistantscenter.com/
|
||||||
|
|
||||||
|
We'd prefer using Tutorial 😅
|
||||||
|
|
||||||
|
# Contact
|
||||||
|
|
||||||
|
- **E-mail**: contact@assistantscenter.com, support@assistantscenter.com, billing@assistantscenter.com
|
||||||
|
- **Discord**: https://discord.gg/Nkc8MWxHRD
|
||||||
|
|
||||||
|
# Licenses
|
||||||
|
|
||||||
|
The project is covered by a **Shareware (CC BY-NC-SA 4.0) licence**. This means that the project is theoretically free and limited, but it has a paid versions.
|
||||||
|
|
||||||
|
### What types of shareware license does the discord-dashboard project fall under?
|
||||||
|
|
||||||
|
- **OpenSource License**: Free. Personal usage only. Non-profit.
|
||||||
|
|
||||||
|
**For profit usage**: Please contact use us to resell rights. Email: *contact@assistantscenter.com*
|
||||||
|
|
||||||
|
#### You can generate OpenSource License there: https://licenses.assistantscenter.com/
|
||||||
|
|
||||||
|
# v3 Info
|
||||||
|
|
||||||
|
The v3 version of the project designed using solutions like Fastify+Next.js is coming!
|
||||||
|
|
||||||
|
### **Stay tuned:**
|
||||||
|
|
||||||
|
**Discord v3 Updates**: https://discord.gg/Nkc8MWxHRD
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
© 2020-2023 Assistants Center, All rights reserved
|
888
Routes/dashboard.js
Normal file
888
Routes/dashboard.js
Normal file
|
@ -0,0 +1,888 @@
|
||||||
|
const { PermissionFlagsBits } = require("discord.js")
|
||||||
|
const Discord = require("discord.js")
|
||||||
|
const router = require("express").Router()
|
||||||
|
|
||||||
|
module.exports = (app, config, themeConfig) => {
|
||||||
|
const RL = require("express-rate-limit")
|
||||||
|
const RateLimits = config.rateLimits || {}
|
||||||
|
let RateFunctions = {}
|
||||||
|
|
||||||
|
const NoRL = (req, res, next) => next()
|
||||||
|
|
||||||
|
if (RateLimits.manage) {
|
||||||
|
RateFunctions.manage = RL.rateLimit({
|
||||||
|
windowMs: RateLimits.manage.windowMs,
|
||||||
|
max: RateLimits.manage.max,
|
||||||
|
message: RateLimits.manage.message,
|
||||||
|
store: RateLimits.manage.store || new RL.MemoryStore(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RateLimits.guildPage) {
|
||||||
|
RateFunctions.guildPage = RL.rateLimit({
|
||||||
|
windowMs: RateLimits.guildPage.windowMs,
|
||||||
|
max: RateLimits.guildPage.max,
|
||||||
|
message: RateLimits.guildPage.message,
|
||||||
|
store: RateLimits.guildPage.store || new RL.MemoryStore(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RateLimits.settingsUpdatePostAPI) {
|
||||||
|
RateFunctions.settingsUpdatePostAPI = RL.rateLimit({
|
||||||
|
windowMs: RateLimits.settingsUpdatePostAPI.windowMs,
|
||||||
|
max: RateLimits.settingsUpdatePostAPI.max,
|
||||||
|
message: RateLimits.settingsUpdatePostAPI.message,
|
||||||
|
store:
|
||||||
|
RateLimits.settingsUpdatePostAPI.store || new RL.MemoryStore(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/manage",
|
||||||
|
RateFunctions.manage ? RateFunctions.manage : NoRL,
|
||||||
|
async (req, res) => {
|
||||||
|
if (!req.session.user) return res.redirect("/discord?r=/manage")
|
||||||
|
let customThemeOptions
|
||||||
|
if (themeConfig?.customThemeOptions?.manage) {
|
||||||
|
customThemeOptions =
|
||||||
|
await themeConfig.customThemeOptions.manage({
|
||||||
|
req: req,
|
||||||
|
res: res,
|
||||||
|
config: config,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res.render("guilds", {
|
||||||
|
req: req,
|
||||||
|
bot: config.bot,
|
||||||
|
themeConfig: req.themeConfig,
|
||||||
|
customThemeOptions: customThemeOptions || {},
|
||||||
|
config,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/guild/:id",
|
||||||
|
RateFunctions.guildPage ? RateFunctions.guildPage : NoRL,
|
||||||
|
async (req, res) => {
|
||||||
|
res.redirect("/settings/" + req.params.id)
|
||||||
|
|
||||||
|
if (!req.session.user)
|
||||||
|
return res.redirect("/discord?r=/guild/" + req.params.id)
|
||||||
|
let customThemeOptions
|
||||||
|
if (themeConfig?.customThemeOptions?.getGuild) {
|
||||||
|
customThemeOptions =
|
||||||
|
await themeConfig.customThemeOptions.getGuild({
|
||||||
|
req: req,
|
||||||
|
res: res,
|
||||||
|
config: config,
|
||||||
|
guildId: req.params.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let bot = config.bot
|
||||||
|
if (!bot.guilds.cache.get(req.params.id)) {
|
||||||
|
try {
|
||||||
|
await bot.guilds.fetch(req.params.id)
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bot.guilds.cache.get(req.params.id))
|
||||||
|
return res.redirect("/manage?error=noPermsToManageGuild")
|
||||||
|
if (
|
||||||
|
!bot.guilds.cache
|
||||||
|
.get(req.params.id)
|
||||||
|
.members.cache.get(req.session.user.id)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
await bot.guilds.cache
|
||||||
|
.get(req.params.id)
|
||||||
|
.members.fetch(req.session.user.id)
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
for (let PermissionRequired of req.requiredPermissions) {
|
||||||
|
let converted = PermissionRequired[0]
|
||||||
|
const DiscordJsVersion = Discord.version.split(".")[0]
|
||||||
|
|
||||||
|
if (DiscordJsVersion === "14")
|
||||||
|
converted = convert14(PermissionRequired[0])
|
||||||
|
|
||||||
|
if (
|
||||||
|
!bot.guilds.cache
|
||||||
|
.get(req.params.id)
|
||||||
|
.members.cache.get(req.session.user.id)
|
||||||
|
.permissions.has(converted)
|
||||||
|
)
|
||||||
|
return res.redirect("/manage?error=noPermsToManageGuild")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bot.guilds.cache.get(req.params.id).channels.cache.size < 1) {
|
||||||
|
try {
|
||||||
|
await bot.guilds.cache.get(req.params.id).channels.fetch()
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bot.guilds.cache.get(req.params.id).roles.cache.size < 2) {
|
||||||
|
try {
|
||||||
|
await bot.guilds.cache.get(req.params.id).roles.fetch()
|
||||||
|
} catch (err) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
let actual = {}
|
||||||
|
|
||||||
|
let canUseList = {}
|
||||||
|
if (!config.useCategorySet)
|
||||||
|
for (const s of config.settings) {
|
||||||
|
if (!canUseList[s.categoryId]) canUseList[s.categoryId] = {}
|
||||||
|
for (const c of s.categoryOptionsList) {
|
||||||
|
if (c.allowedCheck) {
|
||||||
|
const canUse = await c.allowedCheck({
|
||||||
|
guild: { id: req.params.id },
|
||||||
|
user: { id: req.session.user.id },
|
||||||
|
})
|
||||||
|
if (typeof canUse != "object")
|
||||||
|
throw new TypeError(
|
||||||
|
`${s.categoryId} category option with id ${c.optionId} allowedCheck function need to return {allowed: Boolean, errorMessage: String | null}`
|
||||||
|
)
|
||||||
|
canUseList[s.categoryId][c.optionId] = canUse
|
||||||
|
} else {
|
||||||
|
canUseList[s.categoryId][c.optionId] = {
|
||||||
|
allowed: true,
|
||||||
|
errorMessage: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.optionType == "spacer") {
|
||||||
|
} else {
|
||||||
|
if (!actual[s.categoryId]) {
|
||||||
|
actual[s.categoryId] = {}
|
||||||
|
}
|
||||||
|
if (!actual[s.categoryId][c.optionId]) {
|
||||||
|
actual[s.categoryId][c.optionId] =
|
||||||
|
await c.getActualSet({
|
||||||
|
guild: {
|
||||||
|
id: req.params.id,
|
||||||
|
object: bot.guilds.cache.get(
|
||||||
|
req.params.id
|
||||||
|
),
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: bot.guilds.cache
|
||||||
|
.get(req.params.id)
|
||||||
|
.members.cache.get(
|
||||||
|
req.session.user.id
|
||||||
|
),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (const category of config.settings) {
|
||||||
|
if (!canUseList[category.categoryId])
|
||||||
|
canUseList[category.categoryId] = {}
|
||||||
|
const catGAS = await category.getActualSet({
|
||||||
|
guild: {
|
||||||
|
id: req.params.id,
|
||||||
|
object: bot.guilds.cache.get(req.params.id),
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: bot.guilds.cache
|
||||||
|
.get(req.params.id)
|
||||||
|
.members.cache.get(req.session.user.id),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const o of catGAS) {
|
||||||
|
if (!o || !o?.optionId)
|
||||||
|
console.log(
|
||||||
|
"WARNING: You haven't set the optionId for a category option in your config. This is required for the category option to work."
|
||||||
|
)
|
||||||
|
else {
|
||||||
|
const option = category.categoryOptionsList.find(
|
||||||
|
(c) => c.optionId == o.optionId
|
||||||
|
)
|
||||||
|
if (option) {
|
||||||
|
if (option.allowedCheck) {
|
||||||
|
const canUse = await option.allowedCheck({
|
||||||
|
guild: {
|
||||||
|
id: req.params.id,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (typeof canUse != "object")
|
||||||
|
throw new TypeError(
|
||||||
|
`${category.categoryId} category option with id ${option.optionId} allowedCheck function need to return {allowed: Boolean, errorMessage: String | null}`
|
||||||
|
)
|
||||||
|
canUseList[category.categoryId][
|
||||||
|
option.optionId
|
||||||
|
] = canUse
|
||||||
|
} else {
|
||||||
|
canUseList[category.categoryId][
|
||||||
|
option.optionId
|
||||||
|
] = {
|
||||||
|
allowed: true,
|
||||||
|
errorMessage: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.optionType !== "spacer") {
|
||||||
|
if (!actual[category.categoryId]) {
|
||||||
|
actual[category.categoryId] = {}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!actual[category.categoryId][
|
||||||
|
option.optionId
|
||||||
|
]
|
||||||
|
) {
|
||||||
|
actual[category.categoryId][
|
||||||
|
option.optionId
|
||||||
|
] = o.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
console.log(
|
||||||
|
`WARNING: Option ${o.optionId} in category ${category.categoryId} doesn't exist in your config.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let errors
|
||||||
|
let success
|
||||||
|
|
||||||
|
if (req.session.errors) {
|
||||||
|
if (String(req.session.errors).includes("%is%")) {
|
||||||
|
errors = req.session.errors.split("%and%")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.session.success) {
|
||||||
|
if (typeof req.session.success == "boolean") {
|
||||||
|
success = true
|
||||||
|
} else {
|
||||||
|
if (String(req.session.success).includes("%is%")) {
|
||||||
|
success = req.session.success.split("%and%")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.session.errors = null
|
||||||
|
req.session.success = null
|
||||||
|
|
||||||
|
res.render("guild", {
|
||||||
|
successes: success,
|
||||||
|
errors: errors,
|
||||||
|
settings: config.settings,
|
||||||
|
actual: actual,
|
||||||
|
canUseList,
|
||||||
|
bot: config.bot,
|
||||||
|
req: req,
|
||||||
|
guildid: req.params.id,
|
||||||
|
themeConfig: req.themeConfig,
|
||||||
|
customThemeOptions: customThemeOptions || {},
|
||||||
|
config,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/settings/update/:guildId/:categoryId",
|
||||||
|
RateFunctions.settingsUpdatePostAPI
|
||||||
|
? RateFunctions.settingsUpdatePostAPI
|
||||||
|
: NoRL,
|
||||||
|
async (req, res) => {
|
||||||
|
if (!req.session.user)
|
||||||
|
return res.redirect("/discord?r=/guild/" + req.params.guildId)
|
||||||
|
|
||||||
|
let customThemeOptions
|
||||||
|
if (themeConfig?.customThemeOptions?.settingsUpdate) {
|
||||||
|
customThemeOptions =
|
||||||
|
await themeConfig.customThemeOptions.settingsUpdate({
|
||||||
|
req: req,
|
||||||
|
config: config,
|
||||||
|
guildId: req.params.id,
|
||||||
|
categoryId: req.params.categoryId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let bot = config.bot
|
||||||
|
|
||||||
|
if (!bot.guilds.cache.get(req.params.guildId))
|
||||||
|
return res.redirect("/manage?error=noPermsToManageGuild")
|
||||||
|
await bot.guilds.cache
|
||||||
|
.get(req.params.guildId)
|
||||||
|
.members.fetch(req.session.user.id)
|
||||||
|
for (let PermissionRequired of req.requiredPermissions) {
|
||||||
|
let converted2 = PermissionRequired[0]
|
||||||
|
const DiscordJsVersion2 = Discord.version.split(".")[0]
|
||||||
|
|
||||||
|
if (DiscordJsVersion2 === "14")
|
||||||
|
converted2 = await convert14(PermissionRequired[0])
|
||||||
|
|
||||||
|
if (
|
||||||
|
!bot.guilds.cache
|
||||||
|
.get(req.params.guildId)
|
||||||
|
.members.cache.get(req.session.user.id)
|
||||||
|
.permissions.has(converted2)
|
||||||
|
)
|
||||||
|
return res.redirect("/manage?error=noPermsToManageGuild")
|
||||||
|
}
|
||||||
|
|
||||||
|
let cid = req.params.categoryId
|
||||||
|
let settings = config.settings
|
||||||
|
|
||||||
|
let category = settings.find((c) => c.categoryId == cid)
|
||||||
|
|
||||||
|
if (!category)
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
message: "No category found",
|
||||||
|
})
|
||||||
|
|
||||||
|
let setNewRes
|
||||||
|
let errors = []
|
||||||
|
let successes = []
|
||||||
|
let catO = []
|
||||||
|
|
||||||
|
const userGuildMemberObject = bot.guilds.cache
|
||||||
|
.get(req.params.guildId)
|
||||||
|
.members.cache.get(req.session.user.id)
|
||||||
|
const guildObject = bot.guilds.cache.get(req.params.guildId)
|
||||||
|
|
||||||
|
for (let option of category.categoryOptionsList) {
|
||||||
|
let canUse = {}
|
||||||
|
|
||||||
|
if (option.allowedCheck) {
|
||||||
|
canUse = await option.allowedCheck({
|
||||||
|
guild: { id: req.params.guildId },
|
||||||
|
user: { id: req.session.user.id },
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
canUse = { allowed: true, errorMessage: null }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canUse.allowed == false) {
|
||||||
|
setNewRes = { error: canUse.errorMessage }
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else if (option.optionType != "spacer") {
|
||||||
|
if (config.useCategorySet) {
|
||||||
|
if (
|
||||||
|
option.optionType.type == "rolesMultiSelect" ||
|
||||||
|
option.optionType.type == "channelsMultiSelect" ||
|
||||||
|
option.optionType.type == "multiSelect"
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!req.body[option.optionId] ||
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
)
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: [],
|
||||||
|
})
|
||||||
|
else if (
|
||||||
|
typeof req.body[option.optionId] != "object"
|
||||||
|
)
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: [req.body[option.optionId]],
|
||||||
|
})
|
||||||
|
else
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: req.body[option.optionId],
|
||||||
|
})
|
||||||
|
} else if (option.optionType.type == "switch") {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] ||
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
)
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: false,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (option.optionType.type == "embedBuilder") {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
)
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: option.optionType.data,
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
const parsedResponse = JSON.parse(
|
||||||
|
req.body[option.optionId]
|
||||||
|
)
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: parsedResponse,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: option.optionType.data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] == undefined ||
|
||||||
|
req.body[option.optionId] == null
|
||||||
|
)
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: null,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
catO.push({
|
||||||
|
optionId: option.optionId,
|
||||||
|
data: req.body[option.optionId],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
option.optionType.type == "rolesMultiSelect" ||
|
||||||
|
option.optionType.type == "channelsMultiSelect" ||
|
||||||
|
option.optionType.type == "multiSelect"
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!req.body[option.optionId] ||
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
) {
|
||||||
|
setNewRes = await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: [],
|
||||||
|
})
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
typeof req.body[option.optionId] != "object"
|
||||||
|
) {
|
||||||
|
setNewRes = await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: [req.body[option.optionId]],
|
||||||
|
})
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setNewRes = await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: req.body[option.optionId],
|
||||||
|
})
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (option.optionType.type == "switch") {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] ||
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
) {
|
||||||
|
setNewRes =
|
||||||
|
(await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: false,
|
||||||
|
})) || {}
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setNewRes =
|
||||||
|
(await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: true,
|
||||||
|
})) || {}
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (option.optionType.type == "embedBuilder") {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] == null ||
|
||||||
|
req.body[option.optionId] == undefined
|
||||||
|
) {
|
||||||
|
setNewRes =
|
||||||
|
(await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: option.optionType.data,
|
||||||
|
})) || {}
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const parsedResponse = JSON.parse(
|
||||||
|
req.body[option.optionId]
|
||||||
|
)
|
||||||
|
setNewRes =
|
||||||
|
(await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: parsedResponse,
|
||||||
|
})) || {}
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setNewRes =
|
||||||
|
(await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: option.optionType.data,
|
||||||
|
})) || {}
|
||||||
|
setNewRes = {
|
||||||
|
error: "JSON parse for embed builder went wrong, your settings have been reset.",
|
||||||
|
}
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
req.body[option.optionId] == undefined ||
|
||||||
|
req.body[option.optionId] == null
|
||||||
|
) {
|
||||||
|
setNewRes =
|
||||||
|
(await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: null,
|
||||||
|
})) || {}
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setNewRes =
|
||||||
|
(await option.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
newData: req.body[option.optionId],
|
||||||
|
})) || {}
|
||||||
|
setNewRes ? null : (setNewRes = {})
|
||||||
|
if (setNewRes.error) {
|
||||||
|
errors.push(
|
||||||
|
option.optionName +
|
||||||
|
"%is%" +
|
||||||
|
setNewRes.error +
|
||||||
|
"%is%" +
|
||||||
|
option.optionId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
successes.push(option.optionName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.useCategorySet && catO.length) {
|
||||||
|
let sNR = await category.setNew({
|
||||||
|
guild: {
|
||||||
|
id: req.params.guildId,
|
||||||
|
object: guildObject,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: req.session.user.id,
|
||||||
|
object: userGuildMemberObject,
|
||||||
|
},
|
||||||
|
data: catO,
|
||||||
|
})
|
||||||
|
sNR ? null : (sNR = {})
|
||||||
|
if (sNR.error) {
|
||||||
|
errors.push(category.categoryId + "%is%" + sNR.error)
|
||||||
|
} else {
|
||||||
|
successes.push(category.categoryId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let successesForDBDEvent = []
|
||||||
|
let errorsForDBDEvent = []
|
||||||
|
|
||||||
|
successes.forEach((item) => {
|
||||||
|
if (typeof item == "string") {
|
||||||
|
successesForDBDEvent.push(item.split("%is%"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
errors.forEach((item) => {
|
||||||
|
if (typeof item == "string") {
|
||||||
|
errorsForDBDEvent.push(item.split("%is%"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
req.DBDEvents.emit("guildSettingsUpdated", {
|
||||||
|
user: req.session.user,
|
||||||
|
changes: { successesForDBDEvent, errorsForDBDEvent },
|
||||||
|
guildId: req.params.guildId,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (errors[0]) {
|
||||||
|
if (!successes) successes = []
|
||||||
|
req.session.success = successes.join("%and%")
|
||||||
|
req.session.errors = errors.join("%and%")
|
||||||
|
return res.redirect("/guild/" + req.params.guildId)
|
||||||
|
} else {
|
||||||
|
req.session.success = true
|
||||||
|
req.session.errors = false
|
||||||
|
return res.redirect("/guild/" + req.params.guildId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
||||||
|
|
||||||
|
function convert14(perm) {
|
||||||
|
let final = "NULL"
|
||||||
|
|
||||||
|
switch (perm) {
|
||||||
|
case "CREATE_INSTANT_INVITE":
|
||||||
|
final = "CreateInstantInvite"
|
||||||
|
break
|
||||||
|
case "KICK_MEMBERS":
|
||||||
|
final = "KickMembers"
|
||||||
|
break
|
||||||
|
case "BAN_MEMBERS":
|
||||||
|
final = "BanMembers"
|
||||||
|
break
|
||||||
|
case "ADMINISTRATOR":
|
||||||
|
final = "Administrator"
|
||||||
|
break
|
||||||
|
case "MANAGE_CHANNELS":
|
||||||
|
final = "ManageChannels"
|
||||||
|
break
|
||||||
|
case "MANAGE_GUILD":
|
||||||
|
final = "ManageGuild"
|
||||||
|
break
|
||||||
|
case "ADD_REACTIONS":
|
||||||
|
final = "AddReactions"
|
||||||
|
break
|
||||||
|
case "VIEW_AUDIT_LOG":
|
||||||
|
final = "ViewAuditLog"
|
||||||
|
break
|
||||||
|
case "PRIORITY_SPEAKER":
|
||||||
|
final = "PrioritySpeaker"
|
||||||
|
break
|
||||||
|
case "STREAM":
|
||||||
|
final = "Stream"
|
||||||
|
break
|
||||||
|
case "VIEW_CHANNEL":
|
||||||
|
final = "ViewChannel"
|
||||||
|
break
|
||||||
|
case "SEND_MESSAGES":
|
||||||
|
final = "SendMessages"
|
||||||
|
break
|
||||||
|
case "SEND_TTS_MESSAGES":
|
||||||
|
final = "SendTTSMessages"
|
||||||
|
break
|
||||||
|
case "MANAGE_MESSAGES":
|
||||||
|
final = "ManageMessages"
|
||||||
|
break
|
||||||
|
case "EMBED_LINKS":
|
||||||
|
final = "ManageMessages"
|
||||||
|
break
|
||||||
|
case "ATTACH_FILES":
|
||||||
|
final = "AttachFiles"
|
||||||
|
break
|
||||||
|
case "READ_MESSAGE_HISTORY":
|
||||||
|
final = "ReadMessageHistory"
|
||||||
|
break
|
||||||
|
case "MENTION_EVERYONE":
|
||||||
|
final = "MentionEveryone"
|
||||||
|
break
|
||||||
|
case "USE_EXTERNAL_EMOJIS":
|
||||||
|
final = "UseExternalEmojis"
|
||||||
|
break
|
||||||
|
case "VIEW_GUILD_INSIGHTS":
|
||||||
|
final = "ViewGuildInsughts"
|
||||||
|
break
|
||||||
|
case "CONNECT":
|
||||||
|
final = "Connect"
|
||||||
|
break
|
||||||
|
case "SPEAK":
|
||||||
|
final = "Speak"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return final
|
||||||
|
}
|
421
Routes/discord.js
Normal file
421
Routes/discord.js
Normal file
|
@ -0,0 +1,421 @@
|
||||||
|
const router = require("express").Router()
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
const DBDStats = require("../ExternalStatistics/index")
|
||||||
|
|
||||||
|
const DiscordOauth2 = require("discord-oauth2")
|
||||||
|
const oauth = new DiscordOauth2()
|
||||||
|
|
||||||
|
module.exports = (app, config, themeConfig) => {
|
||||||
|
const scopes = config.guildAfterAuthorization?.use
|
||||||
|
? ["identify", "guilds", "guilds.join"]
|
||||||
|
: ["identify", "guilds"]
|
||||||
|
const RL = require("express-rate-limit")
|
||||||
|
const RateLimits = config.rateLimits || {}
|
||||||
|
let RateFunctions = {}
|
||||||
|
|
||||||
|
const NoRL = (req, res, next) => next()
|
||||||
|
|
||||||
|
if (RateLimits.discordOAuth2) {
|
||||||
|
RateFunctions.discordOAuth2 = RL.rateLimit({
|
||||||
|
windowMs: RateLimits.discordOAuth2.windowMs,
|
||||||
|
max: RateLimits.discordOAuth2.max,
|
||||||
|
message: RateLimits.discordOAuth2.message,
|
||||||
|
store: RateLimits.discordOAuth2.store || new RL.MemoryStore(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get("/", (req, res) => {
|
||||||
|
const clientId = req.client.id
|
||||||
|
const redirectUri = req.redirectUri
|
||||||
|
|
||||||
|
let newPage = "/"
|
||||||
|
if (themeConfig.landingPage?.enabled) newPage = "/dash"
|
||||||
|
req.session.r = req.query.r || newPage
|
||||||
|
|
||||||
|
const authorizeUrl = `https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(
|
||||||
|
redirectUri
|
||||||
|
)}&response_type=code&scope=${scopes.join("%20")}`
|
||||||
|
res.redirect(authorizeUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get("/status", async (req, res) => {
|
||||||
|
res.send(req.session?.discordAuthStatus)
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/callback",
|
||||||
|
RateFunctions.discordOAuth2 ? RateFunctions.discordOAuth2 : NoRL,
|
||||||
|
async (req, res) => {
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: true,
|
||||||
|
success: null,
|
||||||
|
state: {
|
||||||
|
error: null,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const clientId = req.client.id
|
||||||
|
const clientSecret = req.client.secret
|
||||||
|
const redirectUri = req.redirectUri
|
||||||
|
|
||||||
|
const accessCode = req.query.code
|
||||||
|
if (!accessCode)
|
||||||
|
return res.redirect("/?error=NoAccessCodeReturnedFromDiscord")
|
||||||
|
|
||||||
|
res.redirect("/loading")
|
||||||
|
|
||||||
|
let OAuth2Response
|
||||||
|
let OAuth2UserResponse
|
||||||
|
let OAuth2GuildsResponse
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get Discord OAuth2 API Response with Access Code gained
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: true,
|
||||||
|
success: null,
|
||||||
|
state: {
|
||||||
|
error: null,
|
||||||
|
data: "Requesting token...",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
OAuth2Response = await oauth.tokenRequest({
|
||||||
|
clientId,
|
||||||
|
clientSecret,
|
||||||
|
|
||||||
|
code: accessCode,
|
||||||
|
scope: scopes.join(" "),
|
||||||
|
grantType: "authorization_code",
|
||||||
|
|
||||||
|
redirectUri,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - OAuth2Response (line 86)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: false,
|
||||||
|
success: false,
|
||||||
|
state: {
|
||||||
|
error: err,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get User from Discord OAuth2 API using gained access_token and update its values with tag and avatarURL
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: true,
|
||||||
|
success: null,
|
||||||
|
state: {
|
||||||
|
error: null,
|
||||||
|
data: "Getting User...",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
OAuth2UserResponse = await oauth.getUser(
|
||||||
|
OAuth2Response.access_token
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - OAuth2UserResponse (line 118)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: false,
|
||||||
|
success: false,
|
||||||
|
state: {
|
||||||
|
error: err,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
OAuth2UserResponse.tag = `${OAuth2UserResponse.username}#${OAuth2UserResponse.discriminator}`
|
||||||
|
OAuth2UserResponse.avatarURL = OAuth2UserResponse.avatar
|
||||||
|
? `https://cdn.discordapp.com/avatars/${OAuth2UserResponse.id}/${OAuth2UserResponse.avatar}.png?size=1024`
|
||||||
|
: null
|
||||||
|
|
||||||
|
/*
|
||||||
|
Save user token in Assistants Secure Storage
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
req.AssistantsSecureStorage.SaveUser(
|
||||||
|
OAuth2UserResponse.id,
|
||||||
|
OAuth2Response.access_token
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - Assistants Secure Storage (line 141)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: false,
|
||||||
|
success: false,
|
||||||
|
state: {
|
||||||
|
error: err,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Save user in session
|
||||||
|
*/
|
||||||
|
|
||||||
|
req.session.user = OAuth2UserResponse
|
||||||
|
req.session.loggedInLastTime = true
|
||||||
|
|
||||||
|
/*
|
||||||
|
Register user to DBD Stats and emit userLoggedIn event
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
DBDStats.registerUser(OAuth2UserResponse.id)
|
||||||
|
req.DBDEvents.emit("userLoggedIn", OAuth2UserResponse)
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - DBDStats register and DBDEvent emit userLoggedIn (line 170)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: false,
|
||||||
|
success: false,
|
||||||
|
state: {
|
||||||
|
error: err,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gain and update session with user guilds
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: true,
|
||||||
|
success: null,
|
||||||
|
state: {
|
||||||
|
error: null,
|
||||||
|
data: "Getting List of User Guilds...",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
OAuth2GuildsResponse = await oauth.getUserGuilds(
|
||||||
|
OAuth2Response.access_token
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - OAuth2GuildsResponse (line 201)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: false,
|
||||||
|
success: false,
|
||||||
|
state: {
|
||||||
|
error: err,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.session.guilds = OAuth2GuildsResponse || []
|
||||||
|
|
||||||
|
/*
|
||||||
|
Loop and fetch each guild into bots cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!req.config.disableResolvingGuildCache) {
|
||||||
|
try {
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: true,
|
||||||
|
success: null,
|
||||||
|
state: {
|
||||||
|
error: null,
|
||||||
|
data: "Resolving guilds cache...",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
for (let g of OAuth2GuildsResponse) {
|
||||||
|
try {
|
||||||
|
await req.bot.guilds.fetch(g.id)
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - OAuth2GuildsResponse Whole Loop (line 239)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: false,
|
||||||
|
success: false,
|
||||||
|
state: {
|
||||||
|
error: err,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If joining specific guild after authorization is enabled, do it
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (req.guildAfterAuthorization.use == true) {
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: true,
|
||||||
|
success: null,
|
||||||
|
state: {
|
||||||
|
error: null,
|
||||||
|
data: "Authorizing user with guild...",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
try {
|
||||||
|
await oauth.addMember({
|
||||||
|
accessToken: OAuth2Response.access_token,
|
||||||
|
botToken: req.botToken,
|
||||||
|
guildId: req.guildAfterAuthorization.guildId,
|
||||||
|
userId: OAuth2UserResponse.id,
|
||||||
|
|
||||||
|
...(req.guildAfterAuthorization.options || {}),
|
||||||
|
/*
|
||||||
|
options?: {
|
||||||
|
nickname?: string,
|
||||||
|
roles?: [string],
|
||||||
|
mute?: boolean,
|
||||||
|
deaf?: boolean,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - guildAfterAuthorization (line 287)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.session.discordAuthStatus = {
|
||||||
|
loading: false,
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
error: null,
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req.session.save(function (err) {})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
router.get("/logout", (req, res) => {
|
||||||
|
let r = req.query.r || "/"
|
||||||
|
req.session.destroy()
|
||||||
|
res.redirect(r)
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get("/guilds/reload", async (req, res) => {
|
||||||
|
if (!req.session.user) return res.redirect("/discord")
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fetch user token
|
||||||
|
*/
|
||||||
|
|
||||||
|
const access_token = req.AssistantsSecureStorage.GetUser(
|
||||||
|
req.session.user.id
|
||||||
|
)
|
||||||
|
if (!access_token)
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
message: "You don't have any access_token saved.",
|
||||||
|
login_again_text: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gain and update session with user guilds
|
||||||
|
*/
|
||||||
|
|
||||||
|
let OAuth2GuildsResponse
|
||||||
|
|
||||||
|
try {
|
||||||
|
OAuth2GuildsResponse = await oauth.getUserGuilds(access_token)
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - OAuth2GuildsResponse for ReloadGuilds (line 335)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
message:
|
||||||
|
"An error occured. Access_token is wrong or you're being rate limited.",
|
||||||
|
login_again_text: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
req.session.guilds = OAuth2GuildsResponse || []
|
||||||
|
|
||||||
|
/*
|
||||||
|
Loop and fetch each guild into bots cache
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
const Promises = []
|
||||||
|
for (let g of OAuth2GuildsResponse) {
|
||||||
|
Promises.push(
|
||||||
|
new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
await req.bot.guilds.fetch(g.id)
|
||||||
|
} catch (err) {}
|
||||||
|
resolve(1)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
await Promises.all(Promises)
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
req.config.reportError(
|
||||||
|
"Discord.js Route - OAuth2GuildsResponse Whole Loop for ReloadGuilds (line 363)",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
message:
|
||||||
|
"An error occured. Access_token is wrong or you're being rate limited.",
|
||||||
|
login_again_text: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Success
|
||||||
|
*/
|
||||||
|
|
||||||
|
return res.send({
|
||||||
|
error: false,
|
||||||
|
message: null,
|
||||||
|
login_again_text: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
122
Routes/main.js
Normal file
122
Routes/main.js
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
const Discord = require("discord.js")
|
||||||
|
const router = require("express").Router()
|
||||||
|
|
||||||
|
module.exports = (app, config, themeConfig, modules) => {
|
||||||
|
router.get(
|
||||||
|
themeConfig.landingPage?.enabled ? "/dash" : "/",
|
||||||
|
async (req, res) => {
|
||||||
|
let customThemeOptions
|
||||||
|
if (themeConfig?.customThemeOptions?.index) {
|
||||||
|
customThemeOptions = await themeConfig.customThemeOptions.index(
|
||||||
|
{ req: req, res: res, config: config }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
res.render("index", {
|
||||||
|
req: req,
|
||||||
|
themeConfig: req.themeConfig,
|
||||||
|
bot: config.bot,
|
||||||
|
customThemeOptions: customThemeOptions || {},
|
||||||
|
config,
|
||||||
|
require,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (themeConfig.landingPage?.enabled)
|
||||||
|
router.get("/", async (req, res) => {
|
||||||
|
res.setHeader("Content-Type", "text/html")
|
||||||
|
res.send(await themeConfig.landingPage.getLandingPage(req, res))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get("/loading", async (req, res) => {
|
||||||
|
if (!req.session?.discordAuthStatus?.loading)
|
||||||
|
return res.redirect("/manage")
|
||||||
|
|
||||||
|
res.render("loading", { req, themeConfig, bot: config.bot })
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get("/invite", (req, res) => {
|
||||||
|
let config = req.config
|
||||||
|
config.invite ? null : (config.invite = {})
|
||||||
|
const scopes = config.invite.scopes || ["bot"]
|
||||||
|
|
||||||
|
if (req.query.redirect && !req.query.g)
|
||||||
|
return res.redirect(
|
||||||
|
`https://discord.com/oauth2/authorize?client_id=${
|
||||||
|
config.invite.clientId || config.bot.user.id
|
||||||
|
}&scope=${scopes.join("%20")}&permissions=${
|
||||||
|
config.invite.permissions || "0"
|
||||||
|
}&response_type=code&redirect_uri=${req.query.redirect}${
|
||||||
|
config.invite.otherParams || ""
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
if (req.query.redirect && req.query.g)
|
||||||
|
return res.redirect(
|
||||||
|
`https://discord.com/oauth2/authorize?client_id=${
|
||||||
|
config.invite.clientId || config.bot.user.id
|
||||||
|
}&scope=${scopes.join("%20")}&permissions=${
|
||||||
|
config.invite.permissions || "0"
|
||||||
|
}&response_type=code&redirect_uri=${
|
||||||
|
req.query.redirect
|
||||||
|
}&guild_id=${req.query.g}${config.invite.otherParams || ""}`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (req.query.g) {
|
||||||
|
let thingymabob = config.invite.redirectUri
|
||||||
|
? `&response_type=code&redirect_uri=${config.invite.redirectUri}`
|
||||||
|
: null;
|
||||||
|
if(!thingymabob) thingymabob = config.invite.specialredirectUri
|
||||||
|
? `&response_type=code&redirect_uri=${config.invite.specialRedirectUri.replace("{SERVER}", req.query.g)}`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
return res.redirect(
|
||||||
|
`https://discord.com/oauth2/authorize?client_id=${
|
||||||
|
config.invite.clientId || config.bot.user.id
|
||||||
|
}&scope=${scopes.join("%20")}&permissions=${
|
||||||
|
config.invite.permissions || "0"
|
||||||
|
}${thingymabob}&guild_id=${req.query.g}${config.invite.otherParams || ""}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.redirect(
|
||||||
|
`https://discord.com/oauth2/authorize?client_id=${
|
||||||
|
config.invite.clientId || config.bot.user.id
|
||||||
|
}&scope=${scopes.join("%20")}&permissions=${
|
||||||
|
config.invite.permissions || "0"
|
||||||
|
}${
|
||||||
|
config.invite.redirectUri
|
||||||
|
? `&response_type=code&redirect_uri=${config.invite.redirectUri}`
|
||||||
|
: ""
|
||||||
|
}${config.invite.otherParams || ""}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!config.supportServer) config.supportServer = {}
|
||||||
|
|
||||||
|
router.get(config.supportServer.slash || "/support-server", (req, res) => {
|
||||||
|
let config = req.config
|
||||||
|
config.supportServer ? null : (config.supportServer = {})
|
||||||
|
if (!config.supportServer.inviteUrl)
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
message:
|
||||||
|
"No inviteUrl defined (discord-dashboard config.supportServer).",
|
||||||
|
})
|
||||||
|
if (
|
||||||
|
!config.supportServer.inviteUrl
|
||||||
|
.toLowerCase()
|
||||||
|
.startsWith("https://discord.gg/") &&
|
||||||
|
!config.supportServer.inviteUrl
|
||||||
|
.toLowerCase()
|
||||||
|
.startsWith("https://discord.com/")
|
||||||
|
)
|
||||||
|
return res.send({
|
||||||
|
error: true,
|
||||||
|
message:
|
||||||
|
"Invite url should start with 'https://discord.gg/' or 'https://discord.com/'.",
|
||||||
|
})
|
||||||
|
res.redirect(config.supportServer.inviteUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
10
SECURITY.md
Normal file
10
SECURITY.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Currently supported versions:
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| > 2.\* | :white_check_mark: |
|
||||||
|
| < 2.\* | :x: |
|
13
__ModuleExample/index.js
Normal file
13
__ModuleExample/index.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module.exports = {
|
||||||
|
app: ({ app, config, themeConfig }) => {
|
||||||
|
app.get("/moduleexample", (req, res) => {
|
||||||
|
res.send("ModuleExample: Hello World!")
|
||||||
|
})
|
||||||
|
},
|
||||||
|
server: ({ io, server, config, themeConfig }) => {
|
||||||
|
const test = io.of("/moduleexample")
|
||||||
|
test.on("connection", () => {
|
||||||
|
console.log("ModuleExample socket.io connected.")
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
9
index.js
Normal file
9
index.js
Normal file
File diff suppressed because one or more lines are too long
0
licensedDashboardClass.js
Normal file
0
licensedDashboardClass.js
Normal file
4537
package-lock.json
generated
Normal file
4537
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
55
package.json
Normal file
55
package.json
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"name": "discord-dashboard",
|
||||||
|
"version": "2.3.61",
|
||||||
|
"description": "Create an Dashboard for your bot in 10 minutes without APIs knowledge and slapping code from scratch!",
|
||||||
|
"main": "index.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"typings": ".d.ts",
|
||||||
|
"dependencies": {
|
||||||
|
"assistants-safe-storage": "^1.0.0",
|
||||||
|
"body-parser": "^1.20.0",
|
||||||
|
"colors": "^1.4.0",
|
||||||
|
"cookie-parser": "^1.4.6",
|
||||||
|
"discord-dashboard": "^2.3.39",
|
||||||
|
"discord-dashboard-pp-system": "^1.0.2",
|
||||||
|
"discord-oauth2": "^2.10.0",
|
||||||
|
"discord.js": "*",
|
||||||
|
"ejs": "^3.1.8",
|
||||||
|
"express": "^4.17.3",
|
||||||
|
"express-partials": "^0.3.0",
|
||||||
|
"express-rate-limit": "^6.4.0",
|
||||||
|
"express-session": "^1.17.3",
|
||||||
|
"https": "^1.0.0",
|
||||||
|
"keyv": "^4.5.2",
|
||||||
|
"node-fetch": "^2.6.7",
|
||||||
|
"readline-sync": "^1.4.10",
|
||||||
|
"socket.io": "^4.5.1",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "breftejk",
|
||||||
|
"license": "CC BY-NC-SA 4.0",
|
||||||
|
"homepage": "https://dbd-docs.assistantscenter.com/",
|
||||||
|
"keywords": [
|
||||||
|
"discord",
|
||||||
|
"discord.js",
|
||||||
|
"discordjs",
|
||||||
|
"discord dashboard",
|
||||||
|
"discord web dashboard",
|
||||||
|
"web dashboard",
|
||||||
|
"dashboard"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Assistants-Center/Discord.js-Web-Dashboard.git"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"dbd-dark-dashboard": "^1.6.58",
|
||||||
|
"javascript-obfuscator": "^4.0.0",
|
||||||
|
"prettier": "2.7.1"
|
||||||
|
}
|
||||||
|
}
|
173
router.js
Normal file
173
router.js
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
module.exports = (app, config, themeConfig, modules) => {
|
||||||
|
app.use(require("cookie-parser")())
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
req.bot = config.bot
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
if (themeConfig.defaultLocales) {
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
if (req.cookies?.lang) req.lang = req.cookies.lang
|
||||||
|
else req.lang = req.acceptsLanguages()[0].replace("-", "")
|
||||||
|
|
||||||
|
if (themeConfig.locales) {
|
||||||
|
if (Object.keys(themeConfig.locales).includes(req.lang)) {
|
||||||
|
req.locales = themeConfig.locales[req.lang]
|
||||||
|
} else {
|
||||||
|
req.locales =
|
||||||
|
themeConfig.locales[Object.keys(themeConfig.locales)[0]]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req.locales =
|
||||||
|
themeConfig.defaultLocales[
|
||||||
|
Object.keys(themeConfig.defaultLocales).includes(
|
||||||
|
req.lang
|
||||||
|
)
|
||||||
|
? req.lang
|
||||||
|
: "enUS"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
"/discord",
|
||||||
|
require("./Routes/discord")(app, config, themeConfig, modules)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (config.useUnderMaintenance) {
|
||||||
|
app.get(
|
||||||
|
config.underMaintenanceAccessPage || "/total-secret-get-access",
|
||||||
|
(req, res) => {
|
||||||
|
res.send(`
|
||||||
|
<form action="${config.domain}${
|
||||||
|
config.underMaintenanceAccessPage ||
|
||||||
|
"/total-secret-get-access"
|
||||||
|
}" method="POST" >
|
||||||
|
<input id="accessKey" name="accessKey"/>
|
||||||
|
<button role="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
app.post(
|
||||||
|
config.underMaintenanceAccessPage || "/total-secret-get-access",
|
||||||
|
(req, res) => {
|
||||||
|
if (!req.body) req.body = {}
|
||||||
|
const accessKey = req.body.accessKey
|
||||||
|
if (accessKey != config.underMaintenanceAccessKey)
|
||||||
|
return res.send("Wrong key.")
|
||||||
|
req.session.umaccess = true
|
||||||
|
res.redirect("/")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
if (req.originalUrl.startsWith("/loading")) return next()
|
||||||
|
if (!req.session.umaccess && !req.session.user) {
|
||||||
|
if (!config.useThemeMaintenance)
|
||||||
|
return res.send(
|
||||||
|
config.underMaintenanceCustomHtml ||
|
||||||
|
require("./underMaintenancePageDefault")(
|
||||||
|
config.underMaintenance,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
res.render("maintenance", {
|
||||||
|
req: req,
|
||||||
|
bot: config.bot,
|
||||||
|
themeConfig: req.themeConfig,
|
||||||
|
loggedIn: false,
|
||||||
|
defaultMaintenanceConfig: config.underMaintenance || {},
|
||||||
|
})
|
||||||
|
} else if (
|
||||||
|
!req.session.umaccess &&
|
||||||
|
config.ownerIDs &&
|
||||||
|
!config.ownerIDs.includes(req.session.user.id)
|
||||||
|
) {
|
||||||
|
if (!config.useThemeMaintenance)
|
||||||
|
return res.send(
|
||||||
|
config.underMaintenanceCustomHtml ||
|
||||||
|
require("./underMaintenancePageDefault")(
|
||||||
|
config.underMaintenance,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
res.render("maintenance", {
|
||||||
|
req: req,
|
||||||
|
bot: config.bot,
|
||||||
|
themeConfig: req.themeConfig,
|
||||||
|
loggedIn: true,
|
||||||
|
defaultMaintenanceConfig: config.underMaintenance || {},
|
||||||
|
})
|
||||||
|
} else next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use("/", require("./Routes/main")(app, config, themeConfig, modules))
|
||||||
|
app.use(
|
||||||
|
"/",
|
||||||
|
require("./Routes/dashboard")(app, config, themeConfig, modules)
|
||||||
|
)
|
||||||
|
|
||||||
|
config.theme.init(app, config)
|
||||||
|
|
||||||
|
let customPages = config.customPages || []
|
||||||
|
customPages.forEach((p) => {
|
||||||
|
if (p.type == "redirect") {
|
||||||
|
app.get(p.endpoint, async (req, res) => {
|
||||||
|
let endpoint = await p.getEndpoint({
|
||||||
|
user: req.session.user || {},
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
res.redirect(endpoint)
|
||||||
|
})
|
||||||
|
} else if (p.type == "html") {
|
||||||
|
app.get(p.endpoint, async (req, res) => {
|
||||||
|
let html = await p.getHtml({
|
||||||
|
user: req.session.user || {},
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
res.send(html)
|
||||||
|
})
|
||||||
|
} else if (p.type == "json") {
|
||||||
|
app.get(p.endpoint, async (req, res) => {
|
||||||
|
let json = await p.getJson({
|
||||||
|
user: req.session.user || {},
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
res.send(json)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
modules.forEach((module) => {
|
||||||
|
module.app({
|
||||||
|
app: app,
|
||||||
|
config: this.config,
|
||||||
|
themeConfig: themeConfig,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!config.useTheme404) {
|
||||||
|
app.get("*", (req, res) => {
|
||||||
|
let text =
|
||||||
|
config.html404 ||
|
||||||
|
require("./404pagedefault")(
|
||||||
|
config.websiteTitle || themeConfig.websiteName
|
||||||
|
)
|
||||||
|
res.send(
|
||||||
|
text.replace(
|
||||||
|
"{{websiteTitle}}",
|
||||||
|
config.websiteTitle || themeConfig.websiteName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
689
underMaintenancePageDefault.js
Normal file
689
underMaintenancePageDefault.js
Normal file
|
@ -0,0 +1,689 @@
|
||||||
|
module.exports = (
|
||||||
|
{
|
||||||
|
title,
|
||||||
|
contentTitle,
|
||||||
|
texts = [],
|
||||||
|
bodyBackgroundColors = ["#ffa191", "#ffc247"],
|
||||||
|
buildingsColor = "#ff6347",
|
||||||
|
craneDivBorderColor = "#ff6347",
|
||||||
|
craneArmColor = "#f88f7c",
|
||||||
|
craneWeightColor = "#f88f7c",
|
||||||
|
outerCraneColor = "#ff6347",
|
||||||
|
craneLineColor = "#ff6347",
|
||||||
|
craneCabinColor = "#f88f7c",
|
||||||
|
craneStandColors = ["#ff6347", "#f29b8b"],
|
||||||
|
},
|
||||||
|
loggedIn
|
||||||
|
) => {
|
||||||
|
let logged = "<a class='text' href='/discord'>Login</a>"
|
||||||
|
if (loggedIn) logged = "<a class='text' href='/discord/logout'>Logout</a>"
|
||||||
|
return `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>${title}</title>
|
||||||
|
<style>
|
||||||
|
@import url("https://fonts.googleapis.com/css?family=Ubuntu");
|
||||||
|
#content-title {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
#outerCraneContainer {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: inset 0 -60px 0 -30px ${outerCraneColor};
|
||||||
|
}
|
||||||
|
.buildings {
|
||||||
|
height: 84.9673202614379px;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.buildings div {
|
||||||
|
height: inherit;
|
||||||
|
width: 42.48366013071895px;
|
||||||
|
background: ${buildingsColor};
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10%;
|
||||||
|
}
|
||||||
|
.buildings div:after {
|
||||||
|
content: '';
|
||||||
|
width: 80%;
|
||||||
|
height: 60%;
|
||||||
|
left: 10%;
|
||||||
|
bottom: 30%;
|
||||||
|
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAFElEQVQImWP4////fwYYIJKDEwAAfPsP8eFXG40AAAAASUVORK5CYII=") repeat;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(1) {
|
||||||
|
width: 42.48366013071895px;
|
||||||
|
height: 21.241830065359476px;
|
||||||
|
right: 37%;
|
||||||
|
bottom: 18%;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(1):after {
|
||||||
|
bottom: 11%;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(2) {
|
||||||
|
width: 48.552754435107374px;
|
||||||
|
height: 28.322440087145967px;
|
||||||
|
right: 30%;
|
||||||
|
bottom: 35%;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(2):after {
|
||||||
|
width: 60%;
|
||||||
|
left: 11%;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(3) {
|
||||||
|
width: 24.276377217553687px;
|
||||||
|
height: 37.76325344952796px;
|
||||||
|
left: 40%;
|
||||||
|
bottom: 35%;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(3):after {
|
||||||
|
bottom: 0;
|
||||||
|
width: 20%;
|
||||||
|
height: 85%;
|
||||||
|
left: 70%;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(4) {
|
||||||
|
width: 84.9673202614379px;
|
||||||
|
height: 21.241830065359476px;
|
||||||
|
left: 24%;
|
||||||
|
bottom: 20%;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(4):after {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(5) {
|
||||||
|
width: 61.794414735591204px;
|
||||||
|
height: 67.97385620915033px;
|
||||||
|
left: 47%;
|
||||||
|
bottom: 10%;
|
||||||
|
}
|
||||||
|
.buildings div:nth-of-type(5):after {
|
||||||
|
bottom: 0;
|
||||||
|
width: 40%;
|
||||||
|
height: 85%;
|
||||||
|
left: 20%;
|
||||||
|
}
|
||||||
|
.crane,
|
||||||
|
.buildings {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.crane div {
|
||||||
|
border-radius: 2px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.crane .line {
|
||||||
|
border: none;
|
||||||
|
background: ${craneLineColor};
|
||||||
|
outline: 1px solid transparent;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
.crane .lineOne {
|
||||||
|
width: 60%;
|
||||||
|
left: 11%;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.crane .lineTwo {
|
||||||
|
width: 19%;
|
||||||
|
right: 8%;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.crane .line.lineThree {
|
||||||
|
height: 30%;
|
||||||
|
top: 22%;
|
||||||
|
left: 9%;
|
||||||
|
}
|
||||||
|
.crane .line.lineThree:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 0.2em;
|
||||||
|
width: 9000%;
|
||||||
|
background: ${craneLineColor};
|
||||||
|
display: block;
|
||||||
|
bottom: 0;
|
||||||
|
left: -4500%;
|
||||||
|
border: solid 1px ${craneLineColor};
|
||||||
|
}
|
||||||
|
.craneTwo .line.lineThree:after {
|
||||||
|
height: 0.1em;
|
||||||
|
}
|
||||||
|
.craneThree .line.lineThree:after {
|
||||||
|
height: 0.05em;
|
||||||
|
}
|
||||||
|
.stand {
|
||||||
|
height: 100%;
|
||||||
|
width: 5%;
|
||||||
|
right: 25%;
|
||||||
|
z-index: 1;
|
||||||
|
background: linear-gradient(to top, ${
|
||||||
|
craneStandColors[0]
|
||||||
|
}, ${craneStandColors[1]});
|
||||||
|
}
|
||||||
|
.craneTwo .stand {
|
||||||
|
background: linear-gradient(to top, ${
|
||||||
|
craneStandColors[0]
|
||||||
|
}, ${craneStandColors[1]});
|
||||||
|
}
|
||||||
|
.craneThree .stand {
|
||||||
|
background: linear-gradient(to top, ${
|
||||||
|
craneStandColors[0]
|
||||||
|
}, ${craneStandColors[1]});
|
||||||
|
}
|
||||||
|
.weight {
|
||||||
|
height: 20%;
|
||||||
|
width: 8%;
|
||||||
|
right: 4%;
|
||||||
|
top: 12%;
|
||||||
|
z-index: 2;
|
||||||
|
background: ${craneWeightColor};
|
||||||
|
}
|
||||||
|
.craneTwo .weight {
|
||||||
|
background: ${craneWeightColor};
|
||||||
|
}
|
||||||
|
.craneThree .weight {
|
||||||
|
background: ${craneWeightColor};
|
||||||
|
}
|
||||||
|
.cabin {
|
||||||
|
height: 9%;
|
||||||
|
width: 12%;
|
||||||
|
right: 24%;
|
||||||
|
top: 20%;
|
||||||
|
z-index: 2;
|
||||||
|
background: ${craneCabinColor};
|
||||||
|
}
|
||||||
|
.cabin:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 10%;
|
||||||
|
width: 100%;
|
||||||
|
background: ${craneCabinColor};
|
||||||
|
display: block;
|
||||||
|
top: 60%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.craneTwo .cabin {
|
||||||
|
background: ${craneCabinColor};
|
||||||
|
}
|
||||||
|
.craneThree .cabin {
|
||||||
|
background: ${craneCabinColor};
|
||||||
|
}
|
||||||
|
.arm {
|
||||||
|
height: 7%;
|
||||||
|
width: 100%;
|
||||||
|
top: 15%;
|
||||||
|
z-index: 3;
|
||||||
|
background: ${craneArmColor};
|
||||||
|
}
|
||||||
|
.craneTwo .arm {
|
||||||
|
background: ${craneArmColor};
|
||||||
|
}
|
||||||
|
.craneThree .arm {
|
||||||
|
background: ${craneArmColor};
|
||||||
|
}
|
||||||
|
.crane div.arm {
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
}
|
||||||
|
.brick {
|
||||||
|
height: 6%;
|
||||||
|
width: 9%;
|
||||||
|
bottom: 0;
|
||||||
|
left: 40%;
|
||||||
|
background: ${craneArmColor};
|
||||||
|
}
|
||||||
|
.brickTwo {
|
||||||
|
left: 48%;
|
||||||
|
}
|
||||||
|
.brickThree {
|
||||||
|
bottom: 5.5%;
|
||||||
|
left: 44%;
|
||||||
|
}
|
||||||
|
.craneOne {
|
||||||
|
width: 260px;
|
||||||
|
height: 169.9346405228758px;
|
||||||
|
left: 20%;
|
||||||
|
}
|
||||||
|
.craneOne div {
|
||||||
|
border: solid 1px ${craneDivBorderColor};
|
||||||
|
}
|
||||||
|
.craneOne .line {
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
.craneOne .lineThree {
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
.craneTwo {
|
||||||
|
width: 200px;
|
||||||
|
height: 130.718954248366px;
|
||||||
|
transform: scaleX(-1);
|
||||||
|
left: 40%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
.craneTwo div {
|
||||||
|
border: solid 1px ${craneDivBorderColor};
|
||||||
|
}
|
||||||
|
.craneTwo .line {
|
||||||
|
height: 0.769230769230769px;
|
||||||
|
}
|
||||||
|
.craneTwo .lineThree {
|
||||||
|
width: 0.714285714285714px;
|
||||||
|
animation-delay: 3s;
|
||||||
|
}
|
||||||
|
.craneTwo .cabin,
|
||||||
|
.craneTwo .arm,
|
||||||
|
.craneTwo .picker,
|
||||||
|
.craneTwo .weight {
|
||||||
|
animation-delay: 3s;
|
||||||
|
}
|
||||||
|
.craneThree {
|
||||||
|
width: 130px;
|
||||||
|
height: 84.9673202614379px;
|
||||||
|
left: 60%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
.craneThree div {
|
||||||
|
border: solid 1px ${craneDivBorderColor};
|
||||||
|
}
|
||||||
|
.craneThree .line {
|
||||||
|
height: 0.5px;
|
||||||
|
}
|
||||||
|
.craneThree .lineThree {
|
||||||
|
width: 0.5px;
|
||||||
|
animation-delay: 1.5s;
|
||||||
|
}
|
||||||
|
.craneThree .brickThree {
|
||||||
|
bottom: 5%;
|
||||||
|
}
|
||||||
|
.craneThree .brickOne,
|
||||||
|
.craneThree .brickTwo {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.craneThree .cabin,
|
||||||
|
.craneThree .arm,
|
||||||
|
.craneThree .picker,
|
||||||
|
.craneThree .weight {
|
||||||
|
animation-delay: 1.5s;
|
||||||
|
}
|
||||||
|
.crane {
|
||||||
|
perspective: 600px;
|
||||||
|
}
|
||||||
|
.lineOne {
|
||||||
|
transform-origin: right 0;
|
||||||
|
animation: moveLineOne 12s infinite alternate;
|
||||||
|
}
|
||||||
|
.lineTwo {
|
||||||
|
transform-origin: top left;
|
||||||
|
animation: moveLineTwo 12s infinite alternate;
|
||||||
|
}
|
||||||
|
.lineThree {
|
||||||
|
transform-origin: right center;
|
||||||
|
animation: moveLineThree 12s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
.cabin,
|
||||||
|
.arm,
|
||||||
|
.picker {
|
||||||
|
transform-origin: 80% center;
|
||||||
|
animation: moveCrane 12s infinite alternate;
|
||||||
|
}
|
||||||
|
.weight {
|
||||||
|
transform-origin: 0 center;
|
||||||
|
animation: moveWeight 12s infinite alternate;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background: linear-gradient(to top, ${
|
||||||
|
bodyBackgroundColors[0]
|
||||||
|
}, ${bodyBackgroundColors[1]});
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-shadow: 1px 1px 1px rgba(0,0,0,0.004);
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-family: Ubuntu;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
#content h1,
|
||||||
|
#content p {
|
||||||
|
margin: -8rem 0 0 1rem;
|
||||||
|
}
|
||||||
|
#content p {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
#license {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
@-moz-keyframes moveCrane {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes moveCrane {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes moveCrane {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes moveCrane {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes moveWeight {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) translateX(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes moveWeight {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) translateX(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes moveWeight {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) translateX(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes moveWeight {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) translateX(0);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes moveLineOne {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes moveLineOne {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes moveLineOne {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes moveLineOne {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(45deg) rotateZ(-10deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes moveLineTwo {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(15deg) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes moveLineTwo {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(15deg) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes moveLineTwo {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(15deg) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes moveLineTwo {
|
||||||
|
0%, 20% {
|
||||||
|
transform: rotateY(0) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
70%, 100% {
|
||||||
|
transform: rotateY(15deg) rotateZ(29deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes moveLineThree {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: translate(2500%, -18%);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: translate(11000%, -25%);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: translate(9100%, -25%);
|
||||||
|
height: 30%;
|
||||||
|
}
|
||||||
|
90%, 100% {
|
||||||
|
transform: translate(9100%, -15%);
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes moveLineThree {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: translate(2500%, -18%);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: translate(11000%, -25%);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: translate(9100%, -25%);
|
||||||
|
height: 30%;
|
||||||
|
}
|
||||||
|
90%, 100% {
|
||||||
|
transform: translate(9100%, -15%);
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes moveLineThree {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: translate(2500%, -18%);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: translate(11000%, -25%);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: translate(9100%, -25%);
|
||||||
|
height: 30%;
|
||||||
|
}
|
||||||
|
90%, 100% {
|
||||||
|
transform: translate(9100%, -15%);
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes moveLineThree {
|
||||||
|
0% {
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: translate(2500%, -18%);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: translate(11000%, -25%);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: translate(9100%, -25%);
|
||||||
|
height: 30%;
|
||||||
|
}
|
||||||
|
90%, 100% {
|
||||||
|
transform: translate(9100%, -15%);
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 30px;
|
||||||
|
text-align: center;
|
||||||
|
z-index:9999999;
|
||||||
|
}
|
||||||
|
#content-title {
|
||||||
|
font-size: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-device-width: 380px) {
|
||||||
|
.text {
|
||||||
|
font-size: 28px;
|
||||||
|
text-align: center;
|
||||||
|
z-index:9999999;
|
||||||
|
}
|
||||||
|
#content-title {
|
||||||
|
font-size: 58px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-device-width: 430px) {
|
||||||
|
.text {
|
||||||
|
font-size: 50px;
|
||||||
|
text-align: center;
|
||||||
|
z-index:9999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content-title {
|
||||||
|
font-size: 80px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-device-width: 750px) {
|
||||||
|
.text {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
z-index:9999999;
|
||||||
|
}
|
||||||
|
#content-title {
|
||||||
|
font-size: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0px !important;">
|
||||||
|
<div id="content">
|
||||||
|
<h1 id="content-title">${contentTitle}</h1>
|
||||||
|
${texts
|
||||||
|
.map((text) => '<p class="text">' + text + "</p>")
|
||||||
|
.join("")}
|
||||||
|
<br><br><br>
|
||||||
|
${logged}
|
||||||
|
</div>
|
||||||
|
<div id="outerCraneContainer">
|
||||||
|
<div class="buildings">
|
||||||
|
<div></div>
|
||||||
|
<div class="1"></div>
|
||||||
|
<div class="2"></div>
|
||||||
|
<div class="3"></div>
|
||||||
|
<div class="4"></div>
|
||||||
|
</div>
|
||||||
|
<div class="crane craneThree">
|
||||||
|
<div class="line lineOne"></div>
|
||||||
|
<div class="line lineTwo"></div>
|
||||||
|
<div class="line lineThree"></div>
|
||||||
|
<div class="stand"></div>
|
||||||
|
<div class="weight"></div>
|
||||||
|
<div class="cabin"></div>
|
||||||
|
<div class="arm"></div>
|
||||||
|
</div>
|
||||||
|
<div class="crane craneTwo">
|
||||||
|
<div class="line lineOne"></div>
|
||||||
|
<div class="line lineTwo"></div>
|
||||||
|
<div class="line lineThree"></div>
|
||||||
|
<div class="stand"></div>
|
||||||
|
<div class="weight"></div>
|
||||||
|
<div class="cabin"></div>
|
||||||
|
<div class="arm"></div>
|
||||||
|
</div>
|
||||||
|
<div class="crane craneOne">
|
||||||
|
<div class="line lineOne"></div>
|
||||||
|
<div class="line lineTwo"></div>
|
||||||
|
<div class="line lineThree"></div>
|
||||||
|
<div class="stand"></div>
|
||||||
|
<div class="weight"></div>
|
||||||
|
<div class="cabin"></div>
|
||||||
|
<div class="arm"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
}
|
Loading…
Reference in a new issue