@open-discord-bots/framework 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +713 -0
- package/README.md +104 -0
- package/dist/api/api.d.ts +26 -0
- package/dist/api/api.js +44 -0
- package/dist/api/main.d.ts +133 -0
- package/dist/api/main.js +87 -0
- package/dist/api/modules/action.d.ts +34 -0
- package/dist/api/modules/action.js +58 -0
- package/dist/api/modules/base.d.ts +329 -0
- package/dist/api/modules/base.js +804 -0
- package/dist/api/modules/builder.d.ts +647 -0
- package/dist/api/modules/builder.js +1441 -0
- package/dist/api/modules/checker.d.ts +648 -0
- package/dist/api/modules/checker.js +1324 -0
- package/dist/api/modules/client.d.ts +768 -0
- package/dist/api/modules/client.js +1859 -0
- package/dist/api/modules/code.d.ts +33 -0
- package/dist/api/modules/code.js +57 -0
- package/dist/api/modules/config.d.ts +70 -0
- package/dist/api/modules/config.js +206 -0
- package/dist/api/modules/console.d.ts +305 -0
- package/dist/api/modules/console.js +598 -0
- package/dist/api/modules/cooldown.d.ts +138 -0
- package/dist/api/modules/cooldown.js +359 -0
- package/dist/api/modules/database.d.ts +135 -0
- package/dist/api/modules/database.js +271 -0
- package/dist/api/modules/event.d.ts +43 -0
- package/dist/api/modules/event.js +100 -0
- package/dist/api/modules/flag.d.ts +40 -0
- package/dist/api/modules/flag.js +72 -0
- package/dist/api/modules/fuse.d.ts +218 -0
- package/dist/api/modules/fuse.js +123 -0
- package/dist/api/modules/helpmenu.d.ts +106 -0
- package/dist/api/modules/helpmenu.js +167 -0
- package/dist/api/modules/language.d.ts +85 -0
- package/dist/api/modules/language.js +195 -0
- package/dist/api/modules/permission.d.ts +121 -0
- package/dist/api/modules/permission.js +314 -0
- package/dist/api/modules/plugin.d.ts +128 -0
- package/dist/api/modules/plugin.js +168 -0
- package/dist/api/modules/post.d.ts +44 -0
- package/dist/api/modules/post.js +92 -0
- package/dist/api/modules/progressbar.d.ts +108 -0
- package/dist/api/modules/progressbar.js +233 -0
- package/dist/api/modules/responder.d.ts +506 -0
- package/dist/api/modules/responder.js +1468 -0
- package/dist/api/modules/session.d.ts +58 -0
- package/dist/api/modules/session.js +171 -0
- package/dist/api/modules/startscreen.d.ts +165 -0
- package/dist/api/modules/startscreen.js +293 -0
- package/dist/api/modules/stat.d.ts +142 -0
- package/dist/api/modules/stat.js +293 -0
- package/dist/api/modules/verifybar.d.ts +54 -0
- package/dist/api/modules/verifybar.js +60 -0
- package/dist/api/modules/worker.d.ts +41 -0
- package/dist/api/modules/worker.js +93 -0
- package/dist/api/utils.d.ts +61 -0
- package/dist/api/utils.js +254 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +40 -0
- package/dist/startup/dump.d.ts +14 -0
- package/dist/startup/dump.js +79 -0
- package/dist/startup/errorHandling.d.ts +2 -0
- package/dist/startup/errorHandling.js +43 -0
- package/dist/startup/pluginLauncher.d.ts +2 -0
- package/dist/startup/pluginLauncher.js +202 -0
- package/package.json +9 -3
- package/src/api/api.ts +29 -0
- package/src/api/main.ts +189 -0
- package/src/api/modules/action.ts +58 -0
- package/src/api/modules/base.ts +811 -0
- package/src/api/modules/builder.ts +1554 -0
- package/src/api/modules/checker.ts +1549 -0
- package/src/api/modules/client.ts +2247 -0
- package/src/api/modules/code.ts +58 -0
- package/src/api/modules/config.ts +159 -0
- package/src/api/modules/console.ts +665 -0
- package/src/api/modules/cooldown.ts +348 -0
- package/src/api/modules/database.ts +278 -0
- package/src/api/modules/event.ts +99 -0
- package/src/api/modules/flag.ts +73 -0
- package/src/api/modules/fuse.ts +348 -0
- package/src/api/modules/helpmenu.ts +216 -0
- package/src/api/modules/language.ts +201 -0
- package/src/api/modules/permission.ts +340 -0
- package/src/api/modules/plugin.ts +242 -0
- package/src/api/modules/post.ts +90 -0
- package/src/api/modules/progressbar.ts +232 -0
- package/src/api/modules/responder.ts +1420 -0
- package/src/api/modules/session.ts +155 -0
- package/src/api/modules/startscreen.ts +320 -0
- package/src/api/modules/stat.ts +313 -0
- package/src/api/modules/verifybar.ts +61 -0
- package/src/api/modules/worker.ts +93 -0
- package/src/api/utils.ts +206 -0
- package/src/cli/cli.ts +151 -0
- package/src/cli/editConfig.ts +943 -0
- package/src/index.ts +6 -1
- package/src/startup/compilation.ts +186 -0
- package/src/startup/dump.ts +45 -0
- package/src/startup/errorHandling.ts +38 -0
- package/src/startup/pluginLauncher.ts +261 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
///////////////////////////////////////
|
|
2
|
+
//STAT MODULE
|
|
3
|
+
///////////////////////////////////////
|
|
4
|
+
import { ODId, ODManager, ODManagerData, ODSystemError, ODValidId } from "./base"
|
|
5
|
+
import { ODDebugger } from "./console"
|
|
6
|
+
import { ODDatabase, ODJsonDatabaseStructure } from "./database"
|
|
7
|
+
import * as discord from "discord.js"
|
|
8
|
+
|
|
9
|
+
/**## ODValidStatValue `type`
|
|
10
|
+
* These are the only allowed types for a stat value to improve compatibility with different database systems.
|
|
11
|
+
*/
|
|
12
|
+
export type ODValidStatValue = string|number|boolean
|
|
13
|
+
|
|
14
|
+
/**## ODStatsManagerInitCallback `type`
|
|
15
|
+
* This callback can be used to execute something when the stats have been initiated.
|
|
16
|
+
*
|
|
17
|
+
* By default this is used to clear stats from users that left the server or tickets which don't exist anymore.
|
|
18
|
+
*/
|
|
19
|
+
export type ODStatsManagerInitCallback = (database:ODJsonDatabaseStructure, deletables:ODJsonDatabaseStructure) => void|Promise<void>
|
|
20
|
+
|
|
21
|
+
/**## ODStatScopeSetMode `type`
|
|
22
|
+
* This type contains all valid methods for changing the value of a stat.
|
|
23
|
+
*/
|
|
24
|
+
export type ODStatScopeSetMode = "set"|"increase"|"decrease"
|
|
25
|
+
|
|
26
|
+
/**## ODStatsManager `class`
|
|
27
|
+
* This is an Open Discord stats manager.
|
|
28
|
+
*
|
|
29
|
+
* This class is responsible for managing all stats of the bot.
|
|
30
|
+
* Stats are categorized in "scopes" which can be accessed in this manager.
|
|
31
|
+
*
|
|
32
|
+
* Stats can be accessed in the individual scopes.
|
|
33
|
+
*/
|
|
34
|
+
export class ODStatsManager extends ODManager<ODStatScope> {
|
|
35
|
+
/**Alias to Open Discord debugger. */
|
|
36
|
+
#debug: ODDebugger
|
|
37
|
+
/**Alias to Open Discord stats database. */
|
|
38
|
+
database: ODDatabase|null = null
|
|
39
|
+
/**All the listeners for the init event. */
|
|
40
|
+
#initListeners: ODStatsManagerInitCallback[] = []
|
|
41
|
+
|
|
42
|
+
constructor(debug:ODDebugger){
|
|
43
|
+
super(debug,"stat scope")
|
|
44
|
+
this.#debug = debug
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**Select the database to use to read/write all stats from/to. */
|
|
48
|
+
useDatabase(database:ODDatabase){
|
|
49
|
+
this.database = database
|
|
50
|
+
}
|
|
51
|
+
add(data:ODStatScope, overwrite?:boolean): boolean {
|
|
52
|
+
data.useDebug(this.#debug,"stat")
|
|
53
|
+
if (this.database) data.useDatabase(this.database)
|
|
54
|
+
return super.add(data,overwrite)
|
|
55
|
+
}
|
|
56
|
+
/**Init all stats and run `onInit()` listeners. */
|
|
57
|
+
async init(){
|
|
58
|
+
if (!this.database) throw new ODSystemError("Unable to initialize stats scopes due to missing database!")
|
|
59
|
+
|
|
60
|
+
//get all valid categories
|
|
61
|
+
const validCategories: string[] = []
|
|
62
|
+
for (const scope of this.getAll()){
|
|
63
|
+
validCategories.push(...scope.init())
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//filter out the deletable stats
|
|
67
|
+
const deletableStats: ODJsonDatabaseStructure = []
|
|
68
|
+
const data = await this.database.getAll()
|
|
69
|
+
data.forEach((data) => {
|
|
70
|
+
if (!validCategories.includes(data.category)) deletableStats.push(data)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
//do additional deletion
|
|
74
|
+
for (const cb of this.#initListeners){
|
|
75
|
+
await cb(data,deletableStats)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//delete all deletable stats
|
|
79
|
+
for (const data of deletableStats){
|
|
80
|
+
if (!this.database) return
|
|
81
|
+
await this.database.delete(data.category,data.key)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**Reset all stats. (clears the entire database) */
|
|
85
|
+
async reset(){
|
|
86
|
+
if (!this.database) return
|
|
87
|
+
const data = await this.database.getAll()
|
|
88
|
+
for (const d of data){
|
|
89
|
+
if (!this.database) return
|
|
90
|
+
await this.database.delete(d.category,d.key)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**Run a function when the stats are initialized. This can be used to clear stats from users that left the server or tickets which don't exist anymore. */
|
|
94
|
+
onInit(callback:ODStatsManagerInitCallback){
|
|
95
|
+
this.#initListeners.push(callback)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**## ODStatScope `class`
|
|
100
|
+
* This is an Open Discord stat scope.
|
|
101
|
+
*
|
|
102
|
+
* A scope can contain multiple stats. Every scope is seperated from other scopes.
|
|
103
|
+
* Here, you can read & write the values of all stats.
|
|
104
|
+
*
|
|
105
|
+
* The built-in Open Discord scopes are: `global`, `user`, `ticket`
|
|
106
|
+
*/
|
|
107
|
+
export class ODStatScope extends ODManager<ODStat> {
|
|
108
|
+
/**The id of this statistics scope. */
|
|
109
|
+
id: ODId
|
|
110
|
+
/**Is this stat scope already initialized? */
|
|
111
|
+
ready: boolean = false
|
|
112
|
+
/**Alias to Open Discord stats database. */
|
|
113
|
+
database: ODDatabase|null = null
|
|
114
|
+
/**The name of this scope (used in embed title) */
|
|
115
|
+
name:string
|
|
116
|
+
|
|
117
|
+
constructor(id:ODValidId, name:string){
|
|
118
|
+
super()
|
|
119
|
+
this.id = new ODId(id)
|
|
120
|
+
this.name = name
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**Select the database to use to read/write all stats from/to. (Automatically assigned when used in `ODStatsManager`) */
|
|
124
|
+
useDatabase(database:ODDatabase){
|
|
125
|
+
this.database = database
|
|
126
|
+
}
|
|
127
|
+
/**Get the value of a statistic. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */
|
|
128
|
+
async getStat(id:ODValidId, scopeId:string): Promise<ODValidStatValue|null> {
|
|
129
|
+
if (!this.database) return null
|
|
130
|
+
const newId = new ODId(id)
|
|
131
|
+
const data = await this.database.get(this.id.value+"_"+newId.value,scopeId)
|
|
132
|
+
|
|
133
|
+
if (typeof data == "undefined"){
|
|
134
|
+
//set stats to default value & return
|
|
135
|
+
return this.resetStat(id,scopeId)
|
|
136
|
+
}else if (typeof data == "string" || typeof data == "boolean" || typeof data == "number"){
|
|
137
|
+
//return value received from database
|
|
138
|
+
return data
|
|
139
|
+
}
|
|
140
|
+
//return null on error
|
|
141
|
+
return null
|
|
142
|
+
}
|
|
143
|
+
/**Get the value of a statistic for all `scopeId`'s. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */
|
|
144
|
+
async getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> {
|
|
145
|
+
if (!this.database) return []
|
|
146
|
+
const newId = new ODId(id)
|
|
147
|
+
const data = await this.database.getCategory(this.id.value+"_"+newId.value) ?? []
|
|
148
|
+
const output: {id:string,value:ODValidStatValue}[] = []
|
|
149
|
+
|
|
150
|
+
for (const stat of data){
|
|
151
|
+
if (typeof stat.value == "string" || typeof stat.value == "boolean" || typeof stat.value == "number"){
|
|
152
|
+
//return value received from database
|
|
153
|
+
output.push({id:stat.key,value:stat.value})
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//return null on error
|
|
158
|
+
return output
|
|
159
|
+
}
|
|
160
|
+
/**Set, increase or decrease the value of a statistic. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */
|
|
161
|
+
async setStat(id:ODValidId, scopeId:string, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise<boolean> {
|
|
162
|
+
if (!this.database) return false
|
|
163
|
+
const stat = this.get(id)
|
|
164
|
+
if (!stat) return false
|
|
165
|
+
if (mode == "set" || typeof value != "number"){
|
|
166
|
+
await this.database.set(this.id.value+"_"+stat.id.value,scopeId,value)
|
|
167
|
+
}else if (mode == "increase"){
|
|
168
|
+
const currentValue = await this.getStat(id,scopeId)
|
|
169
|
+
if (typeof currentValue != "number") await this.database.set(this.id.value+"_"+stat.id.value,scopeId,0+value)
|
|
170
|
+
else await this.database.set(this.id.value+"_"+stat.id.value,scopeId,currentValue+value)
|
|
171
|
+
}else if (mode == "decrease"){
|
|
172
|
+
const currentValue = await this.getStat(id,scopeId)
|
|
173
|
+
if (typeof currentValue != "number") await this.database.set(this.id.value+"_"+stat.id.value,scopeId,0-value)
|
|
174
|
+
else await this.database.set(this.id.value+"_"+stat.id.value,scopeId,currentValue-value)
|
|
175
|
+
}
|
|
176
|
+
return true
|
|
177
|
+
}
|
|
178
|
+
/**Reset the value of a statistic to the initial value. The `scopeId` is the unique id of the user, channel, role, etc that the stats are related to. */
|
|
179
|
+
async resetStat(id:ODValidId, scopeId:string): Promise<ODValidStatValue|null> {
|
|
180
|
+
if (!this.database) return null
|
|
181
|
+
const stat = this.get(id)
|
|
182
|
+
if (!stat) return null
|
|
183
|
+
if (stat.value != null) await this.database.set(this.id.value+"_"+stat.id.value,scopeId,stat.value)
|
|
184
|
+
return stat.value
|
|
185
|
+
}
|
|
186
|
+
/**Initialize this stat scope & return a list of all statistic ids in the following format: `<scopeid>_<statid>` */
|
|
187
|
+
init(): string[] {
|
|
188
|
+
//get all valid stats categories
|
|
189
|
+
this.ready = true
|
|
190
|
+
return this.getAll().map((stat) => this.id.value+"_"+stat.id.value)
|
|
191
|
+
}
|
|
192
|
+
/**Render all stats in this scope for usage in a discord message/embed. */
|
|
193
|
+
async render(scopeId:string, guild:discord.Guild, channel:discord.TextBasedChannel, user:discord.User): Promise<string> {
|
|
194
|
+
//sort from high priority to low
|
|
195
|
+
const derefArray = [...this.getAll()]
|
|
196
|
+
derefArray.sort((a,b) => {
|
|
197
|
+
return b.priority-a.priority
|
|
198
|
+
})
|
|
199
|
+
const result: string[] = []
|
|
200
|
+
|
|
201
|
+
for (const stat of derefArray){
|
|
202
|
+
try {
|
|
203
|
+
if (stat instanceof ODDynamicStat){
|
|
204
|
+
//dynamic render (without value)
|
|
205
|
+
result.push(await stat.render("",scopeId,guild,channel,user))
|
|
206
|
+
}else{
|
|
207
|
+
//normal render (with value)
|
|
208
|
+
const value = await this.getStat(stat.id,scopeId)
|
|
209
|
+
if (value != null) result.push(await stat.render(value,scopeId,guild,channel,user))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
}catch(err){
|
|
213
|
+
process.emit("uncaughtException",err)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return result.filter((stat) => stat !== "").join("\n")
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**## ODStatGlobalScope `class`
|
|
222
|
+
* This is an Open Discord stat global scope.
|
|
223
|
+
*
|
|
224
|
+
* A scope can contain multiple stats. Every scope is seperated from other scopes.
|
|
225
|
+
* Here, you can read & write the values of all stats.
|
|
226
|
+
*
|
|
227
|
+
* This scope is made specifically for the global stats of Open Discord.
|
|
228
|
+
*/
|
|
229
|
+
export class ODStatGlobalScope extends ODStatScope {
|
|
230
|
+
getStat(id:ODValidId): Promise<ODValidStatValue|null> {
|
|
231
|
+
return super.getStat(id,"GLOBAL")
|
|
232
|
+
}
|
|
233
|
+
getAllStats(id:ODValidId): Promise<{id:string,value:ODValidStatValue}[]> {
|
|
234
|
+
return super.getAllStats(id)
|
|
235
|
+
}
|
|
236
|
+
setStat(id:ODValidId, value:ODValidStatValue, mode:ODStatScopeSetMode): Promise<boolean> {
|
|
237
|
+
return super.setStat(id,"GLOBAL",value,mode)
|
|
238
|
+
}
|
|
239
|
+
resetStat(id:ODValidId): Promise<ODValidStatValue|null> {
|
|
240
|
+
return super.resetStat(id,"GLOBAL")
|
|
241
|
+
}
|
|
242
|
+
render(scopeId:"GLOBAL", guild:discord.Guild, channel:discord.TextBasedChannel, user: discord.User): Promise<string> {
|
|
243
|
+
return super.render("GLOBAL",guild,channel,user)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**## ODStatRenderer `type`
|
|
248
|
+
* This callback will render a single statistic for a discord embed/message.
|
|
249
|
+
*/
|
|
250
|
+
export type ODStatRenderer = (value:ODValidStatValue, scopeId:string, guild:discord.Guild, channel:discord.TextBasedChannel, user:discord.User) => string|Promise<string>
|
|
251
|
+
|
|
252
|
+
/**## ODStat `class`
|
|
253
|
+
* This is an Open Discord statistic.
|
|
254
|
+
*
|
|
255
|
+
* This single statistic doesn't do anything except defining the rules of this statistic.
|
|
256
|
+
* Use it in a stats scope to register a new statistic. A statistic can also include a priority to choose the render priority.
|
|
257
|
+
*
|
|
258
|
+
* It's recommended to use the `ODBasicStat` & `ODDynamicStat` classes instead of this one!
|
|
259
|
+
*/
|
|
260
|
+
export class ODStat extends ODManagerData {
|
|
261
|
+
/**The priority of this statistic. */
|
|
262
|
+
priority: number
|
|
263
|
+
/**The render function of this statistic. */
|
|
264
|
+
render: ODStatRenderer
|
|
265
|
+
/**The value of this statistic. */
|
|
266
|
+
value: ODValidStatValue|null
|
|
267
|
+
|
|
268
|
+
constructor(id:ODValidId, priority:number, render:ODStatRenderer, value?:ODValidStatValue){
|
|
269
|
+
super(id)
|
|
270
|
+
this.priority = priority
|
|
271
|
+
this.render = render
|
|
272
|
+
this.value = value ?? null
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**## ODBasicStat `class`
|
|
277
|
+
* This is an Open Discord basic statistic.
|
|
278
|
+
*
|
|
279
|
+
* This single statistic will store a number, boolean or string in the database.
|
|
280
|
+
* Use it to create a simple statistic for any stats scope.
|
|
281
|
+
*/
|
|
282
|
+
export class ODBasicStat extends ODStat {
|
|
283
|
+
/**The name of this stat. Rendered in discord embeds/messages. */
|
|
284
|
+
name: string
|
|
285
|
+
|
|
286
|
+
constructor(id:ODValidId, priority:number, name:string, value:ODValidStatValue){
|
|
287
|
+
super(id,priority,(value) => {
|
|
288
|
+
return ""+name+": `"+value.toString()+"`"
|
|
289
|
+
},value)
|
|
290
|
+
this.name = name
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**## ODDynamicStatRenderer `type`
|
|
295
|
+
* This callback will render a single dynamic statistic for a discord embed/message.
|
|
296
|
+
*/
|
|
297
|
+
export type ODDynamicStatRenderer = (scopeId:string, guild:discord.Guild, channel:discord.TextBasedChannel, user:discord.User) => string|Promise<string>
|
|
298
|
+
|
|
299
|
+
/**## ODDynamicStat `class`
|
|
300
|
+
* This is an Open Discord dynamic statistic.
|
|
301
|
+
*
|
|
302
|
+
* A dynamic statistic does not store anything in the database! Instead, it will execute a function to return a custom result.
|
|
303
|
+
* This can be used to show statistics which are not stored in the database.
|
|
304
|
+
*
|
|
305
|
+
* This is used in Open Discord for the live ticket status, participants & system status.
|
|
306
|
+
*/
|
|
307
|
+
export class ODDynamicStat extends ODStat {
|
|
308
|
+
constructor(id:ODValidId, priority:number, render:ODDynamicStatRenderer){
|
|
309
|
+
super(id,priority,(value,scopeId,guild,channel,user) => {
|
|
310
|
+
return render(scopeId,guild,channel,user)
|
|
311
|
+
})
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
///////////////////////////////////////
|
|
2
|
+
//VERIFYBAR MODULE
|
|
3
|
+
///////////////////////////////////////
|
|
4
|
+
import { ODId, ODManager, ODManagerData, ODValidId } from "./base"
|
|
5
|
+
import { ODMessage } from "./builder"
|
|
6
|
+
import { ODDebugger } from "./console"
|
|
7
|
+
import { ODButtonResponderInstance } from "./responder"
|
|
8
|
+
import * as discord from "discord.js"
|
|
9
|
+
import { ODWorkerManager } from "./worker"
|
|
10
|
+
|
|
11
|
+
/**## ODVerifyBar `class`
|
|
12
|
+
* This is an Open Discord verifybar.
|
|
13
|
+
*
|
|
14
|
+
* It is contains 2 sets of workers and a lot of utilities for the (✅ ❌) verifybars in the bot.
|
|
15
|
+
*
|
|
16
|
+
* It doesn't contain the code which activates or spawns the verifybars!
|
|
17
|
+
*/
|
|
18
|
+
export class ODVerifyBar extends ODManagerData {
|
|
19
|
+
/**All workers that will run when the verifybar is accepted. */
|
|
20
|
+
success: ODWorkerManager<ODButtonResponderInstance,"verifybar",{data:string|null,verifybarMessage:discord.Message<boolean>|null}>
|
|
21
|
+
/**All workers that will run when the verifybar is stopped. */
|
|
22
|
+
failure: ODWorkerManager<ODButtonResponderInstance,"verifybar",{data:string|null,verifybarMessage:discord.Message<boolean>|null}>
|
|
23
|
+
/**The message that will be built wen activating this verifybar. */
|
|
24
|
+
message: ODMessage<"verifybar",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message<boolean>}>
|
|
25
|
+
/**When disabled, it will skip the verifybar and instantly fire the `success` workers. */
|
|
26
|
+
enabled: boolean
|
|
27
|
+
|
|
28
|
+
constructor(id:ODValidId, message:ODMessage<"verifybar",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,originalMessage:discord.Message<boolean>}>, enabled?:boolean){
|
|
29
|
+
super(id)
|
|
30
|
+
this.success = new ODWorkerManager("descending")
|
|
31
|
+
this.failure = new ODWorkerManager("descending")
|
|
32
|
+
this.message = message
|
|
33
|
+
this.enabled = enabled ?? true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**Build the message and reply to a button with this verifybar. */
|
|
37
|
+
async activate(responder:ODButtonResponderInstance){
|
|
38
|
+
if (this.enabled){
|
|
39
|
+
//show verifybar
|
|
40
|
+
const {guild,channel,user,message} = responder
|
|
41
|
+
await responder.update(await this.message.build("verifybar",{guild,channel,user,verifybar:this,originalMessage:message}))
|
|
42
|
+
}else{
|
|
43
|
+
//instant success
|
|
44
|
+
if (this.success) await this.success.executeWorkers(responder,"verifybar",{data:null,verifybarMessage:null})
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**## ODVerifyBarManager `class`
|
|
50
|
+
* This is an Open Discord verifybar manager.
|
|
51
|
+
*
|
|
52
|
+
* It contains all (✅ ❌) verifybars in the bot.
|
|
53
|
+
* The `ODVerifyBar` classes contain `ODWorkerManager`'s that will be fired when the continue/stop buttons are pressed.
|
|
54
|
+
*
|
|
55
|
+
* It doesn't contain the code which activates the verifybars! This should be implemented by your own.
|
|
56
|
+
*/
|
|
57
|
+
export class ODVerifyBarManager extends ODManager<ODVerifyBar> {
|
|
58
|
+
constructor(debug:ODDebugger){
|
|
59
|
+
super(debug,"verifybar")
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
///////////////////////////////////////
|
|
2
|
+
//WORKER MODULE
|
|
3
|
+
///////////////////////////////////////
|
|
4
|
+
import { ODId, ODManager, ODManagerData, ODValidId } from "./base"
|
|
5
|
+
|
|
6
|
+
/**## ODWorkerCallback `type`
|
|
7
|
+
* This is the callback used in `ODWorker`!
|
|
8
|
+
*/
|
|
9
|
+
export type ODWorkerCallback<Instance, Source extends string, Params> = (instance:Instance, params:Params, source:Source, cancel:() => void) => void|Promise<void>
|
|
10
|
+
|
|
11
|
+
/**## ODWorker `class`
|
|
12
|
+
* This is an Open Discord worker.
|
|
13
|
+
*
|
|
14
|
+
* You can compare it with a normal javascript callback, but slightly more advanced!
|
|
15
|
+
*
|
|
16
|
+
* - It has an `id` for identification of the function
|
|
17
|
+
* - A `priority` to know when to execute this callback (related to others)
|
|
18
|
+
* - It knows who called this callback (`source`)
|
|
19
|
+
* - And much more!
|
|
20
|
+
*/
|
|
21
|
+
export class ODWorker<Instance, Source extends string, Params> extends ODManagerData {
|
|
22
|
+
/**The priority of this worker */
|
|
23
|
+
priority: number
|
|
24
|
+
/**The main callback of this worker */
|
|
25
|
+
callback: ODWorkerCallback<Instance,Source,Params>
|
|
26
|
+
|
|
27
|
+
constructor(id:ODValidId, priority:number, callback:ODWorkerCallback<Instance,Source,Params>){
|
|
28
|
+
super(id)
|
|
29
|
+
this.priority = priority
|
|
30
|
+
this.callback = callback
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**## ODWorker `class`
|
|
35
|
+
* This is an Open Discord worker manager.
|
|
36
|
+
*
|
|
37
|
+
* It manages & executes `ODWorker`'s in the correct order.
|
|
38
|
+
*
|
|
39
|
+
* You can register a custom worker in this class to create a message or button.
|
|
40
|
+
*/
|
|
41
|
+
export class ODWorkerManager<Instance, Source extends string, Params> extends ODManager<ODWorker<Instance,Source,Params>> {
|
|
42
|
+
/**The order of execution for workers inside this manager. */
|
|
43
|
+
#priorityOrder: "ascending"|"descending"
|
|
44
|
+
/**The backup worker will be executed when one of the workers fails or cancels execution. */
|
|
45
|
+
backupWorker: ODWorker<{reason:"error"|"cancel"},Source,Params>|null = null
|
|
46
|
+
|
|
47
|
+
constructor(priorityOrder:"ascending"|"descending"){
|
|
48
|
+
super()
|
|
49
|
+
this.#priorityOrder = priorityOrder
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**Get all workers in sorted order. */
|
|
53
|
+
getSortedWorkers(priority:"ascending"|"descending"){
|
|
54
|
+
const derefArray = [...this.getAll()]
|
|
55
|
+
|
|
56
|
+
return derefArray.sort((a,b) => {
|
|
57
|
+
if (priority == "ascending") return a.priority-b.priority
|
|
58
|
+
else return b.priority-a.priority
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
/**Execute all workers on an instance using the given source & parameters. */
|
|
62
|
+
async executeWorkers(instance:Instance, source:Source, params:Params){
|
|
63
|
+
const derefParams = {...params}
|
|
64
|
+
const workers = this.getSortedWorkers(this.#priorityOrder)
|
|
65
|
+
let didCancel = false
|
|
66
|
+
let didCrash = false
|
|
67
|
+
|
|
68
|
+
for (const worker of workers){
|
|
69
|
+
if (didCancel) break
|
|
70
|
+
try {
|
|
71
|
+
await worker.callback(instance,derefParams,source,() => {
|
|
72
|
+
didCancel = true
|
|
73
|
+
})
|
|
74
|
+
}catch(err){
|
|
75
|
+
process.emit("uncaughtException",err)
|
|
76
|
+
didCrash = true
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (didCancel && this.backupWorker){
|
|
80
|
+
try{
|
|
81
|
+
await this.backupWorker.callback({reason:"cancel"},derefParams,source,() => {})
|
|
82
|
+
}catch(err){
|
|
83
|
+
process.emit("uncaughtException",err)
|
|
84
|
+
}
|
|
85
|
+
}else if (didCrash && this.backupWorker){
|
|
86
|
+
try{
|
|
87
|
+
await this.backupWorker.callback({reason:"error"},derefParams,source,() => {})
|
|
88
|
+
}catch(err){
|
|
89
|
+
process.emit("uncaughtException",err)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
package/src/api/utils.ts
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as fs from "fs"
|
|
2
|
+
import ansis from "ansis"
|
|
3
|
+
import * as api from "./api"
|
|
4
|
+
|
|
5
|
+
/**## sharedFuses `utility variable`
|
|
6
|
+
* All shared fuses from Open Discord. Please use `opendiscord.sharedFuses` instead!
|
|
7
|
+
*/
|
|
8
|
+
export const sharedFuses: api.ODSharedFuseManager = new api.ODSharedFuseManager()
|
|
9
|
+
|
|
10
|
+
/**## checkNodeVersion `utility function`
|
|
11
|
+
* Check if the node.js version is v20 or higher.
|
|
12
|
+
*/
|
|
13
|
+
export function checkNodeVersion(project:api.ODProjectType){
|
|
14
|
+
const nodev = process.versions.node.split(".")
|
|
15
|
+
if (Number(nodev[0]) < 20){
|
|
16
|
+
const title = (project == "openticket") ? "OPEN TICKET" : "OPEN MODERATION"
|
|
17
|
+
console.log("\n\n==============================\n["+title+" ERROR]: Invalid node.js version. Open Ticket requires node.js v20 or above!\n==============================\n\n")
|
|
18
|
+
process.exit(1)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**## moduleInstalled `utility function`
|
|
23
|
+
* Use this function to check if an npm package is installed or not!
|
|
24
|
+
* @example utilities.moduleInstalled("discord.js") //check if discord.js is installed
|
|
25
|
+
*/
|
|
26
|
+
export function moduleInstalled(id:string,throwError?:boolean): boolean {
|
|
27
|
+
try{
|
|
28
|
+
require.resolve(id)
|
|
29
|
+
return true
|
|
30
|
+
}catch{
|
|
31
|
+
if (throwError) throw new Error("npm module \""+id+"\" is not installed! Install it via 'npm install "+id+"'")
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**## initialStartupLogs `utility function`
|
|
37
|
+
* Use this function to check if an npm package is installed or not!
|
|
38
|
+
* @example utilities.moduleInstalled("discord.js") //check if discord.js is installed
|
|
39
|
+
*/
|
|
40
|
+
export function initialStartupLogs(opendiscord:api.ODMain,project:api.ODProjectType){
|
|
41
|
+
const title = (project == "openticket") ? "OPEN TICKET" : "OPEN MODERATION"
|
|
42
|
+
console.log("\n--------------------------- "+title+" STARTUP ---------------------------")
|
|
43
|
+
opendiscord.log("Logging system activated!","system")
|
|
44
|
+
opendiscord.debug.debug("Using Node.js "+process.version+"!")
|
|
45
|
+
|
|
46
|
+
try{
|
|
47
|
+
const packageJson = JSON.parse(fs.readFileSync("./package.json").toString())
|
|
48
|
+
opendiscord.debug.debug("Using discord.js "+packageJson.dependencies["discord.js"]+"!")
|
|
49
|
+
opendiscord.debug.debug("Using @discordjs/rest "+packageJson.dependencies["@discordjs/rest"]+"!")
|
|
50
|
+
opendiscord.debug.debug("Using ansis "+packageJson.dependencies["ansis"]+"!")
|
|
51
|
+
opendiscord.debug.debug("Using formatted-json-stringify "+packageJson.dependencies["formatted-json-stringify"]+"!")
|
|
52
|
+
opendiscord.debug.debug("Using terminal-kit "+packageJson.dependencies["terminal-kit"]+"!")
|
|
53
|
+
opendiscord.debug.debug("Using typescript "+packageJson.dependencies["typescript"]+"!")
|
|
54
|
+
}catch{
|
|
55
|
+
opendiscord.debug.debug("Failed to fetch module versions!")
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**## timer `utility function`
|
|
60
|
+
* Use this to wait for a certain amount of milliseconds. This only works when using `await`
|
|
61
|
+
* @example await utilities.timer(1000) //wait 1sec
|
|
62
|
+
*/
|
|
63
|
+
export async function timer(ms:number): Promise<void> {
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
resolve()
|
|
67
|
+
},ms)
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**## emojiTitle `utility function`
|
|
72
|
+
* Use this function to create a title with an emoji before/after the text. The style & divider are set in `opendiscord.sharedFuses`
|
|
73
|
+
* @example utilities.emojiTitle("📎","Links") //create a title with an emoji based on the bot emoji style
|
|
74
|
+
*/
|
|
75
|
+
export function emojiTitle(emoji:string, text:string){
|
|
76
|
+
const style = sharedFuses.getFuse("emojiTitleStyle")
|
|
77
|
+
const divider = sharedFuses.getFuse("emojiTitleDivider")
|
|
78
|
+
|
|
79
|
+
if (style == "disabled") return text
|
|
80
|
+
else if (style == "before") return emoji+divider+text
|
|
81
|
+
else if (style == "after") return text+divider+emoji
|
|
82
|
+
else if (style == "double") return emoji+divider+text+divider+emoji
|
|
83
|
+
else return text
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**## runAsync `utility function`
|
|
87
|
+
* Use this function to run a snippet of code asyncronous without creating a separate function for it!
|
|
88
|
+
*/
|
|
89
|
+
export async function runAsync(func:() => Promise<void>): Promise<void> {
|
|
90
|
+
func()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**## timedAwait `utility function`
|
|
94
|
+
* Use this function to await a promise but reject after the certain timeout has been reached.
|
|
95
|
+
*/
|
|
96
|
+
export function timedAwait<ReturnValue>(promise:ReturnValue,timeout:number,onError:(err:Error) => void): ReturnValue {
|
|
97
|
+
let allowResolve = true
|
|
98
|
+
return new Promise(async (resolve,reject) => {
|
|
99
|
+
//set timeout & stop if it is before the promise resolved
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
allowResolve = false
|
|
102
|
+
reject("utilities.timedAwait() => Promise Timeout")
|
|
103
|
+
},timeout)
|
|
104
|
+
|
|
105
|
+
//get promise result & return if not already rejected
|
|
106
|
+
try{
|
|
107
|
+
const res = await promise
|
|
108
|
+
if (allowResolve) resolve(res)
|
|
109
|
+
}catch(err){
|
|
110
|
+
onError(err)
|
|
111
|
+
}
|
|
112
|
+
return promise
|
|
113
|
+
}) as ReturnValue
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**## dateString `utility function`
|
|
117
|
+
* Use this function to create a short date string in the following format: `DD/MM/YYYY HH:MM:SS`
|
|
118
|
+
*/
|
|
119
|
+
export function dateString(date): string {
|
|
120
|
+
return `${date.getDate()}/${date.getMonth()+1}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**## asyncReplace `utility function`
|
|
124
|
+
* Same as `string.replace(search, value)` but with async compatibility
|
|
125
|
+
*/
|
|
126
|
+
export async function asyncReplace(text:string, regex:RegExp, func:(value:string,...args:any[]) => Promise<string>): Promise<string> {
|
|
127
|
+
const promises: Promise<string>[] = []
|
|
128
|
+
text.replace(regex,(match,...args) => {
|
|
129
|
+
promises.push(func(match,...args))
|
|
130
|
+
return match
|
|
131
|
+
})
|
|
132
|
+
const data = await Promise.all(promises)
|
|
133
|
+
const result = text.replace(regex,(match) => {
|
|
134
|
+
const replaceResult = data.shift()
|
|
135
|
+
return replaceResult ?? match
|
|
136
|
+
})
|
|
137
|
+
return result
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**## getLongestLength `utility function`
|
|
141
|
+
* Get the length of the longest string in the array.
|
|
142
|
+
*/
|
|
143
|
+
export function getLongestLength(texts:string[]): number {
|
|
144
|
+
return Math.max(...texts.map((t) => ansis.strip(t).length))
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**## ordinalNumber `utility function`
|
|
148
|
+
* Get a human readable ordinal number (e.g. 1st, 2nd, 3rd, 4th, ...) from a Javascript number.
|
|
149
|
+
*/
|
|
150
|
+
export function ordinalNumber(num:number){
|
|
151
|
+
const i = Math.abs(Math.round(num))
|
|
152
|
+
const cent = i % 100
|
|
153
|
+
if (cent >= 10 && cent <= 20) return i+'th'
|
|
154
|
+
const dec = i % 10
|
|
155
|
+
if (dec === 1) return i+'st'
|
|
156
|
+
if (dec === 2) return i+'nd'
|
|
157
|
+
if (dec === 3) return i+'rd'
|
|
158
|
+
return i+'th'
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**## trimEmojis `utility function`
|
|
162
|
+
* Trim/remove all emoji's from a Javascript string.
|
|
163
|
+
*/
|
|
164
|
+
export function trimEmojis(text){
|
|
165
|
+
return text.replace(/(\p{Extended_Pictographic}(?:\uFE0F|\uFE0E)?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|\uFE0E)?)*)/gu,"")
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**## easterEggs `utility object`
|
|
169
|
+
* Object containing data for Open Ticket easter eggs.
|
|
170
|
+
*/
|
|
171
|
+
export const easterEggs: api.ODEasterEggs = {
|
|
172
|
+
/* THANK YOU TO ALL OUR CONTRIBUTORS!!! */
|
|
173
|
+
creator:"779742674932072469", //DJj123dj
|
|
174
|
+
translators:[
|
|
175
|
+
"779742674932072469", //DJj123dj
|
|
176
|
+
"574172558006681601", //Sanke
|
|
177
|
+
"540639725300613136", //Guillee.3
|
|
178
|
+
"547231585368539136", //Mods HD
|
|
179
|
+
"664934139954331649", //SpyEye
|
|
180
|
+
"498055992962187264", //Redactado
|
|
181
|
+
"912052735950618705", //T0miiis
|
|
182
|
+
"366673202610569227", //johusens
|
|
183
|
+
"360780292853858306", //David.3
|
|
184
|
+
"950611418389024809", //Sarcastic
|
|
185
|
+
"461603955517161473", //Maurizo
|
|
186
|
+
"465111430274875402", //The_Gamer
|
|
187
|
+
"586376952470831104", //Erxg
|
|
188
|
+
"226695254433202176", //Mkevas
|
|
189
|
+
"437695615095275520", //NoOneNook
|
|
190
|
+
"530047191222583307", //Anderskiy
|
|
191
|
+
"719072181631320145", //ToStam
|
|
192
|
+
"1172870906377408512", //Stragar
|
|
193
|
+
"1084794575945744445", //Sasanwm
|
|
194
|
+
"449613814049275905", //Benzorich
|
|
195
|
+
"905373133085741146", //Ronalds
|
|
196
|
+
"918504977369018408", //Palestinian
|
|
197
|
+
"807970841035145216", //Kornel0706
|
|
198
|
+
"1198883915826475080", //Nova
|
|
199
|
+
"669988226819162133", //Danoglez
|
|
200
|
+
"1313597620996018271", //Fraden1
|
|
201
|
+
"547809968145956884", //TsgIndrius
|
|
202
|
+
"264120132660363267", //Quiradon
|
|
203
|
+
"1272034143777329215", //NotMega
|
|
204
|
+
"LOREMIPSUM", //TODO, ADD MORE IDS IN FUTURE!
|
|
205
|
+
]
|
|
206
|
+
}
|