(v4.2.0) Panel auto-update now uses message states
This commit is contained in:
@@ -5,6 +5,7 @@ import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
|||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
||||||
|
const panelMsgState = opendiscord.states.get("opendiscord:panel-message")
|
||||||
|
|
||||||
export async function registerCommandResponders(){
|
export async function registerCommandResponders(){
|
||||||
//PANEL COMMAND RESPONDER
|
//PANEL COMMAND RESPONDER
|
||||||
@@ -36,15 +37,12 @@ export async function registerCommandResponders(){
|
|||||||
|
|
||||||
await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:panel-ready").build(origin,{guild,channel,user,panel}))
|
await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:panel-ready").build(origin,{guild,channel,user,panel}))
|
||||||
const panelMessage = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:panel").build(origin,{guild,channel,user,panel})).message)
|
const panelMessage = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:panel").build(origin,{guild,channel,user,panel})).message)
|
||||||
|
if (panelMessage) await panelMsgState.setMsgState({channel,message:panelMessage},{
|
||||||
//add panel to database (this way, the bot knows where all panels are located)
|
messageOrigin:origin,
|
||||||
const globalDatabase = opendiscord.databases.get("opendiscord:global")
|
panelId:panel.id.value,
|
||||||
await globalDatabase.set("opendiscord:panel-message",panelMessage.channel.id+"_"+panelMessage.id,panel.id.value)
|
panelOptionIds:panel.get("opendiscord:options").value,
|
||||||
|
panelAutoUpdate:(instance.options.getBoolean("auto-update",false) ?? false)
|
||||||
//add panel to database for auto-update
|
},panelMessage.flags.has("Ephemeral"))
|
||||||
if (instance.options.getBoolean("auto-update",false)){
|
|
||||||
await globalDatabase.set("opendiscord:panel-update",panelMessage.channel.id+"_"+panelMessage.id,panel.id.value)
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
|
new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
|
||||||
opendiscord.log(instance.user.displayName+" used the 'panel' command!","info",[
|
opendiscord.log(instance.user.displayName+" used the 'panel' command!","info",[
|
||||||
|
|||||||
+34
-10
@@ -6,6 +6,7 @@ import * as discord from "discord.js"
|
|||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
||||||
const lang = opendiscord.languages
|
const lang = opendiscord.languages
|
||||||
|
const panelMsgState = opendiscord.states.get("opendiscord:panel-message")
|
||||||
|
|
||||||
async function checkTicketCreationPerms(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance|api.ODCommandResponderInstance,origin:api.ODActionManagerIdMappings["opendiscord:create-ticket-permissions"]["origin"],guild:discord.Guild,user:discord.User,option:api.ODTicketOption){
|
async function checkTicketCreationPerms(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance|api.ODCommandResponderInstance,origin:api.ODActionManagerIdMappings["opendiscord:create-ticket-permissions"]["origin"],guild:discord.Guild,user:discord.User,option:api.ODTicketOption){
|
||||||
//check ticket permissions
|
//check ticket permissions
|
||||||
@@ -82,7 +83,15 @@ export async function registerButtonResponders(){
|
|||||||
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:ticket-option",/^od:ticket-option_/))
|
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:ticket-option",/^od:ticket-option_/))
|
||||||
opendiscord.responders.buttons.get("opendiscord:ticket-option").workers.add(
|
opendiscord.responders.buttons.get("opendiscord:ticket-option").workers.add(
|
||||||
new api.ODWorker("opendiscord:ticket-option",0,async (instance,params,origin,cancel) => {
|
new api.ODWorker("opendiscord:ticket-option",0,async (instance,params,origin,cancel) => {
|
||||||
const {guild,channel,user} = instance
|
const {guild,channel,user,message} = instance
|
||||||
|
|
||||||
|
//check message state
|
||||||
|
const state = await panelMsgState.getMsgState({channel,message})
|
||||||
|
if (!state){
|
||||||
|
//TODO TRANSLATION!!!
|
||||||
|
await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
|
||||||
|
return cancel()
|
||||||
|
}
|
||||||
|
|
||||||
//responder checks
|
//responder checks
|
||||||
const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
|
const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
|
||||||
@@ -124,7 +133,15 @@ export async function registerDropdownResponders(){
|
|||||||
opendiscord.responders.dropdowns.add(new api.ODDropdownResponder("opendiscord:panel-dropdown-tickets",/^od:panel-dropdown_/))
|
opendiscord.responders.dropdowns.add(new api.ODDropdownResponder("opendiscord:panel-dropdown-tickets",/^od:panel-dropdown_/))
|
||||||
opendiscord.responders.dropdowns.get("opendiscord:panel-dropdown-tickets").workers.add(
|
opendiscord.responders.dropdowns.get("opendiscord:panel-dropdown-tickets").workers.add(
|
||||||
new api.ODWorker("opendiscord:panel-dropdown-tickets",0,async (instance,params,origin,cancel) => {
|
new api.ODWorker("opendiscord:panel-dropdown-tickets",0,async (instance,params,origin,cancel) => {
|
||||||
const {guild,channel,user} = instance
|
const {guild,channel,user,message} = instance
|
||||||
|
|
||||||
|
//check message state
|
||||||
|
const state = await panelMsgState.getMsgState({channel,message})
|
||||||
|
if (!state){
|
||||||
|
//TODO TRANSLATION!!!
|
||||||
|
await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
|
||||||
|
return cancel()
|
||||||
|
}
|
||||||
|
|
||||||
//responder checks
|
//responder checks
|
||||||
const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
|
const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
|
||||||
@@ -159,11 +176,15 @@ export async function registerDropdownResponders(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//update panel after dropdown usage (reset panel choice)
|
//update panel after dropdown usage (reset panel choice)
|
||||||
const globalDatabase = opendiscord.databases.get("opendiscord:global")
|
const panel = opendiscord.panels.get(state.data.panelId)
|
||||||
const rawPanelId = await globalDatabase.get("opendiscord:panel-message",instance.message.channel.id+"_"+instance.message.id)
|
if (panel){
|
||||||
if (rawPanelId){
|
const panelMessage = await instance.message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild,channel,user,panel})).message)
|
||||||
const panel = opendiscord.panels.get(rawPanelId)
|
if (panelMessage) await panelMsgState.setMsgState({channel,message:panelMessage},{
|
||||||
if (panel) await instance.message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild,channel,user,panel})).message)
|
messageOrigin:"auto-update",
|
||||||
|
panelId:panel.id.value,
|
||||||
|
panelOptionIds:panel.get("opendiscord:options").value,
|
||||||
|
panelAutoUpdate:state.data.panelAutoUpdate //same value
|
||||||
|
},panelMessage.flags.has("Ephemeral"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -171,17 +192,21 @@ export async function registerDropdownResponders(){
|
|||||||
|
|
||||||
export async function registerModalResponders(){
|
export async function registerModalResponders(){
|
||||||
//TICKET QUESTIONS RESPONDER
|
//TICKET QUESTIONS RESPONDER
|
||||||
opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:ticket-questions",/^od:ticket-questions_/))
|
opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:ticket-questions",/^od:ticket-questions\|([^|]+)\|([^|]+)/))
|
||||||
opendiscord.responders.modals.get("opendiscord:ticket-questions").workers.add([
|
opendiscord.responders.modals.get("opendiscord:ticket-questions").workers.add([
|
||||||
new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,origin,cancel) => {
|
new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,origin,cancel) => {
|
||||||
const {guild,channel,user} = instance
|
const {guild,channel,user} = instance
|
||||||
|
|
||||||
|
const match = /^od:ticket-questions\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
|
||||||
|
if (!match) return cancel()
|
||||||
|
const optionId = match[1]
|
||||||
|
const originalOrigin = match[2] as ("panel-button"|"panel-dropdown"|"slash"|"text"|"other")
|
||||||
|
|
||||||
//responder checks
|
//responder checks
|
||||||
const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
|
const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
|
||||||
if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
|
if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
|
||||||
|
|
||||||
//get option data
|
//get option data
|
||||||
const optionId = instance.interaction.customId.split("_")[1]
|
|
||||||
const option = opendiscord.options.get(optionId)
|
const option = opendiscord.options.get(optionId)
|
||||||
if (!option || !(option instanceof api.ODTicketOption)){
|
if (!option || !(option instanceof api.ODTicketOption)){
|
||||||
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel,user:instance.user}))
|
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel,user:instance.user}))
|
||||||
@@ -189,7 +214,6 @@ export async function registerModalResponders(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check ticket permissions (modals need check after submit)
|
//check ticket permissions (modals need check after submit)
|
||||||
const originalOrigin = instance.interaction.customId.split("_")[2] as ("panel-button"|"panel-dropdown"|"slash"|"text"|"other")
|
|
||||||
if (!(await checkTicketCreationPerms(instance,originalOrigin,guild,user,option))) return cancel()
|
if (!(await checkTicketCreationPerms(instance,originalOrigin,guild,user,option))) return cancel()
|
||||||
|
|
||||||
//get answers
|
//get answers
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { ODTicketClearFilter } from "../api/ticket.js"
|
|||||||
export interface ODStateManagerIdMappings extends api.ODStateManagerIdConstraint {
|
export interface ODStateManagerIdMappings extends api.ODStateManagerIdConstraint {
|
||||||
"opendiscord:interactive-message":ODInteractiveMessageState,
|
"opendiscord:interactive-message":ODInteractiveMessageState,
|
||||||
"opendiscord:clear-message":ODClearMessageState,
|
"opendiscord:clear-message":ODClearMessageState,
|
||||||
|
"opendiscord:panel-message":ODPanelMessageState,
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
@@ -60,3 +61,21 @@ export class ODClearMessageState extends api.ODState<{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**## ODPanelMessageState `class
|
||||||
|
* A special class with state types for the Open Ticket panel message.
|
||||||
|
*/
|
||||||
|
export class ODPanelMessageState extends api.ODState<{
|
||||||
|
/**The method this message was generated with. */
|
||||||
|
messageOrigin:"slash"|"text"|"auto-update"|"other",
|
||||||
|
/**The Id of the panel associated with this message. */
|
||||||
|
panelId:string,
|
||||||
|
/**A list of options available in this panel. (buttons or dropdown) */
|
||||||
|
panelOptionIds:string[]
|
||||||
|
/**Should this panel be auto-updated on restart? */
|
||||||
|
panelAutoUpdate:boolean
|
||||||
|
},false,false> {
|
||||||
|
constructor(id:api.ODValidId,client:api.ODClientManager,database:api.ODDatabase){
|
||||||
|
super(id,client,database,{})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -339,8 +339,10 @@ export const migrations = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
//migrate database
|
//migrate database
|
||||||
|
const globalDatabase = opendiscord.databases.get("opendiscord:global")
|
||||||
const optionDatabase = opendiscord.databases.get("opendiscord:options")
|
const optionDatabase = opendiscord.databases.get("opendiscord:options")
|
||||||
const ticketDatabase = opendiscord.databases.get("opendiscord:tickets")
|
const ticketDatabase = opendiscord.databases.get("opendiscord:tickets")
|
||||||
|
const stateDatabase = opendiscord.databases.get("opendiscord:message-states")
|
||||||
|
|
||||||
for (const option of (await optionDatabase.getCategory("opendiscord:used-option") ?? [])){
|
for (const option of (await optionDatabase.getCategory("opendiscord:used-option") ?? [])){
|
||||||
const optionData = option.value
|
const optionData = option.value
|
||||||
@@ -359,6 +361,34 @@ export const migrations = [
|
|||||||
|
|
||||||
ticketDatabase.set("opendiscord:ticket",ticket.key,ticketData)
|
ticketDatabase.set("opendiscord:ticket",ticket.key,ticketData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//migrate old panel messages from global.json to the new message states
|
||||||
|
const migratedPanelStates: {channelId:string,messageId:string,panelId:string,autoUpdate:boolean}[] = []
|
||||||
|
opendiscord.events.get("afterClientReady").listen(async () => {
|
||||||
|
for (const panelMessage of (await globalDatabase.getCategory("opendiscord:panel-message") ?? [])){
|
||||||
|
const splittedId = panelMessage.key.split("_")
|
||||||
|
const channelId = splittedId[0]
|
||||||
|
const messageId = splittedId[1]
|
||||||
|
const message = await opendiscord.client.fetchChannelMessage(channelId,messageId)
|
||||||
|
const autoUpdate = typeof (await globalDatabase.get("opendiscord:panel-update",panelMessage.key)) == "string"
|
||||||
|
//if message still exists
|
||||||
|
if (message) migratedPanelStates.push({channelId,messageId,panelId:panelMessage.value,autoUpdate})
|
||||||
|
|
||||||
|
await globalDatabase.delete("opendiscord:panel-message",panelMessage.key)
|
||||||
|
await globalDatabase.delete("opendiscord:panel-update",panelMessage.key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
opendiscord.events.get("afterStatesInitiated").listen(async (states) => {
|
||||||
|
const panelMsgState = states.get("opendiscord:panel-message")
|
||||||
|
for (const {channelId,messageId,panelId,autoUpdate} of migratedPanelStates){
|
||||||
|
await panelMsgState.setMsgState({channel:channelId,message:messageId},{
|
||||||
|
messageOrigin:"auto-update",
|
||||||
|
panelId,
|
||||||
|
panelOptionIds:[],
|
||||||
|
panelAutoUpdate:autoUpdate
|
||||||
|
},false)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
@@ -69,38 +69,6 @@ export async function loadStartListeningInteractionsCode(){
|
|||||||
export async function loadDatabaseCleanersCode(){
|
export async function loadDatabaseCleanersCode(){
|
||||||
if (!mainServer) return
|
if (!mainServer) return
|
||||||
|
|
||||||
//PANEL DATABASE CLEANER
|
|
||||||
opendiscord.code.add(new api.ODCode("opendiscord:panel-database-cleaner",12,async () => {
|
|
||||||
const validPanels: string[] = []
|
|
||||||
|
|
||||||
//check global database for valid panel embeds
|
|
||||||
for (const panel of (await globalDatabase.getCategory("opendiscord:panel-message") ?? [])){
|
|
||||||
if (!validPanels.includes(panel.key)){
|
|
||||||
try{
|
|
||||||
const splittedId = panel.key.split("_")
|
|
||||||
const message = await opendiscord.client.fetchChannelMessage(splittedId[0],splittedId[1])
|
|
||||||
if (message) validPanels.push(panel.key)
|
|
||||||
}catch{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove all unused panels
|
|
||||||
for (const panel of (await globalDatabase.getCategory("opendiscord:panel-message") ?? [])){
|
|
||||||
if (!validPanels.includes(panel.key)){
|
|
||||||
await globalDatabase.delete("opendiscord:panel-message",panel.key)
|
|
||||||
await globalDatabase.delete("opendiscord:panel-update",panel.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete panel from database on delete
|
|
||||||
opendiscord.client.client.on("messageDelete",async (msg) => {
|
|
||||||
if (await globalDatabase.exists("opendiscord:panel-message",msg.channel.id+"_"+msg.id)){
|
|
||||||
await globalDatabase.delete("opendiscord:panel-message",msg.channel.id+"_"+msg.id)
|
|
||||||
await globalDatabase.delete("opendiscord:panel-update",msg.channel.id+"_"+msg.id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
|
|
||||||
//SUFFIX DATABASE CLEANER
|
//SUFFIX DATABASE CLEANER
|
||||||
opendiscord.code.add(new api.ODCode("opendiscord:suffix-database-cleaner",11,async () => {
|
opendiscord.code.add(new api.ODCode("opendiscord:suffix-database-cleaner",11,async () => {
|
||||||
const validSuffixCounters: string[] = []
|
const validSuffixCounters: string[] = []
|
||||||
@@ -284,34 +252,43 @@ export async function loadDatabaseCleanersCode(){
|
|||||||
|
|
||||||
export async function loadPanelAutoUpdateCode(){
|
export async function loadPanelAutoUpdateCode(){
|
||||||
//PANEL AUTO UPDATE
|
//PANEL AUTO UPDATE
|
||||||
|
const panelMsgState = opendiscord.states.get("opendiscord:panel-message")
|
||||||
opendiscord.code.add(new api.ODCode("opendiscord:panel-auto-update",7,async () => {
|
opendiscord.code.add(new api.ODCode("opendiscord:panel-auto-update",7,async () => {
|
||||||
const globalDatabase = opendiscord.databases.get("opendiscord:global")
|
|
||||||
const panelIds = await globalDatabase.getCategory("opendiscord:panel-update") ?? []
|
|
||||||
if (!mainServer) return
|
if (!mainServer) return
|
||||||
|
|
||||||
for (const panelId of panelIds){
|
for (const panelState of (await panelMsgState.listMsgStates()).map((rawState) => rawState.value)){
|
||||||
const panel = opendiscord.panels.get(panelId.value)
|
|
||||||
|
|
||||||
//panel doesn't exist anymore in config and needs to be removed
|
|
||||||
if (!panel){
|
|
||||||
globalDatabase.delete("opendiscord:panel-update",panelId.key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
const splittedId = panelId.key.split("_")
|
//fetch panel (& check if auto-update is required)
|
||||||
const channel = await opendiscord.client.fetchGuildTextChannel(mainServer,splittedId[0])
|
const panel = opendiscord.panels.get(panelState.data.panelId)
|
||||||
if (!channel) return
|
if (!panel || !panelState.data.panelAutoUpdate) continue
|
||||||
const message = await opendiscord.client.fetchChannelMessage(channel,splittedId[1])
|
|
||||||
if (!message || !message.editable) return
|
//fetch panel channel
|
||||||
|
const channel = await opendiscord.client.fetchGuildTextChannel(mainServer,panelState.channelId)
|
||||||
|
if (!channel) continue
|
||||||
|
|
||||||
|
//fetch panel message
|
||||||
|
const message = await opendiscord.client.fetchChannelMessage(channel,panelState.messageId)
|
||||||
|
if (!message || !message.editable || message.flags.has("Ephemeral")) continue
|
||||||
|
|
||||||
|
const panelMessage = await message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild:mainServer,channel,user:opendiscord.client.client.user,panel})).message)
|
||||||
|
if (panelMessage) await panelMsgState.setMsgState({channel,message:panelMessage},{
|
||||||
|
messageOrigin:"auto-update",
|
||||||
|
panelId:panel.id.value,
|
||||||
|
panelOptionIds:panel.get("opendiscord:options").value,
|
||||||
|
panelAutoUpdate:true
|
||||||
|
},panelMessage.flags.has("Ephemeral"))
|
||||||
|
|
||||||
message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild:mainServer,channel,user:opendiscord.client.client.user,panel})).message)
|
|
||||||
opendiscord.log("Panel in server got auto-updated!","info",[
|
opendiscord.log("Panel in server got auto-updated!","info",[
|
||||||
{key:"channelid",value:splittedId[0]},
|
{key:"channelid",value:panelState.channelId},
|
||||||
{key:"messageid",value:splittedId[1]},
|
{key:"messageid",value:panelState.messageId},
|
||||||
{key:"panel",value:panelId.value}
|
{key:"panel",value:panel.id.value}
|
||||||
])
|
])
|
||||||
}catch{}
|
}catch{
|
||||||
|
opendiscord.log("Failed to auto-update panel","error",[
|
||||||
|
{key:"channelid",value:panelState.channelId},
|
||||||
|
{key:"messageid",value:panelState.messageId}
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ export async function loadAllStates(){
|
|||||||
|
|
||||||
opendiscord.states.add(new api.ODInteractiveMessageState("opendiscord:interactive-message",opendiscord.client,stateDatabase))
|
opendiscord.states.add(new api.ODInteractiveMessageState("opendiscord:interactive-message",opendiscord.client,stateDatabase))
|
||||||
opendiscord.states.add(new api.ODClearMessageState("opendiscord:clear-message",opendiscord.client,stateDatabase))
|
opendiscord.states.add(new api.ODClearMessageState("opendiscord:clear-message",opendiscord.client,stateDatabase))
|
||||||
|
opendiscord.states.add(new api.ODPanelMessageState("opendiscord:panel-message",opendiscord.client,stateDatabase))
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user