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