diff --git a/src/actions/claimTicket.ts b/src/actions/claimTicket.ts index f901362..7d886fc 100644 --- a/src/actions/claimTicket.ts +++ b/src/actions/claimTicket.ts @@ -5,6 +5,7 @@ import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerActions(){ opendiscord.actions.add(new api.ODAction("opendiscord:claim-ticket")) @@ -62,7 +63,15 @@ export async function registerActions(){ } //reply with new message - if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (params.sendMessage){ + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"claim-message", + messageOrigin:"other", + messageAuthor:user.id, + messageReason:reason + },false) + } ticket.get("opendiscord:busy").value = false await opendiscord.events.get("afterTicketClaimed").emit([ticket,user,channel,reason]) @@ -99,184 +108,4 @@ export async function registerActions(){ //set busy to false in case of crash or cancel params.ticket.get("opendiscord:busy").value = false }) -} - -export async function registerVerifyBars(){ - //CLAIM TICKET TICKET MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.claim - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when already claimed - if (ticket.get("opendiscord:claimed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start claiming ticket - if (params.data == "reason"){ - //claim with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("ticket-message",{guild,channel,user,ticket})) - }else{ - //claim without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:claim-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").failure.add([ - new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }) - ]) - - //CLAIM TICKET UNCLAIM MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket-unclaim-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-unclaim-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.claim - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when already claimed - if (ticket.get("opendiscord:claimed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start claiming ticket - if (params.data == "reason"){ - //claim with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("unclaim-message",{guild,channel,user,ticket})) - }else{ - //claim without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:claim-ticket").run("unclaim-message",{guild,channel,user,ticket,reason:null,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("unclaim-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").failure.add([ - new api.ODWorker("opendiscord:back-to-unclaim-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) } \ No newline at end of file diff --git a/src/actions/closeTicket.ts b/src/actions/closeTicket.ts index 8a88d29..29d886f 100644 --- a/src/actions/closeTicket.ts +++ b/src/actions/closeTicket.ts @@ -127,7 +127,15 @@ export async function registerActions(){ } //reply with new message - if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (params.sendMessage){ + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"close-message", + messageOrigin:"other", + messageAuthor:user.id, + messageReason:reason + },false) + } ticket.get("opendiscord:busy").value = false await opendiscord.events.get("afterTicketClosed").emit([ticket,user,channel,reason]) @@ -164,172 +172,4 @@ export async function registerActions(){ //set busy to false in case of crash or cancel params.ticket.get("opendiscord:busy").value = false }) -} - -export const registerVerifyBars = async () => { - //CLOSE TICKET TICKET MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").success.add([ - new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin,cancel) => { - const {user,member,channel,guild} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when already closed - if (ticket.get("opendiscord:closed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:lang.getTranslation("errors.actionInvalid.close"),layout:"simple"})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } - - //start closing ticket - if (params.data == "reason"){ - //close with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("ticket-message",{guild,channel,user,ticket})) - }else{ - //close without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:close-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").failure.add([ - new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }) - ]) - - //CLOSE TICKET REOPEN MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket-reopen-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-reopen-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").success.add([ - new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin,cancel) => { - const {user,member,channel,guild} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when already closed - if (ticket.get("opendiscord:closed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:lang.getTranslation("errors.actionInvalid.close"),layout:"simple"})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } - - //start closing ticket - if (params.data == "reason"){ - //close with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("reopen-message",{guild,channel,user,ticket})) - }else{ - //close without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:close-ticket").run("reopen-message",{guild,channel,user,ticket,reason:null,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("reopen-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").failure.add([ - new api.ODWorker("opendiscord:back-to-reopen-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) } \ No newline at end of file diff --git a/src/actions/createTicket.ts b/src/actions/createTicket.ts index e57544f..7b580d9 100644 --- a/src/actions/createTicket.ts +++ b/src/actions/createTicket.ts @@ -6,6 +6,7 @@ import * as discord from "discord.js" const generalConfig = opendiscord.configs.get("opendiscord:general") const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerActions(){ opendiscord.actions.add(new api.ODAction("opendiscord:create-ticket")) @@ -207,17 +208,23 @@ export async function registerActions(){ //check if ticket message is enabled if (!option.get("opendiscord:ticket-message-enabled").value) return try { - const msg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build(origin,{guild,channel,user,ticket})).message) + const ticketMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build(origin,{guild,channel,user,ticket})).message) - ticket.get("opendiscord:ticket-message").value = msg.id + if (ticketMsg) await interactiveMsgState.setMsgState({channel,message:ticketMsg},{ + messageType:"ticket-message", + messageOrigin:"other", + messageAuthor:user.id + },false) + + ticket.get("opendiscord:ticket-message").value = ticketMsg.id //pin ticket message (if required) - if (generalConfig.data.system.pinFirstTicketMessage && msg.pinnable) await msg.pin("Ticket Message") + if (generalConfig.data.system.pinFirstTicketMessage && ticketMsg.pinnable) await ticketMsg.pin("Ticket Message") //manage stats await opendiscord.statistics.get("opendiscord:ticket").setStat("opendiscord:messages-sent",ticket.id.value,1,"increase") - await opendiscord.events.get("afterTicketMainMessageCreated").emit([ticket,msg,channel,user]) + await opendiscord.events.get("afterTicketMainMessageCreated").emit([ticket,ticketMsg,channel,user]) }catch(err){ process.emit("uncaughtException",err) //something went wrong while sending the ticket message diff --git a/src/actions/deleteTicket.ts b/src/actions/deleteTicket.ts index 28d98fe..b7f0005 100644 --- a/src/actions/deleteTicket.ts +++ b/src/actions/deleteTicket.ts @@ -113,357 +113,4 @@ export async function registerActions(){ params.ticket.get("opendiscord:busy").value = false params.ticket.get("opendiscord:for-deletion").value = false }) -} - -export async function registerVerifyBars(){ - //DELETE TICKET TICKET MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").success.add([ - new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => { - const {user,member,channel,guild} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //don't allow deleteWithoutTranscript to non-global-admins when enabled - if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - } - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } - - //start deleting ticket - if (params.data == "reason"){ - //delete with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("ticket-message",{guild,channel,user,ticket})) - }else{ - //delete without reason - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true,withoutTranscript:(params.data == "no-transcript")}) - //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable - ticket.get("opendiscord:for-deletion").value = true - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").failure.add([ - new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }) - ]) - - //DELETE TICKET CLOSE MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-close-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-close-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").success.add([ - new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => { - const {user,member,channel,guild} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //don't allow deleteWithoutTranscript to non-global-admins when enabled - if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - } - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } - - //start deleting ticket - if (params.data == "reason"){ - //delete with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("close-message",{guild,channel,user,ticket})) - }else{ - //delete without reason - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run("close-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")}) - //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable - ticket.get("opendiscord:for-deletion").value = true - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("close-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").failure.add([ - new api.ODWorker("opendiscord:back-to-close-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) - - //DELETE TICKET REOPEN MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-reopen-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-reopen-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").success.add([ - new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => { - const {user,member,channel,guild} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //don't allow deleteWithoutTranscript to non-global-admins when enabled - if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - } - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } - - //start deleting ticket - if (params.data == "reason"){ - //delete with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("reopen-message",{guild,channel,user,ticket})) - }else{ - //delete without reason - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run("reopen-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")}) - //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable - ticket.get("opendiscord:for-deletion").value = true - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("reopen-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").failure.add([ - new api.ODWorker("opendiscord:back-to-reopen-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) - - //DELETE TICKET AUTOCLOSE MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-autoclose-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-autoclose-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").success.add([ - new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => { - const {user,member,channel,guild} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //don't allow deleteWithoutTranscript to non-global-admins when enabled - if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - } - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } - - //start deleting ticket - if (params.data == "reason"){ - //delete with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("autoclose-message",{guild,channel,user,ticket})) - }else{ - //delete without reason - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run("autoclose-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")}) - //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable - ticket.get("opendiscord:for-deletion").value = true - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("autoclose-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").failure.add([ - new api.ODWorker("opendiscord:back-to-autoclose-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket})) - }) - ]) } \ No newline at end of file diff --git a/src/actions/handleVerifyBar.ts b/src/actions/handleVerifyBar.ts index c0c3be6..f2f5961 100644 --- a/src/actions/handleVerifyBar.ts +++ b/src/actions/handleVerifyBar.ts @@ -3,30 +3,19 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" -export const registerButtonResponders = async () => { - //VERIFYBAR SUCCESS - opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-success",/^od:verifybar-success_([^_]+)/)) - opendiscord.responders.buttons.get("opendiscord:verifybar-success").workers.add( +export async function registerButtonResponders(){ + //HANDLE VERIFYBAR BUTTON + opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-button",/^od:verifybar\|([^|]+)\|([^|]+)/)) + opendiscord.responders.buttons.get("opendiscord:verifybar-button").workers.add( new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,origin,cancel) => { - const id = instance.interaction.customId.split("_")[1] - const customData = instance.interaction.customId.split("_")[2] as string|undefined + const match = /^od:verifybar\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const verifyBarId = match[1] + const verifyButtonId = match[2] - const verifybar = opendiscord.verifybars.get(id) + const verifybar = opendiscord.verifybars.get(verifyBarId) if (!verifybar) return - if (verifybar.success) await verifybar.success.executeWorkers(instance,"verifybar",{data:customData ?? null,verifybarMessage:instance.message}) - }) - ) - - //VERIFYBAR FAILURE - opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-failure",/^od:verifybar-failure_([^_]+)/)) - opendiscord.responders.buttons.get("opendiscord:verifybar-failure").workers.add( - new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,origin,cancel) => { - const id = instance.interaction.customId.split("_")[1] - const customData = instance.interaction.customId.split("_")[2] as string|undefined - - const verifybar = opendiscord.verifybars.get(id) - if (!verifybar) return - if (verifybar.failure) await verifybar.failure.executeWorkers(instance,"verifybar",{data:customData ?? null,verifybarMessage:instance.message}) + await verifybar.activate(instance,verifyButtonId) }) ) } \ No newline at end of file diff --git a/src/actions/pinTicket.ts b/src/actions/pinTicket.ts index 74c77c4..a55484e 100644 --- a/src/actions/pinTicket.ts +++ b/src/actions/pinTicket.ts @@ -5,6 +5,7 @@ import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerActions(){ opendiscord.actions.add(new api.ODAction("opendiscord:pin-ticket")) @@ -61,7 +62,15 @@ export async function registerActions(){ } //reply with new message - if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (params.sendMessage){ + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"pin-message", + messageOrigin:"other", + messageAuthor:user.id, + messageReason:reason + },false) + } ticket.get("opendiscord:busy").value = false await opendiscord.events.get("afterTicketPinned").emit([ticket,user,channel,reason]) @@ -94,188 +103,4 @@ export async function registerActions(){ ]) }) ]) -} - -export async function registerVerifyBars(){ - //PIN TICKET TICKET MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.pin - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when already pinned - if (ticket.get("opendiscord:pinned").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start pinning ticket - if (params.data == "reason"){ - //pin with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("ticket-message",{guild,channel,user,ticket})) - }else{ - //pin without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:pin-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").failure.add([ - new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }) - ]) - - //PIN TICKET UNPIN MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket-unpin-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-unpin-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.pin - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when already pinned - if (ticket.get("opendiscord:pinned").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start pinning ticket - if (params.data == "reason"){ - //pin with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("unpin-message",{guild,channel,user,ticket})) - }else{ - //pin without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:pin-ticket").run("unpin-message",{guild,channel,user,ticket,reason:null,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("unpin-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").failure.add([ - new api.ODWorker("opendiscord:back-to-unpin-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) - opendiscord.actions.get("opendiscord:pin-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => { - //set busy to false in case of crash or cancel - params.ticket.get("opendiscord:busy").value = false - }) } \ No newline at end of file diff --git a/src/actions/reopenTicket.ts b/src/actions/reopenTicket.ts index 4865cd4..dbc169b 100644 --- a/src/actions/reopenTicket.ts +++ b/src/actions/reopenTicket.ts @@ -5,6 +5,7 @@ import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerActions(){ opendiscord.actions.add(new api.ODAction("opendiscord:reopen-ticket")) @@ -157,7 +158,15 @@ export async function registerActions(){ } } - if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (params.sendMessage){ + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"reopen-message", + messageOrigin:"other", + messageAuthor:user.id, + messageReason:reason + },false) + } ticket.get("opendiscord:busy").value = false await opendiscord.events.get("afterTicketReopened").emit([ticket,user,channel,reason]) @@ -190,276 +199,4 @@ export async function registerActions(){ ]) }) ]) -} - -export async function registerVerifyBars(){ - //REOPEN TICKET TICKET MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.reopen - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when not closed - if (!ticket.get("opendiscord:closed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start reopening ticket - if (params.data == "reason"){ - //reopen with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("ticket-message",{guild,channel,user,ticket})) - }else{ - //reopen without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:reopen-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").failure.add([ - new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }) - ]) - - //REOPEN TICKET CLOSE MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-close-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-close-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.reopen - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when not closed - if (!ticket.get("opendiscord:closed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start reopening ticket - if (params.data == "reason"){ - //reopen with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("close-message",{guild,channel,user,ticket})) - }else{ - //reopen without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:reopen-ticket").run("close-message",{guild,channel,user,ticket,reason:null,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("close-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").failure.add([ - new api.ODWorker("opendiscord:back-to-close-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) - - //REOPEN TICKET AUTOCLOSE MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-autoclose-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-autoclose-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.reopen - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when not closed - if (!ticket.get("opendiscord:closed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start reopening ticket - if (params.data == "reason"){ - //reopen with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("autoclose-message",{guild,channel,user,ticket})) - }else{ - //reopen without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:reopen-ticket").run("autoclose-message",{guild,channel,user,ticket,reason:null,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("autoclose-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").failure.add([ - new api.ODWorker("opendiscord:back-to-autoclose-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket})) - }) - ]) - opendiscord.actions.get("opendiscord:reopen-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => { - //set busy to false in case of crash or cancel - params.ticket.get("opendiscord:busy").value = false - }) } \ No newline at end of file diff --git a/src/actions/unclaimTicket.ts b/src/actions/unclaimTicket.ts index 1a2e3f1..a26853a 100644 --- a/src/actions/unclaimTicket.ts +++ b/src/actions/unclaimTicket.ts @@ -5,6 +5,7 @@ import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerActions(){ opendiscord.actions.add(new api.ODAction("opendiscord:unclaim-ticket")) @@ -91,7 +92,15 @@ export async function registerActions(){ } //reply with new message - if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (params.sendMessage){ + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"unclaim-message", + messageOrigin:"other", + messageAuthor:user.id, + messageReason:reason + },false) + } ticket.get("opendiscord:busy").value = false await opendiscord.events.get("afterTicketUnclaimed").emit([ticket,user,channel,reason]) @@ -124,188 +133,4 @@ export async function registerActions(){ ]) }) ]) -} - -export async function registerVerifyBars(){ - //UNCLAIM TICKET TICKET MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.unclaim - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when not claimed - if (!ticket.get("opendiscord:claimed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start unclaiming ticket - if (params.data == "reason"){ - //unclaim with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("ticket-message",{guild,channel,user,ticket})) - }else{ - //unclaim without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unclaim-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").failure.add([ - new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }) - ]) - - //UNCLAIM TICKET CLAIM MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket-claim-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-claim-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.unclaim - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when not claimed - if (!ticket.get("opendiscord:claimed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start unclaiming ticket - if (params.data == "reason"){ - //unclaim with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("claim-message",{guild,channel,user,ticket})) - }else{ - //unclaim without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unclaim-ticket").run("claim-message",{guild,channel,user,ticket,reason:null,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("claim-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").failure.add([ - new api.ODWorker("opendiscord:back-to-claim-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) - opendiscord.actions.get("opendiscord:unclaim-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => { - //set busy to false in case of crash or cancel - params.ticket.get("opendiscord:busy").value = false - }) } \ No newline at end of file diff --git a/src/actions/unpinTicket.ts b/src/actions/unpinTicket.ts index 5564dc6..7cc2d06 100644 --- a/src/actions/unpinTicket.ts +++ b/src/actions/unpinTicket.ts @@ -5,6 +5,7 @@ import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerActions(){ opendiscord.actions.add(new api.ODAction("opendiscord:unpin-ticket")) @@ -52,7 +53,15 @@ export async function registerActions(){ } //reply with new message - if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (params.sendMessage){ + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason})).message) + if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"unpin-message", + messageOrigin:"other", + messageAuthor:user.id, + messageReason:reason + },false) + } ticket.get("opendiscord:busy").value = false await opendiscord.events.get("afterTicketUnpinned").emit([ticket,user,channel,reason]) @@ -85,188 +94,4 @@ export async function registerActions(){ ]) }) ]) -} - -export async function registerVerifyBars(){ - //UNPIN TICKET TICKET MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.unpin - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when not pinned - if (!ticket.get("opendiscord:pinned").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start unpining ticket - if (params.data == "reason"){ - //unpin with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("ticket-message",{guild,channel,user,ticket})) - }else{ - //unpin without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unpin-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").failure.add([ - new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }) - ]) - - //UNPIN TICKET PIN MESSAGE - opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket-pin-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-pin-message"),!generalConfig.data.system.disableVerifyBars)) - opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").success.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.unpin - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), - new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - //return when not pinned - if (!ticket.get("opendiscord:pinned").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //start unpinning ticket - if (params.data == "reason"){ - //unpin with reason - instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("pin-message",{guild,channel,user,ticket})) - }else{ - //unpin without reason - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unpin-ticket").run("pin-message",{guild,channel,user,ticket,reason:null,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("pin-message",{guild,channel,user,ticket,reason:null})) - } - }) - ]) - opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").failure.add([ - new api.ODWorker("opendiscord:back-to-pin-message",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - const {verifybarMessage} = params - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("other",{guild,channel,user,ticket,reason})) - }) - ]) - opendiscord.actions.get("opendiscord:unpin-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => { - //set busy to false in case of crash or cancel - params.ticket.get("opendiscord:busy").value = false - }) } \ No newline at end of file diff --git a/src/actions/utilities.ts b/src/actions/utilities.ts new file mode 100644 index 0000000..ae657de --- /dev/null +++ b/src/actions/utilities.ts @@ -0,0 +1,160 @@ +/////////////////////////////////////// +//ACTION UTILITY FUNCTIONS +/////////////////////////////////////// +import {opendiscord, api, utilities} from "../index.js" +import * as discord from "discord.js" + +const lang = opendiscord.languages + +/**Fetch the interactive message state. If not present, auto replies with error and returns `null`. When `null` is received, the worker should be returned and canceled. */ +export async function replyInteractiveMessageState(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",channel:discord.TextBasedChannel,message:discord.Message|null,replacementCommandName:string){ + //check message state + const {user,member,guild} = instance + const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") + + if (!message){ + //TODO TRANSLATION!!! + await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"Unable to locate message of interaction. Use the command `{0}` instead.".replace("{0}",replacementCommandName),layout:"simple",customTitle:"Message State Error"})) + return null + } + + const state = await interactiveMsgState.getMsgState({channel,message}) + if (!state){ + //TODO TRANSLATION!!! + await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This interaction is no longer valid or has expired. Use the command `{0}` instead. It is normal to receive this error after a major Open Ticket update.".replace("{0}",replacementCommandName),layout:"simple",customTitle:"Message State Expired"})) + return null + }else return state +} + +/**Check the permissions for this command. If not allowed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyHasPermissions(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",commandName:keyof api.ODGeneralJsonConfig_SystemPermissions) { + //check permissions + const {user,member,channel,guild} = instance + const generalConfig = opendiscord.configs.get("opendiscord:general") + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions[commandName],"support",user,member,channel,guild) + + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server" && channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) + return false + }else return true +} + +/**Check if channel is in guild/server. If not, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyIsInGuild(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other"){ + //check is in guild/server + const {user,member,channel,guild} = instance + + if (!guild){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user})) + return false + }else return true +} + +/**Check if channel is valid ticket. If not, auto replies with error and returns `null`. When `null` is received, the worker should be returned and canceled. */ +export async function replyIsTicket(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other") { + //check if ticket exists + const {user,member,channel,guild} = instance + if (!channel) return null + const ticket = opendiscord.tickets.get(channel.id) + + if (!ticket || channel.isDMBased()){ + await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build(origin,{guild,channel,user})) + return null + }else return ticket +} + +/**Check if ticket is not busy and available. If not, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyTicketIsAvailable(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) { + //return when busy + const {user,member,channel,guild} = instance + + if (ticket.get("opendiscord:busy").value){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build(origin,{guild,channel,user})) + return false + }else return true +} + +/**Check if ticket is open. If closed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyTicketMustBeOpen(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket){ + //return when already closed + const {user,member,channel,guild} = instance + if (ticket.get("opendiscord:closed").value){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"})) + return false + }else return true +} + +/**Check if ticket is closed. If open, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyTicketMustBeClosed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) { + //return when already open + const {user,member,channel,guild} = instance + if (!ticket.get("opendiscord:closed").value){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"})) + return false + }else return true +} + +/**Check if ticket is unclaimed. If claimed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyTicketMustBeUnclaimed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) { + //return when already claimed + const {user,member,channel,guild} = instance + if (ticket.get("opendiscord:claimed").value){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"})) + return false + }else return true +} + +/**Check if ticket is claimed. If unclaimed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyTicketMustBeClaimed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) { + //return when already unclaimed + const {user,member,channel,guild} = instance + if (!ticket.get("opendiscord:claimed").value){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"})) + return false + }else return true +} + +/**Check if ticket is unpinned. If pinned, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyTicketMustBeUnpinned(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) { + //return when already pinned + const {user,member,channel,guild} = instance + if (ticket.get("opendiscord:pinned").value){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"})) + return false + }else return true +} + +/**Check if ticket is pinned. If unpinned, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyTicketMustBePinned(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) { + //return when already unpinned + const {user,member,channel,guild} = instance + if (!ticket.get("opendiscord:pinned").value){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"})) + return false + }else return true +} + +/**Check if the ticket can be closed/deleted before a message has been sent by an admin or user. If not passing the test, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */ +export async function replyMessageMustBeSentBeforeClose(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket,commandName:keyof api.ODGeneralJsonConfig_SystemPermissions) { + //return when not allowed because of missing messages + const {user,member,channel,guild} = instance + const generalConfig = opendiscord.configs.get("opendiscord:general") + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions[commandName],"support",user,member,channel,guild) + + if (!permsResult.hasPerms) throw new api.ODSystemError("Please check permissions before using replyMessageMustBeSentBeforeClose()") + if (!guild || channel.isDMBased()) throw new api.ODSystemError("replyMessageMustBeSentBeforeClose() must be used in a guild and not a DM channel.") + + if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ + const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) + if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) + return false + } + if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ + if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) + return false + } + return true + }else return true +} \ No newline at end of file diff --git a/src/builders/buttons.ts b/src/builders/buttons.ts index 77ed3a1..64272a8 100644 --- a/src/builders/buttons.ts +++ b/src/builders/buttons.ts @@ -8,8 +8,27 @@ const buttons = opendiscord.builders.buttons const lang = opendiscord.languages const generalConfig = opendiscord.configs.get("opendiscord:general") -export const registerAllButtons = async () => { - verifybarButtons() +export async function registerAllButtons(){ + //VERIFYBAR BUTTON + buttons.add(new api.ODButton("opendiscord:verifybar-button")) + buttons.get("opendiscord:verifybar-button").workers.add( + new api.ODWorker("opendiscord:verifybar-button",0,async (instance,params) => { + const {verifybar,verifyButtonId} = params + if (params.verifyButtonId.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-button => verifyButtonId '"+verifyButtonId+"' exceeds 40 characters limit!") + + const color = ("customColor" in params && params.customColor) ? params.customColor : "gray" + const label = ("customLabel" in params && params.customLabel) ? params.customLabel : null + const defaultEmoji = ("buttonStyle" in params && params.buttonStyle && params.buttonStyle == "✅") ? "✅" : "❌" + const emoji = ("customEmoji" in params && params.customEmoji) ? params.customEmoji : defaultEmoji + + instance.setCustomId("od:verifybar|"+verifybar.id.value+"|"+verifyButtonId) + instance.setMode("button") + instance.setColor(color) + if (label) instance.setLabel(label) + if (emoji) instance.setEmoji(emoji) + }) + ) + errorButtons() helpMenuButtons() panelButtons() @@ -18,50 +37,6 @@ export const registerAllButtons = async () => { clearButtons() } -const verifybarButtons = () => { - //VERIFYBAR SUCCESS - buttons.add(new api.ODButton("opendiscord:verifybar-success")) - buttons.get("opendiscord:verifybar-success").workers.add( - new api.ODWorker("opendiscord:verifybar-success",0,async (instance,params) => { - const {verifybar,customData,customColor,customLabel,customEmoji} = params - - if (customData && customData.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-success => customData exceeds 40 characters limit!") - - const newData = (customData) ? "_"+customData : "" - const newColor = customColor ?? "gray" - const newLabel = customLabel ?? "" - const newEmoji = customEmoji ?? "✅" - - instance.setCustomId("od:verifybar-success_"+verifybar.id.value+newData) - instance.setMode("button") - instance.setColor(newColor) - if (newLabel) instance.setLabel(newLabel) - if (newEmoji) instance.setEmoji(newEmoji) - }) - ) - - //VERIFYBAR FAILURE - buttons.add(new api.ODButton("opendiscord:verifybar-failure")) - buttons.get("opendiscord:verifybar-failure").workers.add( - new api.ODWorker("opendiscord:verifybar-failure",0,async (instance,params) => { - const {verifybar,customData,customColor,customLabel,customEmoji} = params - - if (customData && customData.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-success => customData exceeds 40 characters limit!") - - const newData = (customData) ? "_"+customData : "" - const newColor = customColor ?? "gray" - const newLabel = customLabel ?? "" - const newEmoji = customEmoji ?? "❌" - - instance.setCustomId("od:verifybar-failure_"+verifybar.id.value+newData) - instance.setMode("button") - instance.setColor(newColor) - if (newLabel) instance.setLabel(newLabel) - if (newEmoji) instance.setEmoji(newEmoji) - }) - ) -} - const errorButtons = () => { //ERROR TICKET DEPRECATED TRANSCRIPT buttons.add(new api.ODButton("opendiscord:error-ticket-deprecated-transcript")) @@ -205,7 +180,7 @@ const ticketButtons = () => { const {guild,channel,ticket} = params instance.setMode("button") - instance.setCustomId("od:close-ticket_"+origin) + instance.setCustomId("od:close-ticket") instance.setColor("gray") instance.setEmoji("🔒") instance.setLabel(lang.getTranslation("actions.buttons.close")) @@ -219,7 +194,7 @@ const ticketButtons = () => { const {guild,channel,ticket} = params instance.setMode("button") - instance.setCustomId("od:delete-ticket_"+origin) + instance.setCustomId("od:delete-ticket") instance.setColor("red") instance.setEmoji("✖") instance.setLabel(lang.getTranslation("actions.buttons.delete")) @@ -233,7 +208,7 @@ const ticketButtons = () => { const {guild,channel,ticket} = params instance.setMode("button") - instance.setCustomId("od:reopen-ticket_"+origin) + instance.setCustomId("od:reopen-ticket") instance.setColor("green") instance.setEmoji("🔓") instance.setLabel(lang.getTranslation("actions.buttons.reopen")) @@ -247,7 +222,7 @@ const ticketButtons = () => { const {guild,channel,ticket} = params instance.setMode("button") - instance.setCustomId("od:claim-ticket_"+origin) + instance.setCustomId("od:claim-ticket") instance.setColor("green") instance.setEmoji("👋") instance.setLabel(lang.getTranslation("actions.buttons.claim")) @@ -261,7 +236,7 @@ const ticketButtons = () => { const {guild,channel,ticket} = params instance.setMode("button") - instance.setCustomId("od:unclaim-ticket_"+origin) + instance.setCustomId("od:unclaim-ticket") instance.setColor("green") instance.setEmoji("↩️") instance.setLabel(lang.getTranslation("actions.buttons.unclaim")) @@ -275,7 +250,7 @@ const ticketButtons = () => { const {guild,channel,ticket} = params instance.setMode("button") - instance.setCustomId("od:pin-ticket_"+origin) + instance.setCustomId("od:pin-ticket") instance.setColor("gray") instance.setEmoji(generalConfig.data.system.pinEmoji) instance.setLabel(lang.getTranslation("actions.buttons.pin")) @@ -289,7 +264,7 @@ const ticketButtons = () => { const {guild,channel,ticket} = params instance.setMode("button") - instance.setCustomId("od:unpin-ticket_"+origin) + instance.setCustomId("od:unpin-ticket") instance.setColor("gray") instance.setEmoji(generalConfig.data.system.pinEmoji) instance.setLabel(lang.getTranslation("actions.buttons.unpin")) @@ -342,10 +317,11 @@ const clearButtons = () => { buttons.get("opendiscord:clear-continue").workers.add( new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,origin) => { instance.setMode("button") - instance.setCustomId("od:clear-continue_"+origin+"_"+params.filter) + instance.setCustomId("od:clear-continue") instance.setColor("red") instance.setEmoji("✖") instance.setLabel(lang.getTranslation("actions.buttons.clear")) + instance.setDisabled(params.inProgress) }) ) } \ No newline at end of file diff --git a/src/builders/messages.ts b/src/builders/messages.ts index 17417a6..0028578 100644 --- a/src/builders/messages.ts +++ b/src/builders/messages.ts @@ -13,7 +13,6 @@ const lang = opendiscord.languages const generalConfig = opendiscord.configs.get("opendiscord:general") export async function registerAllMessages(){ - verifyBarMessages() errorMessages() helpMenuMessages() statsMessages() @@ -27,307 +26,6 @@ export async function registerAllMessages(){ extraMessages() } -const verifyBarMessages = () => { - //VERIFYBAR TICKET MESSAGE - messages.add(new api.ODMessage("opendiscord:verifybar-ticket-message")) - messages.get("opendiscord:verifybar-ticket-message").workers.add( - new api.ODWorker("opendiscord:verifybar-ticket-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar} = params - if (!guild){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-ticket-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-ticket-message`") - return - } - const option = ticket.option - - //add pings - const pingOptions = option.get("opendiscord:ticket-message-ping").value - const pings: string[] = [] - const creator = ticket.get("opendiscord:opened-by").value - if (creator) pings.push(discord.userMention(creator)) - if (pingOptions["@everyone"]) pings.push("@everyone") - if (pingOptions["@here"]) pings.push("@here") - pingOptions.custom.forEach((ping) => pings.push(discord.roleMention(ping))) - const pingText = (pings.length > 0) ? pings.join(" ")+"\n" : "" - - //add text - const text = option.get("opendiscord:ticket-message-text").value - if (text !== "") instance.setContent(pingText+text) - else instance.setContent(pingText) - - //add embed - if (option.get("opendiscord:ticket-message-embed").value.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:claim-ticket-ticket-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:unclaim-ticket-ticket-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:pin-ticket-ticket-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:unpin-ticket-ticket-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:close-ticket-ticket-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:reopen-ticket-ticket-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:delete-ticket-ticket-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"})) - } - }) - ) - - //TICKET CLOSED - messages.add(new api.ODMessage("opendiscord:verifybar-close-message")) - messages.get("opendiscord:verifybar-close-message").workers.add( - new api.ODWorker("opendiscord:verifybar-close-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar,originalMessage} = params - if (!guild){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-close-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-close-message`") - return - } - - const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - //add embed - instance.addEmbed(await embeds.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:reopen-ticket-close-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:delete-ticket-close-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"})) - } - }) - ) - - //TICKET REOPENED - messages.add(new api.ODMessage("opendiscord:verifybar-reopen-message")) - messages.get("opendiscord:verifybar-reopen-message").workers.add( - new api.ODWorker("opendiscord:verifybar-reopen-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar,originalMessage} = params - if (!guild){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-reopen-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-reopen-message`") - return - } - - const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - //add embed - instance.addEmbed(await embeds.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:close-ticket-reopen-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:delete-ticket-reopen-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"})) - } - }) - ) - - //TICKET CLAIM - messages.add(new api.ODMessage("opendiscord:verifybar-claim-message")) - messages.get("opendiscord:verifybar-claim-message").workers.add( - new api.ODWorker("opendiscord:verifybar-claim-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar,originalMessage} = params - if (!guild){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-claim-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-claim-message`") - return - } - - const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - //add embed - instance.addEmbed(await embeds.getSafe("opendiscord:claim-message").build("other",{guild,channel,user,ticket,reason})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:unclaim-ticket-claim-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - } - }) - ) - - //TICKET UNCLAIM - messages.add(new api.ODMessage("opendiscord:verifybar-unclaim-message")) - messages.get("opendiscord:verifybar-unclaim-message").workers.add( - new api.ODWorker("opendiscord:verifybar-unclaim-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar,originalMessage} = params - if (!guild){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-unclaim-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-unclaim-message`") - return - } - - const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - //add embed - instance.addEmbed(await embeds.getSafe("opendiscord:unclaim-message").build("other",{guild,channel,user,ticket,reason})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:claim-ticket-unclaim-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - } - }) - ) - - //TICKET PIN - messages.add(new api.ODMessage("opendiscord:verifybar-pin-message")) - messages.get("opendiscord:verifybar-pin-message").workers.add( - new api.ODWorker("opendiscord:verifybar-pin-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar,originalMessage} = params - if (!guild){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-pin-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-pin-message`") - return - } - - const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - //add embed - instance.addEmbed(await embeds.getSafe("opendiscord:pin-message").build("other",{guild,channel,user,ticket,reason})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:unpin-ticket-pin-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - } - }) - ) - - //TICKET UNPIN - messages.add(new api.ODMessage("opendiscord:verifybar-unpin-message")) - messages.get("opendiscord:verifybar-unpin-message").workers.add( - new api.ODWorker("opendiscord:verifybar-unpin-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar,originalMessage} = params - if (!guild){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-unpin-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-unpin-message`") - return - } - - const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null - const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3) - - //add embed - instance.addEmbed(await embeds.getSafe("opendiscord:unpin-message").build("other",{guild,channel,user,ticket,reason})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:pin-ticket-unpin-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - } - }) - ) - - //TICKET AUTOCLOSED - messages.add(new api.ODMessage("opendiscord:verifybar-autoclose-message")) - messages.get("opendiscord:verifybar-autoclose-message").workers.add( - new api.ODWorker("opendiscord:verifybar-autoclose-message",0,async (instance,params,origin) => { - const {guild,channel,user,verifybar,originalMessage} = params - if (!guild || channel.isDMBased()){ - instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-autoclose-message`") - return - } - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket){ - instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-autoclose-message`") - return - } - - //add embed - instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket})) - - //add verifybar components - if (verifybar.id.value == "opendiscord:reopen-ticket-autoclose-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - - }else if (verifybar.id.value == "opendiscord:delete-ticket-autoclose-message"){ - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar})) - instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar})) - if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"})) - if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"})) - } - }) - ) -} - const errorMessages = () => { //ERROR messages.add(new api.ODMessage("opendiscord:error")) @@ -990,9 +688,9 @@ const clearMessages = () => { messages.add(new api.ODMessage("opendiscord:clear-verify-message")) messages.get("opendiscord:clear-verify-message").workers.add( new api.ODWorker("opendiscord:clear-verify-message",0,async (instance,params,origin) => { - const {guild,channel,user,filter,list} = params - instance.addEmbed(await embeds.getSafe("opendiscord:clear-verify-message").build(origin,{guild,channel,user,filter,list})) - instance.addComponent(await buttons.getSafe("opendiscord:clear-continue").build(origin,{guild,channel,user,filter,list})) + const {guild,channel,user,filter,list,inProgress} = params + instance.addEmbed(await embeds.getSafe("opendiscord:clear-verify-message").build(origin,{guild,channel,user,filter,list,inProgress})) + instance.addComponent(await buttons.getSafe("opendiscord:clear-continue").build(origin,{guild,channel,user,filter,list,inProgress})) instance.setEphemeral(true) }) ) diff --git a/src/builders/modals.ts b/src/builders/modals.ts index e06100c..b1c1e56 100644 --- a/src/builders/modals.ts +++ b/src/builders/modals.ts @@ -49,9 +49,9 @@ const ticketModals = () => { modals.add(new api.ODModal("opendiscord:close-ticket-reason")) modals.get("opendiscord:close-ticket-reason").workers.add( new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin) => { - const {ticket} = params + const {channel,message} = params - instance.setCustomId("od:close-ticket-reason_"+ticket.id.value+"_"+origin) + instance.setCustomId("od:close-ticket-reason|"+channel.id+"|"+message.id) instance.setTitle(lang.getTranslation("actions.buttons.close")) instance.addQuestion({ customId:"reason", @@ -67,9 +67,9 @@ const ticketModals = () => { modals.add(new api.ODModal("opendiscord:reopen-ticket-reason")) modals.get("opendiscord:reopen-ticket-reason").workers.add( new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin) => { - const {ticket} = params + const {channel,message} = params - instance.setCustomId("od:reopen-ticket-reason_"+ticket.id.value+"_"+origin) + instance.setCustomId("od:reopen-ticket-reason|"+channel.id+"|"+message.id) instance.setTitle(lang.getTranslation("actions.buttons.reopen")) instance.addQuestion({ customId:"reason", @@ -85,9 +85,9 @@ const ticketModals = () => { modals.add(new api.ODModal("opendiscord:delete-ticket-reason")) modals.get("opendiscord:delete-ticket-reason").workers.add( new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin) => { - const {ticket} = params + const {channel,message} = params - instance.setCustomId("od:delete-ticket-reason_"+ticket.id.value+"_"+origin) + instance.setCustomId("od:delete-ticket-reason|"+channel.id+"|"+message.id) instance.setTitle(lang.getTranslation("actions.buttons.delete")) instance.addQuestion({ customId:"reason", @@ -103,9 +103,9 @@ const ticketModals = () => { modals.add(new api.ODModal("opendiscord:claim-ticket-reason")) modals.get("opendiscord:claim-ticket-reason").workers.add( new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin) => { - const {ticket} = params + const {channel,message} = params - instance.setCustomId("od:claim-ticket-reason_"+ticket.id.value+"_"+origin) + instance.setCustomId("od:claim-ticket-reason|"+channel.id+"|"+message.id) instance.setTitle(lang.getTranslation("actions.buttons.claim")) instance.addQuestion({ customId:"reason", @@ -121,9 +121,9 @@ const ticketModals = () => { modals.add(new api.ODModal("opendiscord:unclaim-ticket-reason")) modals.get("opendiscord:unclaim-ticket-reason").workers.add( new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin) => { - const {ticket} = params + const {channel,message} = params - instance.setCustomId("od:unclaim-ticket-reason_"+ticket.id.value+"_"+origin) + instance.setCustomId("od:unclaim-ticket-reason|"+channel.id+"|"+message.id) instance.setTitle(lang.getTranslation("actions.buttons.unclaim")) instance.addQuestion({ customId:"reason", @@ -139,9 +139,9 @@ const ticketModals = () => { modals.add(new api.ODModal("opendiscord:pin-ticket-reason")) modals.get("opendiscord:pin-ticket-reason").workers.add( new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin) => { - const {ticket} = params + const {channel,message} = params - instance.setCustomId("od:pin-ticket-reason_"+ticket.id.value+"_"+origin) + instance.setCustomId("od:pin-ticket-reason|"+channel.id+"|"+message.id) instance.setTitle(lang.getTranslation("actions.buttons.pin")) instance.addQuestion({ customId:"reason", @@ -157,9 +157,9 @@ const ticketModals = () => { modals.add(new api.ODModal("opendiscord:unpin-ticket-reason")) modals.get("opendiscord:unpin-ticket-reason").workers.add( new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin) => { - const {ticket} = params + const {channel,message} = params - instance.setCustomId("od:unpin-ticket-reason_"+ticket.id.value+"_"+origin) + instance.setCustomId("od:unpin-ticket-reason|"+channel.id+"|"+message.id) instance.setTitle(lang.getTranslation("actions.buttons.unpin")) instance.addQuestion({ customId:"reason", diff --git a/src/commands/claim.ts b/src/commands/claim.ts index 80d5eb7..bec0392 100644 --- a/src/commands/claim.ts +++ b/src/commands/claim.ts @@ -3,8 +3,11 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerCommandResponders(){ //CLAIM COMMAND RESPONDER @@ -13,46 +16,36 @@ export async function registerCommandResponders(){ new api.ODWorker("opendiscord:claim",0,async (instance,params,origin,cancel) => { const {guild,channel,user,member} = instance - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.claim,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when already claimed - if (ticket.get("opendiscord:claimed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - const claimUser = instance.options.getUser("user",false) ?? user - const reason = instance.options.getString("reason",false) - + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"claim") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnclaimed = await actionUtils.replyTicketMustBeUnclaimed(instance,origin,ticket) + if (!isTicketUnclaimed) return cancel() + //start claiming ticket await instance.defer(false) + const reason = instance.options.getString("reason",false) + const claimUser = instance.options.getUser("user",false) ?? user await opendiscord.actions.get("opendiscord:claim-ticket").run(origin,{guild,channel,user:claimUser,ticket,reason,sendMessage:false}) - await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user:claimUser,ticket,reason})) + + //send message & set state + const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user:claimUser,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"claim-message", + messageOrigin:origin, + messageAuthor:claimUser.id, + messageReason:reason + },sentMsg.ephemeral) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { opendiscord.log(instance.user.displayName+" used the 'claim' command!","info",[ @@ -70,50 +63,174 @@ export async function registerButtonResponders(){ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:claim-ticket",/^od:claim-ticket/)) opendiscord.responders.buttons.get("opendiscord:claim-ticket").workers.add( new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin,cancel) => { - const originalOrigin = instance.interaction.customId.split("_")[1] as Exclude + const {guild,channel,user,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"claim") + if (!hasPerms) return cancel() - if (originalOrigin == "ticket-message") await opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").activate(instance) - else if (originalOrigin == "unclaim-message") await opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").activate(instance) - else await instance.defer("update",false) + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/claim") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnclaimed = await actionUtils.replyTicketMustBeUnclaimed(instance,origin,ticket) + if (!isTicketUnclaimed) return cancel() + + //fetch state details + const verifybar = opendiscord.verifybars.get("opendiscord:claim-ticket") + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //send verifybar + if (generalConfig.data.system.disableVerifyBars){ + //verifybar disabled, directly run response + await verifybar.activate(instance,"accept") + + }else if (originalMsgType == "ticket-message"){ + //ticket message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:claim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "unclaim-message"){ + //unclaim message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:claim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:unclaim-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } }) ) } +export async function registerVerifyBars(){ + //CLAIM TICKET + opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket")) + opendiscord.verifybars.get("opendiscord:claim-ticket").workers.add([ + new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin,cancel) => { + const {user,member,channel,guild,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"claim") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/claim") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnclaimed = await actionUtils.replyTicketMustBeUnclaimed(instance,origin,ticket) + if (!isTicketUnclaimed) return cancel() + + //fetch state details + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //start claiming ticket + if (params.selectedButtonId == "cancel"){ + //CANCEL + if (originalMsgType == "ticket-message"){ + //ticket message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "unclaim-message"){ + //unclaim message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } + }else if (params.selectedButtonId == "accept"){ + //CLAIM TICKET + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "unclaim-message"){ + //converted to claim message + await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("verifybar",{guild,channel,user,ticket,reason:null})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"claim-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:null + },sentMsg.ephemeral) + } + }else if (params.selectedButtonId == "accept-with-reason"){ + //CLAIM WITH REASON (MODAL) + instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("other",{guild,channel,user,ticket,message})) + } + }) + ]) +} + export async function registerModalResponders(){ //CLAIM WITH REASON MODAL RESPONDER - opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:claim-ticket-reason",/^od:claim-ticket-reason_/)) + opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:claim-ticket-reason",/^od:claim-ticket-reason\|([^|]+)\|([^|]+)/)) opendiscord.responders.modals.get("opendiscord:claim-ticket-reason").workers.add([ new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!channel) return - if (!guild){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user:instance.user})) - return cancel() - } - const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1]) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return - } - - const originalOrigin = instance.interaction.customId.split("_")[2] as Exclude - const reason = instance.values.getTextField("reason",true) - - //claim with reason - if (originalOrigin == "ticket-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:claim-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }else if (originalOrigin == "unclaim-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:claim-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("other",{guild,channel,user,ticket,reason})) - }else{ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:claim-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - } + const {guild,user} = instance + const match = /^od:claim-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const channel = await opendiscord.client.fetchTextChannel(match[1]) + const message = await opendiscord.client.fetchChannelMessage(match[1],match[2]) + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"claim") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/claim") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnclaimed = await actionUtils.replyTicketMustBeUnclaimed(instance,origin,ticket) + if (!isTicketUnclaimed) return cancel() + + //fetch state details + const reason = instance.values.getTextField("reason",true) + const originalMsgOrigin = state.data.messageOrigin + const originalMsgType = state.data.messageType + + //start claiming ticket + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) + + }else if (originalMsgType == "unclaim-message"){ + //converted to claim message + await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"claim-message", + messageOrigin:originalMsgOrigin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) + } }) ]) } \ No newline at end of file diff --git a/src/commands/clear.ts b/src/commands/clear.ts index 89dc97d..891b21d 100644 --- a/src/commands/clear.ts +++ b/src/commands/clear.ts @@ -3,8 +3,10 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const clearMsgState = opendiscord.states.get("opendiscord:clear-message") export async function registerCommandResponders(){ //CLEAR COMMAND RESPONDER @@ -29,7 +31,7 @@ export async function registerCommandResponders(){ const tempFilter = instance.options.getString("filter",false) const filter = (tempFilter) ? tempFilter.toLowerCase() as api.ODTicketClearFilter : "all" - const list: string[] = [] + const channelNameList: string[] = [] const ticketList = opendiscord.tickets.getAll().filter((ticket) => { if (filter == "all") return true else if (filter == "open" && ticket.get("opendiscord:open").value) return true @@ -43,12 +45,17 @@ export async function registerCommandResponders(){ }) for (const ticket of ticketList){ const ticketChannel = await opendiscord.tickets.getTicketChannel(ticket) - if (ticketChannel) list.push("#"+ticketChannel.name) + if (ticketChannel) channelNameList.push("#"+ticketChannel.name) } //reply with clear verify await instance.defer(true) - await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:clear-verify-message").build(origin,{guild,channel,user,filter,list})) + const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:clear-verify-message").build(origin,{guild,channel,user,filter,list:channelNameList,inProgress:false})) + if (sentMsg.success) await clearMsgState.setMsgState({channel,message:sentMsg.message,user},{ + messageOrigin:origin, + clearFilter:filter, + clearChannelNameList:channelNameList + },sentMsg.ephemeral) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { opendiscord.log(instance.user.displayName+" used the 'clear' command!","info",[ @@ -63,26 +70,45 @@ export async function registerCommandResponders(){ export async function registerButtonResponders(){ //CLEAR CONTINUE BUTTON RESPONDER - opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:clear-continue",/^od:clear-continue_/)) + opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:clear-continue","od:clear-continue")) opendiscord.responders.buttons.get("opendiscord:clear-continue").workers.add( new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!guild || channel.isDMBased()) return - const originalOrigin = instance.interaction.customId.split("_")[1] as api.ODActionManagerIdMappings["opendiscord:clear-tickets"]["origin"] - const filter = instance.interaction.customId.split("_")[2] as api.ODTicketClearFilter + const {guild,channel,user,message} = instance + + //check message state + const state = await clearMsgState.getMsgState({channel,message,user}) + if (!state){ + //TODO TRANSLATION!!! + await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This interaction is no longer valid or has expired. Use the command `{0}` instead. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/clear"),layout:"simple",customTitle:"Message State Expired"})) + return cancel() + } + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"clear") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() + + //fetch state details + const originalUser = ((state.userId) ? await opendiscord.client.fetchUser(state.userId) : user) ?? user + const originalOrigin = state.data.messageOrigin + const originalClearFilter = state.data.clearFilter + const originalClearChannelNameList = state.data.clearChannelNameList //start ticket clear - await instance.defer("update",true) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:clear-verify-message").build(originalOrigin,{guild,channel,user:originalUser,filter:originalClearFilter,list:originalClearChannelNameList,inProgress:true})) + const list: string[] = [] const ticketList = opendiscord.tickets.getAll().filter((ticket) => { - if (filter == "all") return true - else if (filter == "open" && ticket.get("opendiscord:open").value) return true - else if (filter == "closed" && ticket.get("opendiscord:closed").value) return true - else if (filter == "claimed" && ticket.get("opendiscord:claimed").value) return true - else if (filter == "pinned" && ticket.get("opendiscord:pinned").value) return true - else if (filter == "unclaimed" && !ticket.get("opendiscord:claimed").value) return true - else if (filter == "unpinned" && !ticket.get("opendiscord:pinned").value) return true - else if (filter == "autoclosed" && ticket.get("opendiscord:closed").value) return true + if (originalClearFilter == "all") return true + else if (originalClearFilter == "open" && ticket.get("opendiscord:open").value) return true + else if (originalClearFilter == "closed" && ticket.get("opendiscord:closed").value) return true + else if (originalClearFilter == "claimed" && ticket.get("opendiscord:claimed").value) return true + else if (originalClearFilter == "pinned" && ticket.get("opendiscord:pinned").value) return true + else if (originalClearFilter == "unclaimed" && !ticket.get("opendiscord:claimed").value) return true + else if (originalClearFilter == "unpinned" && !ticket.get("opendiscord:pinned").value) return true + else if (originalClearFilter == "autoclosed" && ticket.get("opendiscord:closed").value) return true else return false }) for (const ticket of ticketList){ @@ -90,8 +116,8 @@ export async function registerButtonResponders(){ if (ticketChannel) list.push("#"+ticketChannel.name) } - await opendiscord.actions.get("opendiscord:clear-tickets").run(originalOrigin,{guild,channel,user,filter,list:ticketList}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:clear-message").build(originalOrigin,{guild,channel,user,filter,list})) + await opendiscord.actions.get("opendiscord:clear-tickets").run(originalOrigin,{guild,channel,user,filter:originalClearFilter,list:ticketList}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:clear-message").build(originalOrigin,{guild,channel,user,filter:originalClearFilter,list})) }) ) } \ No newline at end of file diff --git a/src/commands/close.ts b/src/commands/close.ts index 670f468..8263062 100644 --- a/src/commands/close.ts +++ b/src/commands/close.ts @@ -3,9 +3,11 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerCommandResponders(){ //CLOSE COMMAND RESPONDER @@ -14,57 +16,38 @@ export async function registerCommandResponders(){ new api.ODWorker("opendiscord:close",0,async (instance,params,origin,cancel) => { const {user,member,channel,guild} = instance - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when already closed - if (ticket.get("opendiscord:closed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"close") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketOpen = await actionUtils.replyTicketMustBeOpen(instance,origin,ticket) + if (!isTicketOpen) return cancel() + + const messagesHaveBeenSent = await actionUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"close") + if (!messagesHaveBeenSent) return cancel() //start closing ticket await instance.defer(false) const reason = instance.options.getString("reason",false) await opendiscord.actions.get("opendiscord:close-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason})) + + //send message & set state + const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"close-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { opendiscord.log(instance.user.displayName+" used the 'close' command!","info",[ @@ -77,55 +60,185 @@ export async function registerCommandResponders(){ ]) } -export const registerButtonResponders = async () => { +export async function registerButtonResponders(){ //CLOSE TICKET BUTTON RESPONDER - opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:close-ticket",/^od:close-ticket_/)) + opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:close-ticket",/^od:close-ticket/)) opendiscord.responders.buttons.get("opendiscord:close-ticket").workers.add( new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin,cancel) => { - const originalOrigin = instance.interaction.customId.split("_")[1] as Exclude + const {guild,channel,message,user,member} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"close") + if (!hasPerms) return cancel() - if (originalOrigin == "ticket-message") await opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").activate(instance) - else if (originalOrigin == "reopen-message") await opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").activate(instance) - else await instance.defer("update",false) + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/close") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketOpen = await actionUtils.replyTicketMustBeOpen(instance,origin,ticket) + if (!isTicketOpen) return cancel() + + const messagesHaveBeenSent = await actionUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"close") + if (!messagesHaveBeenSent) return cancel() + + //fetch state details + const verifybar = opendiscord.verifybars.get("opendiscord:close-ticket") + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //send verifybar + if (generalConfig.data.system.disableVerifyBars){ + //verifybar disabled, directly run response + await verifybar.activate(instance,"accept") + + }else if (originalMsgType == "ticket-message"){ + //ticket message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:close-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "reopen-message"){ + //reopen message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:close-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:reopen-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } }) ) } +export async function registerVerifyBars(){ + //CLOSE TICKET VERIFYBAR + opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket")) + opendiscord.verifybars.get("opendiscord:close-ticket").workers.add([ + new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin,cancel) => { + const {user,member,channel,guild,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"close") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/close") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketOpen = await actionUtils.replyTicketMustBeOpen(instance,origin,ticket) + if (!isTicketOpen) return cancel() + + const messagesHaveBeenSent = await actionUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"close") + if (!messagesHaveBeenSent) return cancel() + + //fetch state details + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //start closing ticket + if (params.selectedButtonId == "cancel"){ + //CANCEL + if (originalMsgType == "ticket-message"){ + //ticket message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "reopen-message"){ + //reopen message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } + }else if (params.selectedButtonId == "accept"){ + //CLOSE TICKET + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "reopen-message"){ + //converted to close message + await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("verifybar",{guild,channel,user,ticket,reason:null})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"close-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:null + },sentMsg.ephemeral) + } + }else if (params.selectedButtonId == "accept-with-reason"){ + //CLOSE WITH REASON (MODAL) + instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("other",{guild,channel,user,ticket,message})) + } + }) + ]) +} + export async function registerModalResponders(){ //CLOSE WITH REASON MODAL RESPONDER - opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:close-ticket-reason",/^od:close-ticket-reason_/)) + opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:close-ticket-reason",/^od:close-ticket-reason\|([^|]+)\|([^|]+)/)) opendiscord.responders.modals.get("opendiscord:close-ticket-reason").workers.add([ new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!channel) return - if (!guild){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user:instance.user})) - return cancel() - } - const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1]) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return - } + const {guild,user} = instance - const originalOrigin = instance.interaction.customId.split("_")[2] as Exclude - const reason = instance.values.getTextField("reason",true) - - //close with reason - if (originalOrigin == "ticket-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:close-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }else if (originalOrigin == "reopen-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:close-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason})) - }else{ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:close-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - } + const match = /^od:close-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const channel = await opendiscord.client.fetchTextChannel(match[1]) + const message = await opendiscord.client.fetchChannelMessage(match[1],match[2]) + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"close") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/close") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketOpen = await actionUtils.replyTicketMustBeOpen(instance,origin,ticket) + if (!isTicketOpen) return cancel() + + //fetch state details + const reason = instance.values.getTextField("reason",true) + const originalMsgOrigin = state.data.messageOrigin + const originalMsgType = state.data.messageType + + //start closing ticket + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) + + }else if (originalMsgType == "reopen-message"){ + //converted to close message + await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"close-message", + messageOrigin:originalMsgOrigin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) + } }) ]) } \ No newline at end of file diff --git a/src/commands/delete.ts b/src/commands/delete.ts index 5278534..4a32cdc 100644 --- a/src/commands/delete.ts +++ b/src/commands/delete.ts @@ -3,9 +3,11 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerCommandResponders(){ //DELETE COMMAND RESPONDER @@ -14,50 +16,27 @@ export async function registerCommandResponders(){ new api.ODWorker("opendiscord:delete",0,async (instance,params,origin,cancel) => { const {user,member,channel,guild} = instance - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"delete") + if (!hasPerms) return cancel() - //return when not allowed because of missing messages - if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ - const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel) - if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")})) - return cancel() - } - } + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketOpen = await actionUtils.replyTicketMustBeOpen(instance,origin,ticket) + if (!isTicketOpen) return cancel() - const reason = instance.options.getString("reason",false) - const withoutTranscript = instance.options.getBoolean("notranscript",false) ?? false + const messagesHaveBeenSent = await actionUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"delete") + if (!messagesHaveBeenSent) return cancel() //don't allow deleteWithoutTranscript to non-global-admins when enabled + const withoutTranscript = instance.options.getBoolean("notranscript",false) ?? false if (withoutTranscript && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) @@ -67,6 +46,7 @@ export async function registerCommandResponders(){ //start deleting ticket await instance.defer(false) + const reason = instance.options.getString("reason",false) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(origin,{guild,channel,user,ticket,reason})) await opendiscord.actions.get("opendiscord:delete-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript}) }), @@ -86,65 +66,207 @@ export async function registerButtonResponders(){ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:delete-ticket",/^od:delete-ticket/)) opendiscord.responders.buttons.get("opendiscord:delete-ticket").workers.add( new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => { - const originalOrigin = instance.interaction.customId.split("_")[1] as Exclude + const {guild,channel,message,user,member} = instance - if (originalOrigin == "ticket-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").activate(instance) - else if (originalOrigin == "close-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").activate(instance) - else if (originalOrigin == "reopen-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").activate(instance) - else if (originalOrigin == "autoclose-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").activate(instance) - else await instance.defer("update",false) + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"delete") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/delete") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const messagesHaveBeenSent = await actionUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"delete") + if (!messagesHaveBeenSent) return cancel() + + //fetch state details + const verifybar = opendiscord.verifybars.get("opendiscord:delete-ticket") + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //send verifybar + if (generalConfig.data.system.disableVerifyBars){ + //verifybar disabled, directly run response + await verifybar.activate(instance,"accept") + + }else if (originalMsgType == "ticket-message"){ + //ticket message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "close-message"){ + //close message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:close-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + }else if (originalMsgType == "reopen-message"){ + //reopen message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:reopen-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + }else if (originalMsgType == "autoclose-message"){ + //autoclose message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:autoclose-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket})) + } }) ) } +export async function registerVerifyBars(){ + //DELETE TICKET + opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket")) + opendiscord.verifybars.get("opendiscord:delete-ticket").workers.add([ + new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => { + const {user,member,channel,guild,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"delete") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/delete") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const messagesHaveBeenSent = await actionUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"delete") + if (!messagesHaveBeenSent) return cancel() + + //don't allow deleteWithoutTranscript to non-global-admins when enabled + const withoutTranscript = (params.selectedButtonId == "accept-without-transcript") + if (withoutTranscript && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ + if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){ + instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) + return cancel() + } + } + + //fetch state details + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //start deleting ticket + if (params.selectedButtonId == "cancel"){ + //CANCEL + if (originalMsgType == "ticket-message"){ + //ticket message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "close-message"){ + //close message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + }else if (originalMsgType == "reopen-message"){ + //reopen message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + }else if (originalMsgType == "autoclose-message"){ + //autoclose message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("verifybar",{guild,channel,user:originalUser,ticket})) + } + }else if (params.selectedButtonId == "accept" || params.selectedButtonId == "accept-without-transcript"){ + //DELETE TICKET + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true,withoutTranscript}) + ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) + + }else if (originalMsgType == "close-message"){ + //converted to delete message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason:null})) + + }else if (originalMsgType == "reopen-message"){ + //converted to delete message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason:null})) + + }else if (originalMsgType == "autoclose-message"){ + //converted to delete message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason:null})) + + } + }else if (params.selectedButtonId == "accept-with-reason"){ + //DELETE WITH REASON (MODAL) + instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("other",{guild,channel,user,ticket,message})) + } + }) + ]) +} + export async function registerModalResponders(){ - //REOPEN WITH REASON MODAL RESPONDER - opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:delete-ticket-reason",/^od:delete-ticket-reason_/)) + //DELETE WITH REASON MODAL RESPONDER + opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:delete-ticket-reason",/^od:delete-ticket-reason\|([^|]+)\|([^|]+)/)) opendiscord.responders.modals.get("opendiscord:delete-ticket-reason").workers.add([ new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!channel) return - if (!guild){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user:instance.user})) - return cancel() - } - const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1]) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return - } + const {guild,user} = instance - const originalOrigin = instance.interaction.customId.split("_")[2] as Exclude + const match = /^od:delete-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const channel = await opendiscord.client.fetchTextChannel(match[1]) + const message = await opendiscord.client.fetchChannelMessage(match[1],match[2]) + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"delete") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/delete") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + //fetch state details const reason = instance.values.getTextField("reason",true) + const originalMsgOrigin = state.data.messageOrigin + const originalMsgType = state.data.messageType - //delete with reason - if (originalOrigin == "ticket-message"){ - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true,withoutTranscript:false}) - //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable - ticket.get("opendiscord:for-deletion").value = true + //start deleting ticket + //don't await DELETE action => else it will update the message after the channel has been deleted + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:true,withoutTranscript:false}) + ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }else if (originalOrigin == "close-message"){ - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason})) - }else if (originalOrigin == "reopen-message"){ - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason})) - }else if (originalOrigin == "autoclose-message"){ - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason})) - }else{ - await instance.defer("update",false) - //don't await DELETE action => else it will update the message after the channel has been deleted - opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true,withoutTranscript:false}) + + }else if (originalMsgType == "close-message"){ + //converted to delete message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + + }else if (originalMsgType == "reopen-message"){ + //converted to delete message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + + }else if (originalMsgType == "autoclose-message"){ + //converted to delete message + opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + } }) ]) diff --git a/src/commands/pin.ts b/src/commands/pin.ts index beb10c2..2b076aa 100644 --- a/src/commands/pin.ts +++ b/src/commands/pin.ts @@ -3,88 +3,48 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerCommandResponders(){ //PIN COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:pin",generalConfig.data.prefix,"pin")) opendiscord.responders.commands.get("opendiscord:pin").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,origin,cancel) => { - const permissionMode = generalConfig.data.system.permissions.pin - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:pin",0,async (instance,params,origin,cancel) => { const {guild,channel,user,member} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.pin,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) - return cancel() - } - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when already pinned - if (ticket.get("opendiscord:pinned").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"})) - return cancel() - } + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"pin") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnpinned = await actionUtils.replyTicketMustBeUnpinned(instance,origin,ticket) + if (!isTicketUnpinned) return cancel() - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - const reason = instance.options.getString("reason",false) - //start pinning ticket await instance.defer(false) + const reason = instance.options.getString("reason",false) await opendiscord.actions.get("opendiscord:pin-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason})) + + //send message & set state + const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"pin-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { opendiscord.log(instance.user.displayName+" used the 'pin' command!","info",[ @@ -102,50 +62,175 @@ export async function registerButtonResponders(){ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:pin-ticket",/^od:pin-ticket/)) opendiscord.responders.buttons.get("opendiscord:pin-ticket").workers.add( new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin,cancel) => { - const originalOrigin = instance.interaction.customId.split("_")[1] as Exclude + const {guild,channel,user,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"pin") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() - if (originalOrigin == "ticket-message") await opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").activate(instance) - else if (originalOrigin == "unpin-message") await opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").activate(instance) - else await instance.defer("update",false) + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/pin") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnpinned = await actionUtils.replyTicketMustBeUnpinned(instance,origin,ticket) + if (!isTicketUnpinned) return cancel() + + //fetch state details + const verifybar = opendiscord.verifybars.get("opendiscord:pin-ticket") + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //send verifybar + if (generalConfig.data.system.disableVerifyBars){ + //verifybar disabled, directly run response + await verifybar.activate(instance,"accept") + + }else if (originalMsgType == "ticket-message"){ + //ticket message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:pin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "unpin-message"){ + //unpin message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:pin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:unpin-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } }) ) } + +export async function registerVerifyBars(){ + //PIN TICKET + opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket")) + opendiscord.verifybars.get("opendiscord:pin-ticket").workers.add([ + new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin,cancel) => { + const {user,member,channel,guild,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"pin") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/pin") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnpinned = await actionUtils.replyTicketMustBeUnpinned(instance,origin,ticket) + if (!isTicketUnpinned) return cancel() + + //fetch state details + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //start pinning ticket + if (params.selectedButtonId == "cancel"){ + //CANCEL + if (originalMsgType == "ticket-message"){ + //ticket message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "unpin-message"){ + //unpin message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } + }else if (params.selectedButtonId == "accept"){ + //PIN TICKET + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "unpin-message"){ + //converted to pin message + await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("verifybar",{guild,channel,user,ticket,reason:null})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"pin-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:null + },sentMsg.ephemeral) + } + }else if (params.selectedButtonId == "accept-with-reason"){ + //PIN WITH REASON (MODAL) + instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("other",{guild,channel,user,ticket,message})) + } + }) + ]) +} + export async function registerModalResponders(){ //PIN WITH REASON MODAL RESPONDER - opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:pin-ticket-reason",/^od:pin-ticket-reason_/)) + opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:pin-ticket-reason",/^od:pin-ticket-reason\|([^|]+)\|([^|]+)/)) opendiscord.responders.modals.get("opendiscord:pin-ticket-reason").workers.add([ new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!channel) return - if (!guild){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user:instance.user})) - return cancel() - } - const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1]) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return - } - - const originalOrigin = instance.interaction.customId.split("_")[2] as Exclude - const reason = instance.values.getTextField("reason",true) - - //pin with reason - if (originalOrigin == "ticket-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:pin-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }else if (originalOrigin == "unpin-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:pin-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("other",{guild,channel,user,ticket,reason})) - }else{ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:pin-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - } + const {guild,user} = instance + + const match = /^od:pin-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const channel = await opendiscord.client.fetchTextChannel(match[1]) + const message = await opendiscord.client.fetchChannelMessage(match[1],match[2]) + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"pin") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/pin") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketUnpinned = await actionUtils.replyTicketMustBeUnpinned(instance,origin,ticket) + if (!isTicketUnpinned) return cancel() + + //fetch state details + const reason = instance.values.getTextField("reason",true) + const originalMsgOrigin = state.data.messageOrigin + const originalMsgType = state.data.messageType + + //start pinning ticket + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) + + }else if (originalMsgType == "unpin-message"){ + //converted to pin message + await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"pin-message", + messageOrigin:originalMsgOrigin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) + } }) ]) } \ No newline at end of file diff --git a/src/commands/reopen.ts b/src/commands/reopen.ts index a622ac0..2b1fe59 100644 --- a/src/commands/reopen.ts +++ b/src/commands/reopen.ts @@ -3,8 +3,11 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerCommandResponders(){ //REOPEN COMMAND RESPONDER @@ -13,45 +16,35 @@ export async function registerCommandResponders(){ new api.ODWorker("opendiscord:reopen",0,async (instance,params,origin,cancel) => { const {guild,channel,user,member} = instance - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.reopen,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when not closed - if (!ticket.get("opendiscord:closed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - const reason = instance.options.getString("reason",false) + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"reopen") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClosed = await actionUtils.replyTicketMustBeClosed(instance,origin,ticket) + if (!isTicketClosed) return cancel() //start reopening ticket await instance.defer(false) + const reason = instance.options.getString("reason",false) await opendiscord.actions.get("opendiscord:reopen-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason})) + + //send message & set state + const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"reopen-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { opendiscord.log(instance.user.displayName+" used the 'reopen' command!","info",[ @@ -69,55 +62,201 @@ export async function registerButtonResponders(){ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:reopen-ticket",/^od:reopen-ticket/)) opendiscord.responders.buttons.get("opendiscord:reopen-ticket").workers.add( new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin,cancel) => { - const originalOrigin = instance.interaction.customId.split("_")[1] as Exclude + const {guild,channel,message,user,member} = instance - if (originalOrigin == "ticket-message") await opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").activate(instance) - else if (originalOrigin == "close-message") await opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").activate(instance) - else if (originalOrigin == "autoclose-message") await opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").activate(instance) - else await instance.defer("update",false) + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"reopen") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/reopen") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClosed = await actionUtils.replyTicketMustBeClosed(instance,origin,ticket) + if (!isTicketClosed) return cancel() + + //fetch state details + const verifybar = opendiscord.verifybars.get("opendiscord:reopen-ticket") + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //send verifybar + if (generalConfig.data.system.disableVerifyBars){ + //verifybar disabled, directly run response + await verifybar.activate(instance,"accept") + + }else if (originalMsgType == "ticket-message"){ + //ticket message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:reopen-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "close-message"){ + //close message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:reopen-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:close-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + }else if (originalMsgType == "autoclose-message"){ + //autoclose message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:reopen-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:autoclose-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket})) + } }) ) } +export async function registerVerifyBars(){ + //REOPEN TICKET + opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket")) + opendiscord.verifybars.get("opendiscord:reopen-ticket").workers.add([ + new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin,cancel) => { + const {user,member,channel,guild,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"reopen") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/reopen") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClosed = await actionUtils.replyTicketMustBeClosed(instance,origin,ticket) + if (!isTicketClosed) return cancel() + + //fetch state details + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //start reopening ticket + if (params.selectedButtonId == "cancel"){ + //CANCEL + if (originalMsgType == "ticket-message"){ + //ticket message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "close-message"){ + //close message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + }else if (originalMsgType == "autoclose-message"){ + //autoclose message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("verifybar",{guild,channel,user:originalUser,ticket})) + } + }else if (params.selectedButtonId == "accept"){ + //REOPEN TICKET + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "close-message"){ + //converted to reopen message + await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user,ticket,reason:null})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"reopen-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:null + },sentMsg.ephemeral) + }else if (originalMsgType == "autoclose-message"){ + //converted to reopen message + await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user,ticket,reason:null})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"reopen-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:null + },sentMsg.ephemeral) + } + }else if (params.selectedButtonId == "accept-with-reason"){ + //REOPEN WITH REASON (MODAL) + instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("other",{guild,channel,user,ticket,message})) + } + }) + ]) +} + export async function registerModalResponders(){ //REOPEN WITH REASON MODAL RESPONDER - opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:reopen-ticket-reason",/^od:reopen-ticket-reason_/)) + opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:reopen-ticket-reason",/^od:reopen-ticket-reason\|([^|]+)\|([^|]+)/)) opendiscord.responders.modals.get("opendiscord:reopen-ticket-reason").workers.add([ new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!channel) return - if (!guild){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user:instance.user})) - return cancel() - } - const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1]) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return - } + const {guild,user} = instance - const originalOrigin = instance.interaction.customId.split("_")[2] as Exclude - const reason = instance.values.getTextField("reason",true) - - //reopen with reason - if (originalOrigin == "ticket-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }else if (originalOrigin == "close-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason})) - }else if (originalOrigin == "autoclose-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason})) - }else{ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) - } + const match = /^od:reopen-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const channel = await opendiscord.client.fetchTextChannel(match[1]) + const message = await opendiscord.client.fetchChannelMessage(match[1],match[2]) + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"reopen") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/reopen") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClosed = await actionUtils.replyTicketMustBeClosed(instance,origin,ticket) + if (!isTicketClosed) return cancel() + + //fetch state details + const reason = instance.values.getTextField("reason",true) + const originalMsgOrigin = state.data.messageOrigin + const originalMsgType = state.data.messageType + + //start reopening ticket + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) + + }else if (originalMsgType == "close-message"){ + //converted to reopen message + await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"reopen-message", + messageOrigin:originalMsgOrigin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) + }else if (originalMsgType == "autoclose-message"){ + //converted to reopen message + await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"reopen-message", + messageOrigin:originalMsgOrigin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) + } }) ]) } \ No newline at end of file diff --git a/src/commands/unclaim.ts b/src/commands/unclaim.ts index 4c40f34..729c189 100644 --- a/src/commands/unclaim.ts +++ b/src/commands/unclaim.ts @@ -3,8 +3,11 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerCommandResponders(){ //UNCLAIM COMMAND RESPONDER @@ -13,45 +16,35 @@ export async function registerCommandResponders(){ new api.ODWorker("opendiscord:unclaim",0,async (instance,params,origin,cancel) => { const {user,member,channel,guild} = instance - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.unclaim,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/Server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when not claimed - if (!ticket.get("opendiscord:claimed").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"})) - return cancel() - } - - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - const reason = instance.options.getString("reason",false) - + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unclaim") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClaimed = await actionUtils.replyTicketMustBeClaimed(instance,origin,ticket) + if (!isTicketClaimed) return cancel() + //start unclaiming ticket await instance.defer(false) + const reason = instance.options.getString("reason",false) await opendiscord.actions.get("opendiscord:unclaim-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason})) + + //send message & set state + const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"unclaim-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { opendiscord.log(instance.user.displayName+" used the 'unclaim' command!","info",[ @@ -69,48 +62,173 @@ export async function registerButtonResponders(){ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:unclaim-ticket",/^od:unclaim-ticket/)) opendiscord.responders.buttons.get("opendiscord:unclaim-ticket").workers.add( new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin,cancel) => { - const originalOrigin = instance.interaction.customId.split("_")[1] as Exclude + const {guild,channel,user,message} = instance - if (originalOrigin == "ticket-message") await opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").activate(instance) - else if (originalOrigin == "claim-message") await opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").activate(instance) - else await instance.defer("update",false) + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unclaim") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unclaim") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClaimed = await actionUtils.replyTicketMustBeClaimed(instance,origin,ticket) + if (!isTicketClaimed) return cancel() + + //fetch state details + const verifybar = opendiscord.verifybars.get("opendiscord:unclaim-ticket") + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //send verifybar + if (generalConfig.data.system.disableVerifyBars){ + //verifybar disabled, directly run response + await verifybar.activate(instance,"accept") + + }else if (originalMsgType == "ticket-message"){ + //ticket message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unclaim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "claim-message"){ + //claim message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unclaim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:claim-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } }) ) } +export async function registerVerifyBars(){ + //UNCLAIM TICKET + opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket")) + opendiscord.verifybars.get("opendiscord:unclaim-ticket").workers.add([ + new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin,cancel) => { + const {user,member,channel,guild,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unclaim") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unclaim") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClaimed = await actionUtils.replyTicketMustBeClaimed(instance,origin,ticket) + if (!isTicketClaimed) return cancel() + + //fetch state details + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //start unclaiming ticket + if (params.selectedButtonId == "cancel"){ + //CANCEL + if (originalMsgType == "ticket-message"){ + //ticket message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "claim-message"){ + //claim message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } + }else if (params.selectedButtonId == "accept"){ + //UNCLAIM TICKET + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "claim-message"){ + //converted to unclaim message + await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("verifybar",{guild,channel,user,ticket,reason:null})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"unclaim-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:null + },sentMsg.ephemeral) + } + }else if (params.selectedButtonId == "accept-with-reason"){ + //UNCLAIM WITH REASON (MODAL) + instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("other",{guild,channel,user,ticket,message})) + } + }) + ]) +} + export async function registerModalResponders(){ //UNCLAIM WITH REASON MODAL RESPONDER - opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unclaim-ticket-reason",/^od:unclaim-ticket-reason_/)) + opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unclaim-ticket-reason",/^od:unclaim-ticket-reason\|([^|]+)\|([^|]+)/)) opendiscord.responders.modals.get("opendiscord:unclaim-ticket-reason").workers.add([ new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!channel) return - if (!guild){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user:instance.user})) - return cancel() - } - const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1]) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return - } + const {guild,user} = instance + + const match = /^od:unclaim-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const channel = await opendiscord.client.fetchTextChannel(match[1]) + const message = await opendiscord.client.fetchChannelMessage(match[1],match[2]) + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unclaim") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() - const originalOrigin = instance.interaction.customId.split("_")[2] as Exclude + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unclaim") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketClaimed = await actionUtils.replyTicketMustBeClaimed(instance,origin,ticket) + if (!isTicketClaimed) return cancel() + + //fetch state details const reason = instance.values.getTextField("reason",true) + const originalMsgOrigin = state.data.messageOrigin + const originalMsgType = state.data.messageType - //unclaim with reason - if (originalOrigin == "ticket-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) + //start claiming ticket + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }else if (originalOrigin == "claim-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("other",{guild,channel,user,ticket,reason})) - }else{ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) + + }else if (originalMsgType == "claim-message"){ + //converted to unclaim message + await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"unclaim-message", + messageOrigin:originalMsgOrigin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) } }) ]) diff --git a/src/commands/unpin.ts b/src/commands/unpin.ts index 855dd06..cfeb4ea 100644 --- a/src/commands/unpin.ts +++ b/src/commands/unpin.ts @@ -3,8 +3,11 @@ /////////////////////////////////////// import {opendiscord, api, utilities} from "../index.js" import * as discord from "discord.js" +import * as actionUtils from "../actions/utilities.js" const generalConfig = opendiscord.configs.get("opendiscord:general") +const lang = opendiscord.languages +const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") export async function registerCommandResponders(){ //UNPIN COMMAND RESPONDER @@ -12,46 +15,36 @@ export async function registerCommandResponders(){ opendiscord.responders.commands.get("opendiscord:unpin").workers.add([ new api.ODWorker("opendiscord:unpin",0,async (instance,params,origin,cancel) => { const {user,member,channel,guild} = instance - - //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.unpin,"support",user,member,channel,guild) - if (!permsResult.hasPerms){ - if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]})) - return cancel() - } - - //check is in guild/Server - if (!guild){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) - return cancel() - } - - //check if ticket exists - const ticket = opendiscord.tickets.get(channel.id) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return cancel() - } - - //return when not pinned yet - if (!ticket.get("opendiscord:pinned").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"})) - return cancel() - } - //return when busy - if (ticket.get("opendiscord:busy").value){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) - return cancel() - } - - const reason = instance.options.getString("reason",false) - - //start unpinning ticket + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unpin") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketPinned = await actionUtils.replyTicketMustBePinned(instance,origin,ticket) + if (!isTicketPinned) return cancel() + + //start unpining ticket await instance.defer(false) + const reason = instance.options.getString("reason",false) await opendiscord.actions.get("opendiscord:unpin-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason})) + + //send message & set state + const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"unpin-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { opendiscord.log(instance.user.displayName+" used the 'unpin' command!","info",[ @@ -69,48 +62,173 @@ export async function registerButtonResponders(){ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:unpin-ticket",/^od:unpin-ticket/)) opendiscord.responders.buttons.get("opendiscord:unpin-ticket").workers.add( new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin,cancel) => { - const originalOrigin = instance.interaction.customId.split("_")[1] as Exclude + const {guild,channel,user,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unpin") + if (!hasPerms) return cancel() - if (originalOrigin == "ticket-message") await opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").activate(instance) - else if (originalOrigin == "pin-message") await opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").activate(instance) - else await instance.defer("update",false) + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unpin") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketPinned = await actionUtils.replyTicketMustBePinned(instance,origin,ticket) + if (!isTicketPinned) return cancel() + + //fetch state details + const verifybar = opendiscord.verifybars.get("opendiscord:unpin-ticket") + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //send verifybar + if (generalConfig.data.system.disableVerifyBars){ + //verifybar disabled, directly run response + await verifybar.activate(instance,"accept") + + }else if (originalMsgType == "ticket-message"){ + //ticket message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unpin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "pin-message"){ + //pin message verifybar + const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unpin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:pin-message"),originalMsgType,{guild,channel,user,verifybar}) + await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } }) ) } +export async function registerVerifyBars(){ + //UNPIN TICKET + opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket")) + opendiscord.verifybars.get("opendiscord:unpin-ticket").workers.add([ + new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin,cancel) => { + const {user,member,channel,guild,message} = instance + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unpin") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || channel.isDMBased()) return cancel() + + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unpin") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketPinned = await actionUtils.replyTicketMustBePinned(instance,origin,ticket) + if (!isTicketPinned) return cancel() + + //fetch state details + const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user + const originalReason = state.data.messageReason ?? null + const originalMsgType = state.data.messageType + + //start unpinning ticket + if (params.selectedButtonId == "cancel"){ + //CANCEL + if (originalMsgType == "ticket-message"){ + //ticket message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "pin-message"){ + //pin message + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason})) + } + }else if (params.selectedButtonId == "accept"){ + //UNPIN TICKET + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) + await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket})) + }else if (originalMsgType == "pin-message"){ + //converted to unpin message + await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("verifybar",{guild,channel,user,ticket,reason:null})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"unpin-message", + messageOrigin:origin, + messageAuthor:user.id, + messageReason:null + },sentMsg.ephemeral) + } + }else if (params.selectedButtonId == "accept-with-reason"){ + //UNPIN WITH REASON (MODAL) + instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("other",{guild,channel,user,ticket,message})) + } + }) + ]) +} + export async function registerModalResponders(){ //UNPIN WITH REASON MODAL RESPONDER - opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unpin-ticket-reason",/^od:unpin-ticket-reason_/)) + opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unpin-ticket-reason",/^od:unpin-ticket-reason\|([^|]+)\|([^|]+)/)) opendiscord.responders.modals.get("opendiscord:unpin-ticket-reason").workers.add([ new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin,cancel) => { - const {guild,channel,user} = instance - if (!channel) return - if (!guild){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user:instance.user})) - return cancel() - } - const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1]) - if (!ticket || channel.isDMBased()){ - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) - return - } + const {guild,user} = instance + + const match = /^od:unpin-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId) + if (!match) return cancel() + const channel = await opendiscord.client.fetchTextChannel(match[1]) + const message = await opendiscord.client.fetchChannelMessage(match[1],match[2]) + + //responder checks + const hasPerms = await actionUtils.replyHasPermissions(instance,origin,"unpin") + if (!hasPerms) return cancel() + + const isInGuild = await actionUtils.replyIsInGuild(instance,origin) + if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel() - const originalOrigin = instance.interaction.customId.split("_")[2] as Exclude + const state = await actionUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unpin") + if (!state) return cancel() + + const ticket = await actionUtils.replyIsTicket(instance,origin) + if (!ticket) return cancel() + + const isAvailable = await actionUtils.replyTicketIsAvailable(instance,origin,ticket) + if (!isAvailable) return cancel() + + const isTicketPinned = await actionUtils.replyTicketMustBePinned(instance,origin,ticket) + if (!isTicketPinned) return cancel() + + //fetch state details const reason = instance.values.getTextField("reason",true) + const originalMsgOrigin = state.data.messageOrigin + const originalMsgType = state.data.messageType - //unpin with reason - if (originalOrigin == "ticket-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) + //start pinning ticket + await instance.defer("update",false) + + if (originalMsgType == "ticket-message"){ + //ticket message + await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true}) await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})) - }else if (originalOrigin == "pin-message"){ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:false}) - await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("other",{guild,channel,user,ticket,reason})) - }else{ - await instance.defer("update",false) - await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalOrigin,{guild,channel,user,ticket,reason,sendMessage:true}) + + }else if (originalMsgType == "pin-message"){ + //converted to unpin message + await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false}) + const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(originalMsgType,{guild,channel,user,ticket,reason})) + if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{ + messageType:"unpin-message", + messageOrigin:originalMsgOrigin, + messageAuthor:user.id, + messageReason:reason + },sentMsg.ephemeral) } }) ]) diff --git a/src/components/verifybarModifiers.ts b/src/components/verifybarModifiers.ts new file mode 100644 index 0000000..be67f9c --- /dev/null +++ b/src/components/verifybarModifiers.ts @@ -0,0 +1,138 @@ +/////////////////////////////////////// +//VERIFYBAR MESSAGE MODIFIERS +/////////////////////////////////////// +import {opendiscord, api, utilities} from "../index.js" +import * as discord from "discord.js" + +const modifiers = opendiscord.components.modifiers +const lang = opendiscord.languages +const generalConfig = opendiscord.configs.get("opendiscord:general") + +export async function addVerifyButton(instance:api.ODMessageInstance|api.ODComponentFactoryInstance,params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},buttonStyle:"✅"|"❌",verifyButtonId:string,customLabel?:string,customColor?:api.ODValidButtonColor,customEmoji?:string){ + const {guild,channel,user,verifybar} = params + if (instance instanceof api.ODMessageInstance){ + //message builders + instance.addComponent(await opendiscord.builders.buttons.getSafe("opendiscord:verifybar-button").build("verifybar",{ + guild,channel,user,verifybar, + buttonStyle,customColor,customEmoji,customLabel, + verifyButtonId + })) + }else{ + //message components + throw new api.ODSystemError("registerAllVerifyBarModifiers addVerifyButton() => verifybar doesn't support ODComponents v2 yet!") + //const message = instance.getComponent() + //if (!message) return + //const actionRow: api.ODActionRowComponent|null = message.getComponentsOfType("action-row")[0] + //if (actionRow) actionRow.addComponent(new api.ODButtonComponent("opendiscord:verifybar-button",{ + // //TODO + //}),"end") + } +} + +export async function registerAllVerifyBarModifiers(){ + //CLOSE TICKET VERIFYBAR + modifiers.add(new api.ODMessageComponentModifier("opendiscord:close-ticket-verifybar")) + modifiers.get("opendiscord:close-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:close-ticket-verifybar",100,async (instance,params,origin,cancel) => { + if (instance instanceof api.ODMessageInstance){ + instance.data.components = [] //clear actionrow + }else{ + throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!") + } + + //cancel, accept or close with reason + await addVerifyButton(instance,params,"❌",api.ODVerifyButtonId.Cancel) + await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.Accept) + if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️") + })) + + //REOPEN TICKET VERIFYBAR + modifiers.add(new api.ODMessageComponentModifier("opendiscord:reopen-ticket-verifybar")) + modifiers.get("opendiscord:reopen-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:reopen-ticket-verifybar",100,async (instance,params,origin,cancel) => { + if (instance instanceof api.ODMessageInstance){ + instance.data.components = [] //clear actionrow + }else{ + throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!") + } + + //cancel, accept or reopen with reason + await addVerifyButton(instance,params,"❌",api.ODVerifyButtonId.Cancel) + await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.Accept) + if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️") + })) + + //DELETE TICKET VERIFYBAR + modifiers.add(new api.ODMessageComponentModifier("opendiscord:delete-ticket-verifybar")) + modifiers.get("opendiscord:delete-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:delete-ticket-verifybar",100,async (instance,params,origin,cancel) => { + if (instance instanceof api.ODMessageInstance){ + instance.data.components = [] //clear actionrow + }else{ + throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!") + } + + //cancel, accept or delete with reason or without transcript + await addVerifyButton(instance,params,"❌",api.ODVerifyButtonId.Cancel) + await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.Accept) + if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️") + if (generalConfig.data.system.enableDeleteWithoutTranscript) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithoutTranscript,lang.getTranslation("actions.buttons.withoutTranscript"),"red","📄") + })) + + //CLAIM TICKET VERIFYBAR + modifiers.add(new api.ODMessageComponentModifier("opendiscord:claim-ticket-verifybar")) + modifiers.get("opendiscord:claim-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:claim-ticket-verifybar",100,async (instance,params,origin,cancel) => { + if (instance instanceof api.ODMessageInstance){ + instance.data.components = [] //clear actionrow + }else{ + throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!") + } + + //cancel, accept or claim with reason + await addVerifyButton(instance,params,"❌",api.ODVerifyButtonId.Cancel) + await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.Accept) + if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️") + })) + + //UNCLAIM TICKET VERIFYBAR + modifiers.add(new api.ODMessageComponentModifier("opendiscord:unclaim-ticket-verifybar")) + modifiers.get("opendiscord:unclaim-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:unclaim-ticket-verifybar",100,async (instance,params,origin,cancel) => { + if (instance instanceof api.ODMessageInstance){ + instance.data.components = [] //clear actionrow + }else{ + throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!") + } + + //cancel, accept or unclaim with reason + await addVerifyButton(instance,params,"❌",api.ODVerifyButtonId.Cancel) + await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.Accept) + if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️") + })) + + //PIN TICKET VERIFYBAR + modifiers.add(new api.ODMessageComponentModifier("opendiscord:pin-ticket-verifybar")) + modifiers.get("opendiscord:pin-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:pin-ticket-verifybar",100,async (instance,params,origin,cancel) => { + if (instance instanceof api.ODMessageInstance){ + instance.data.components = [] //clear actionrow + }else{ + throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!") + } + + //cancel, accept or pin with reason + await addVerifyButton(instance,params,"❌",api.ODVerifyButtonId.Cancel) + await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.Accept) + if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️") + })) + + //UNPIN TICKET VERIFYBAR + modifiers.add(new api.ODMessageComponentModifier("opendiscord:unpin-ticket-verifybar")) + modifiers.get("opendiscord:unpin-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:unpin-ticket-verifybar",100,async (instance,params,origin,cancel) => { + if (instance instanceof api.ODMessageInstance){ + instance.data.components = [] //clear actionrow + }else{ + throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!") + } + + //cancel, accept or unpin with reason + await addVerifyButton(instance,params,"❌",api.ODVerifyButtonId.Cancel) + await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.Accept) + if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️") + })) +} \ No newline at end of file diff --git a/src/core/mappings/builder.ts b/src/core/mappings/builder.ts index 67e8b50..7905161 100644 --- a/src/core/mappings/builder.ts +++ b/src/core/mappings/builder.ts @@ -16,9 +16,8 @@ import * as discord from "discord.js" * It's used to generate typescript declarations for this class. */ export interface ODButtonManagerIdMappings extends api.ODButtonManagerIdConstraint { - "opendiscord:verifybar-success":{origin:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,customData?:string,customColor?:api.ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-success"}, - "opendiscord:verifybar-failure":{origin:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,customData?:string,customColor?:api.ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-failure"}, - + "opendiscord:verifybar-button":{origin:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,verifyButtonId:string,buttonStyle:"✅"|"❌",customLabel?:string,customColor?:api.ODValidButtonColor,customEmoji?:string},workers:"opendiscord:verifybar-button"}, + "opendiscord:error-ticket-deprecated-transcript":{origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{},workers:"opendiscord:error-ticket-deprecated-transcript"}, "opendiscord:help-menu-previous":{origin:"text"|"slash"|"button"|"other",params:{mode:"slash"|"text",page:number},workers:"opendiscord:help-menu-previous"}, @@ -44,7 +43,7 @@ export interface ODButtonManagerIdMappings extends api.ODButtonManagerIdConstrai "opendiscord:transcript-error-retry":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler,reason:string|null},workers:"opendiscord:transcript-error-retry"}, "opendiscord:transcript-error-continue":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler,reason:string|null},workers:"opendiscord:transcript-error-continue"}, - "opendiscord:clear-continue":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-continue"}, + "opendiscord:clear-continue":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[],inProgress:boolean},workers:"opendiscord:clear-continue"}, } /**## ODDropdownManagerIdMappings `interface` @@ -97,14 +96,14 @@ export interface ODEmbedManagerIdMappings extends api.ODEmbedManagerIdConstraint "opendiscord:ticket-created":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created"}, "opendiscord:ticket-created-dm":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-dm"}, "opendiscord:ticket-created-logs":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-logs"}, - "opendiscord:ticket-message":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-message"}, - "opendiscord:close-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"autoclose"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:close-message"}, - "opendiscord:reopen-message":{origin:"slash"|"text"|"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:reopen-message"}, - "opendiscord:delete-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:delete-message"}, - "opendiscord:claim-message":{origin:"slash"|"text"|"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:claim-message"}, - "opendiscord:unclaim-message":{origin:"slash"|"text"|"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unclaim-message"}, - "opendiscord:pin-message":{origin:"slash"|"text"|"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:pin-message"}, - "opendiscord:unpin-message":{origin:"slash"|"text"|"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unpin-message"}, + "opendiscord:ticket-message":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-message"}, + "opendiscord:close-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"autoclose"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:close-message"}, + "opendiscord:reopen-message":{origin:"slash"|"text"|"ticket-message"|"close-message"|"autoclose-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:reopen-message"}, + "opendiscord:delete-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:delete-message"}, + "opendiscord:claim-message":{origin:"slash"|"text"|"ticket-message"|"unclaim-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:claim-message"}, + "opendiscord:unclaim-message":{origin:"slash"|"text"|"ticket-message"|"claim-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unclaim-message"}, + "opendiscord:pin-message":{origin:"slash"|"text"|"ticket-message"|"unpin-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:pin-message"}, + "opendiscord:unpin-message":{origin:"slash"|"text"|"ticket-message"|"pin-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unpin-message"}, "opendiscord:rename-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:string},workers:"opendiscord:rename-message"}, "opendiscord:move-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:ODTicketOption},workers:"opendiscord:move-message"}, "opendiscord:add-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:discord.User},workers:"opendiscord:add-message"}, @@ -128,11 +127,11 @@ export interface ODEmbedManagerIdMappings extends api.ODEmbedManagerIdConstraint "opendiscord:reaction-role-dm":{origin:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-dm"}, "opendiscord:reaction-role-logs":{origin:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-logs"}, - "opendiscord:clear-verify-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-verify-message"}, + "opendiscord:clear-verify-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[],inProgress:boolean},workers:"opendiscord:clear-verify-message"}, "opendiscord:clear-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-message"}, "opendiscord:clear-logs":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-logs"}, - "opendiscord:autoclose-message":{origin:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autoclose-message"}, + "opendiscord:autoclose-message":{origin:"timeout"|"leave"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autoclose-message"}, "opendiscord:autodelete-message":{origin:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autodelete-message"}, "opendiscord:autoclose-enable":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autoclose-enable"}, "opendiscord:autodelete-enable":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autodelete-enable"}, @@ -150,15 +149,6 @@ export interface ODEmbedManagerIdMappings extends api.ODEmbedManagerIdConstraint * It's used to generate typescript declarations for this class. */ export interface ODMessageManagerIdMappings extends api.ODMessageManagerIdConstraint { - "opendiscord:verifybar-ticket-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-ticket-message"}, - "opendiscord:verifybar-close-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-close-message"}, - "opendiscord:verifybar-reopen-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-reopen-message"}, - "opendiscord:verifybar-claim-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-claim-message"}, - "opendiscord:verifybar-unclaim-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unclaim-message"}, - "opendiscord:verifybar-pin-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-pin-message"}, - "opendiscord:verifybar-unpin-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unpin-message"} - "opendiscord:verifybar-autoclose-message":{origin:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-autoclose-message"} - "opendiscord:error":{origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:string,layout:"simple"|"advanced",customTitle?:string},workers:"opendiscord:error"}, "opendiscord:error-option-missing":{origin:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:api.ODTextCommandErrorMissingOption},workers:"opendiscord:error-option-missing"}, "opendiscord:error-option-invalid":{origin:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:api.ODTextCommandErrorInvalidOption},workers:"opendiscord:error-option-invalid"}, @@ -190,14 +180,14 @@ export interface ODMessageManagerIdMappings extends api.ODMessageManagerIdConstr "opendiscord:ticket-created":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created"}, "opendiscord:ticket-created-dm":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-dm"}, "opendiscord:ticket-created-logs":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-logs"}, - "opendiscord:ticket-message":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-message-layout"|"opendiscord:ticket-message-components"|"opendiscord:ticket-message-disable-components"}, - "opendiscord:close-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"autoclose"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:close-message"}, - "opendiscord:reopen-message":{origin:"slash"|"text"|"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:reopen-message"}, - "opendiscord:delete-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:delete-message"}, - "opendiscord:claim-message":{origin:"slash"|"text"|"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:claim-message"}, - "opendiscord:unclaim-message":{origin:"slash"|"text"|"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unclaim-message"}, - "opendiscord:pin-message":{origin:"slash"|"text"|"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:pin-message"}, - "opendiscord:unpin-message":{origin:"slash"|"text"|"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unpin-message"}, + "opendiscord:ticket-message":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-message-layout"|"opendiscord:ticket-message-components"|"opendiscord:ticket-message-disable-components"}, + "opendiscord:close-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"autoclose"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:close-message"}, + "opendiscord:reopen-message":{origin:"slash"|"text"|"ticket-message"|"close-message"|"autoclose-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:reopen-message"}, + "opendiscord:delete-message":{origin:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:delete-message"}, + "opendiscord:claim-message":{origin:"slash"|"text"|"ticket-message"|"unclaim-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:claim-message"}, + "opendiscord:unclaim-message":{origin:"slash"|"text"|"ticket-message"|"claim-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unclaim-message"}, + "opendiscord:pin-message":{origin:"slash"|"text"|"ticket-message"|"unpin-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:pin-message"}, + "opendiscord:unpin-message":{origin:"slash"|"text"|"ticket-message"|"pin-message"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unpin-message"}, "opendiscord:rename-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:string},workers:"opendiscord:rename-message"}, "opendiscord:move-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:ODTicketOption},workers:"opendiscord:move-message"}, "opendiscord:add-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:discord.User},workers:"opendiscord:add-message"}, @@ -221,11 +211,11 @@ export interface ODMessageManagerIdMappings extends api.ODMessageManagerIdConstr "opendiscord:reaction-role-dm":{origin:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-dm"}, "opendiscord:reaction-role-logs":{origin:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-logs"}, - "opendiscord:clear-verify-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-verify-message"}, + "opendiscord:clear-verify-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[],inProgress:boolean},workers:"opendiscord:clear-verify-message"}, "opendiscord:clear-message":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-message"}, "opendiscord:clear-logs":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-logs"}, - "opendiscord:autoclose-message":{origin:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autoclose-message"}, + "opendiscord:autoclose-message":{origin:"timeout"|"leave"|"verifybar"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autoclose-message"}, "opendiscord:autodelete-message":{origin:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autodelete-message"}, "opendiscord:autoclose-enable":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autoclose-enable"}, "opendiscord:autodelete-enable":{origin:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autodelete-enable"}, @@ -244,13 +234,13 @@ export interface ODMessageManagerIdMappings extends api.ODMessageManagerIdConstr */ export interface ODModalManagerIdMappings extends api.ODModalManagerIdConstraint { "opendiscord:ticket-questions":{origin:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,option:ODTicketOption},workers:"opendiscord:ticket-questions"} - "opendiscord:close-ticket-reason":{origin:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:close-ticket-reason"} - "opendiscord:reopen-ticket-reason":{origin:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:reopen-ticket-reason"} - "opendiscord:delete-ticket-reason":{origin:"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:delete-ticket-reason"} - "opendiscord:claim-ticket-reason":{origin:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:claim-ticket-reason"} - "opendiscord:unclaim-ticket-reason":{origin:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:unclaim-ticket-reason"} - "opendiscord:pin-ticket-reason":{origin:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:pin-ticket-reason"} - "opendiscord:unpin-ticket-reason":{origin:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:unpin-ticket-reason"} + "opendiscord:close-ticket-reason":{origin:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:close-ticket-reason"} + "opendiscord:reopen-ticket-reason":{origin:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:reopen-ticket-reason"} + "opendiscord:delete-ticket-reason":{origin:"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:delete-ticket-reason"} + "opendiscord:claim-ticket-reason":{origin:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:claim-ticket-reason"} + "opendiscord:unclaim-ticket-reason":{origin:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unclaim-ticket-reason"} + "opendiscord:pin-ticket-reason":{origin:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:pin-ticket-reason"} + "opendiscord:unpin-ticket-reason":{origin:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,message:discord.Message},workers:"opendiscord:unpin-ticket-reason"} } ///////////////////////////// diff --git a/src/core/mappings/component.ts b/src/core/mappings/component.ts index 42adc59..db313c6 100644 --- a/src/core/mappings/component.ts +++ b/src/core/mappings/component.ts @@ -33,7 +33,13 @@ export interface ODModalComponentManagerIdMappings extends api.ODComponentManage * It's used to generate typescript declarations for this class. */ export interface ODComponentModifierManagerIdMappings extends api.ODComponentModifierManagerIdConstraint { - //"opendiscord:example-modifier":api.ODMessageComponentModifier, + "opendiscord:close-ticket-verifybar":api.ODMessageComponentModifier<"ticket-message"|"reopen-message",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},string>, + "opendiscord:reopen-ticket-verifybar":api.ODMessageComponentModifier<"ticket-message"|"close-message"|"autoclose-message",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},string>, + "opendiscord:delete-ticket-verifybar":api.ODMessageComponentModifier<"ticket-message"|"close-message"|"autoclose-message"|"reopen-message",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},string>, + "opendiscord:claim-ticket-verifybar":api.ODMessageComponentModifier<"ticket-message"|"unclaim-message",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},string>, + "opendiscord:unclaim-ticket-verifybar":api.ODMessageComponentModifier<"ticket-message"|"claim-message",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},string>, + "opendiscord:pin-ticket-verifybar":api.ODMessageComponentModifier<"ticket-message"|"unpin-message",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},string>, + "opendiscord:unpin-ticket-verifybar":api.ODMessageComponentModifier<"ticket-message"|"pin-message",{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},string>, } ///////////////////////////// diff --git a/src/core/mappings/responder.ts b/src/core/mappings/responder.ts index 65217b8..db257f6 100644 --- a/src/core/mappings/responder.ts +++ b/src/core/mappings/responder.ts @@ -40,8 +40,7 @@ export interface ODCommandResponderManagerIdMappings extends api.ODCommandRespon * It's used to generate typescript declarations for this class. */ export interface ODButtonResponderManagerIdMappings extends api.ODButtonResponderManagerIdConstraint { - "opendiscord:verifybar-success":{origin:"button",params:{},workers:"opendiscord:handle-verifybar"}, - "opendiscord:verifybar-failure":{origin:"button",params:{},workers:"opendiscord:handle-verifybar"}, + "opendiscord:verifybar-button":{origin:"button",params:{},workers:"opendiscord:verifybar-button"}, "opendiscord:help-menu-switch":{origin:"button",params:{},workers:"opendiscord:update-help-menu"}, "opendiscord:help-menu-previous":{origin:"button",params:{},workers:"opendiscord:update-help-menu"}, diff --git a/src/core/mappings/state.ts b/src/core/mappings/state.ts index 1b57723..9136c41 100644 --- a/src/core/mappings/state.ts +++ b/src/core/mappings/state.ts @@ -3,6 +3,7 @@ /////////////////////////////////////// import * as api from "@open-discord-bots/framework/api" import * as discord from "discord.js" +import { ODTicketClearFilter } from "../api/ticket.js" /**## ODStateManagerIdMappings `interface` * A list of all available IDs in the default `ODStateManager` class in `opendiscord`. @@ -10,6 +11,7 @@ import * as discord from "discord.js" */ export interface ODStateManagerIdMappings extends api.ODStateManagerIdConstraint { "opendiscord:interactive-message":ODInteractiveMessageState, + "opendiscord:clear-message":ODClearMessageState, } ///////////////////////////// @@ -35,4 +37,26 @@ export class ODInteractiveMessageState extends api.ODState<{ messageAuthor?:string, /**Additional data of this interactive message. */ messageExtraData?:any, -},false,false> {} \ No newline at end of file +},false,false> { + constructor(id:api.ODValidId,client:api.ODClientManager,database:api.ODDatabase){ + super(id,client,database,{}) + } +} + +/**## ODClearMessageState `class + * A special class with state types for the Open Ticket clear tickets message. + */ +export class ODClearMessageState extends api.ODState<{ + /**The method this message was generated with. */ + messageOrigin:"slash"|"text"|"other", + /**The clear filters. */ + clearFilter:ODTicketClearFilter, + /**The list of ticket channel names (e.g. `#ticket-1`) to be cleared. */ + clearChannelNameList:string[] +},false,true> { + constructor(id:api.ODValidId,client:api.ODClientManager,database:api.ODDatabase){ + super(id,client,database,{ + autodeleteOnRestart:true + }) + } +} \ No newline at end of file diff --git a/src/core/mappings/verifybar.ts b/src/core/mappings/verifybar.ts index b2d4e01..267d422 100644 --- a/src/core/mappings/verifybar.ts +++ b/src/core/mappings/verifybar.ts @@ -10,7 +10,7 @@ import * as api from "@open-discord-bots/framework/api" export interface ODVerifyBarManagerIdMappings extends api.ODVerifyBarManagerIdConstraint { "opendiscord:close-ticket":api.ODVerifyBar<"accept"|"cancel"|"accept-with-reason","opendiscord:close-ticket">, "opendiscord:reopen-ticket":api.ODVerifyBar<"accept"|"cancel"|"accept-with-reason","opendiscord:reopen-ticket">, - "opendiscord:delete-ticket":api.ODVerifyBar<"accept"|"cancel"|"accept-with-reason","opendiscord:delete-ticket">, + "opendiscord:delete-ticket":api.ODVerifyBar<"accept"|"cancel"|"accept-with-reason"|"accept-without-transcript","opendiscord:delete-ticket">, "opendiscord:claim-ticket":api.ODVerifyBar<"accept"|"cancel"|"accept-with-reason","opendiscord:claim-ticket">, "opendiscord:unclaim-ticket":api.ODVerifyBar<"accept"|"cancel"|"accept-with-reason","opendiscord:unclaim-ticket">, "opendiscord:pin-ticket":api.ODVerifyBar<"accept"|"cancel"|"accept-with-reason","opendiscord:pin-ticket">, diff --git a/src/data/framework/codeLoader.ts b/src/data/framework/codeLoader.ts index 97ee71a..8a0f32f 100644 --- a/src/data/framework/codeLoader.ts +++ b/src/data/framework/codeLoader.ts @@ -381,6 +381,8 @@ export async function loadDatabaseSaversCode(){ } const loadAutoCode = () => { + const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message") + //AUTOCLOSE TIMEOUT opendiscord.code.add(new api.ODCode("opendiscord:autoclose-timeout",3,() => { setInterval(async () => { @@ -399,7 +401,13 @@ const loadAutoCode = () => { if (enabled && (new Date().getTime() - lastMessage.createdTimestamp) >= time){ //autoclose ticket await opendiscord.actions.get("opendiscord:close-ticket").run("autoclose",{guild:channel.guild,channel,user:opendiscord.client.client.user,ticket,reason:"Autoclose",sendMessage:false}) - await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("timeout",{guild:channel.guild,channel,user:opendiscord.client.client.user,ticket})).message) + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("timeout",{guild:channel.guild,channel,user:opendiscord.client.client.user,ticket})).message) + await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"autoclose-message", + messageOrigin:"other", + messageAuthor:opendiscord.client.client.user.id, + messageReason:"Autoclose" + },false) count++ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-autoclosed",1,"increase") } @@ -426,7 +434,13 @@ const loadAutoCode = () => { if (enabled){ //autoclose ticket await opendiscord.actions.get("opendiscord:close-ticket").run("autoclose",{guild:channel.guild,channel,user:opendiscord.client.client.user,ticket,reason:"Autoclose",sendMessage:false}) - await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("leave",{guild:channel.guild,channel,user:opendiscord.client.client.user,ticket})).message) + const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("leave",{guild:channel.guild,channel,user:opendiscord.client.client.user,ticket})).message) + await interactiveMsgState.setMsgState({channel,message:sentMsg},{ + messageType:"autoclose-message", + messageOrigin:"other", + messageAuthor:opendiscord.client.client.user.id, + messageReason:"Autoclose" + },false) await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-autoclosed",1,"increase") } } diff --git a/src/data/framework/stateLoader.ts b/src/data/framework/stateLoader.ts index 60573b1..7654feb 100644 --- a/src/data/framework/stateLoader.ts +++ b/src/data/framework/stateLoader.ts @@ -3,5 +3,6 @@ import {opendiscord, api, utilities} from "../../index.js" export async function loadAllStates(){ const stateDatabase = opendiscord.databases.get("opendiscord:message-states") - 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)) } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 9629ea6..cba8a7c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -676,7 +676,7 @@ const main = async () => { //load component modifiers opendiscord.log("Loading component modifiers...","system") if (opendiscord.sharedFuses.getFuse("componentModifiersLoading")){ - //TODO!! + await (await import("./components/verifybarModifiers.js")).registerAllVerifyBarModifiers() } await opendiscord.events.get("onComponentModifierLoad").emit([opendiscord.components.modifiers,opendiscord.components.messages,opendiscord.builders.messages]) await opendiscord.events.get("afterComponentModifiersLoaded").emit([opendiscord.components.modifiers,opendiscord.components.messages,opendiscord.builders.messages]) @@ -806,13 +806,13 @@ const main = async () => { //load verifybars opendiscord.log("Loading verifybars...","system") if (opendiscord.sharedFuses.getFuse("verifyBarsLoading")){ - await (await import("./actions/closeTicket.js")).registerVerifyBars() - await (await import("./actions/deleteTicket.js")).registerVerifyBars() - await (await import("./actions/reopenTicket.js")).registerVerifyBars() - await (await import("./actions/claimTicket.js")).registerVerifyBars() - await (await import("./actions/unclaimTicket.js")).registerVerifyBars() - await (await import("./actions/pinTicket.js")).registerVerifyBars() - await (await import("./actions/unpinTicket.js")).registerVerifyBars() + await (await import("./commands/close.js")).registerVerifyBars() + await (await import("./commands/delete.js")).registerVerifyBars() + await (await import("./commands/reopen.js")).registerVerifyBars() + await (await import("./commands/claim.js")).registerVerifyBars() + await (await import("./commands/unclaim.js")).registerVerifyBars() + await (await import("./commands/pin.js")).registerVerifyBars() + await (await import("./commands/unpin.js")).registerVerifyBars() } await opendiscord.events.get("onVerifyBarLoad").emit([opendiscord.verifybars]) await opendiscord.events.get("afterVerifyBarsLoaded").emit([opendiscord.verifybars])