-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
1,293 additions
and
60 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { ChannelType, ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js'; | ||
|
||
import { query } from '../utils/postgres'; | ||
|
||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName('add') | ||
.setDescription('Add a member to a support ticket') | ||
.addUserOption((option) => option.setName('member').setDescription('The member to give access to this support ticket').setRequired(true)), | ||
|
||
category: 'Tickets', | ||
guildOnly: true, | ||
|
||
async execute(interaction: ChatInputCommandInteraction) { | ||
if (!interaction.inCachedGuild() || interaction.channel?.type !== ChannelType.GuildText) return interaction.client.error.ONLY_IN_GUILD(interaction); | ||
|
||
const { rows: currentSupportRows } = await query('SELECT FROM supports WHERE channel = $1 AND guild = $2;', [interaction.channelId, interaction.guildId]); | ||
if (currentSupportRows.length === 0) return interaction.client.error.ONLY_IN_TICKET(interaction, false); | ||
|
||
const member = interaction.options.getMember('member'); | ||
if (!member) return interaction.client.error.INVALID_INPUT(interaction, 'member', 'should be nonzero'); | ||
const memberID = member.id; | ||
|
||
await interaction.channel.permissionOverwrites.create(memberID, { | ||
ViewChannel: true, | ||
ReadMessageHistory: true, | ||
SendMessages: true, | ||
}); | ||
|
||
return interaction.editReply(`You added ${member.displayName} to this support ticket!`); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { ChatInputCommandInteraction, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js'; | ||
import { v4 as uuidv4 } from 'uuid'; | ||
|
||
import { query } from '../utils/postgres'; | ||
|
||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName('ban') | ||
.setDescription('Ban a member') | ||
.addUserOption((option) => option.setName('member').setDescription('The member to ban').setRequired(true)) | ||
.addStringOption((option) => option.setName('reason').setDescription('The reason to ban').setRequired(true).setMaxLength(512).setMinLength(2)) | ||
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers), | ||
|
||
category: 'Moderation', | ||
guildOnly: true, | ||
|
||
async execute(interaction: ChatInputCommandInteraction) { | ||
if (!interaction.inCachedGuild()) return interaction.client.error.ONLY_IN_GUILD(interaction); | ||
if (!interaction.member.permissions.has(PermissionFlagsBits.BanMembers)) return interaction.client.error.NO_PERMISSION(interaction); | ||
|
||
const moderator = interaction.member; | ||
const moderatorID = moderator.id; | ||
|
||
const member = interaction.options.getMember('member'); | ||
if (!member) return interaction.client.error.INVALID_INPUT(interaction, 'member', 'should be nonzero'); | ||
const memberID = member.id; | ||
if (memberID === moderatorID) return interaction.client.error.INVALID_INPUT(interaction, 'member', 'should not be you'); | ||
|
||
const reason = interaction.options.getString('reason', true); | ||
if (reason.length < 2 || reason.length > 512) return interaction.client.error.INVALID_INPUT(interaction, 'reason', 'should be 512 characters or less'); | ||
|
||
const positionDifference = moderator.roles.highest.comparePositionTo(member.roles.highest); | ||
if (positionDifference <= 0) return interaction.client.error.NO_PERMISSION(interaction); | ||
|
||
if (!member.bannable) return interaction.editReply('I have no permissions to ban this member!'); | ||
|
||
member.send(`You are banned for ${reason} in ${interaction.guild.name}, goodbye!`).catch(); | ||
|
||
try { | ||
member.ban({ reason }); | ||
} catch (error) { | ||
return interaction.client.error.UNKNOWN_ERROR(interaction, error); | ||
} | ||
|
||
await query('INSERT INTO guilds (id) VALUES ($1) ON CONFLICT DO NOTHING;', [interaction.guildId]); | ||
await query('INSERT INTO users (id) VALUES ($1) ON CONFLICT DO NOTHING;', [memberID]); | ||
await query('INSERT INTO users (id) VALUES ($1) ON CONFLICT DO NOTHING;', [moderatorID]); | ||
|
||
const id = uuidv4(); | ||
|
||
await query('INSERT INTO bans (id, guild, member, reason, moderator, time) VALUES ($1,$2,$3,$4,$5,$6);', [ | ||
id, | ||
interaction.guildId, | ||
memberID, | ||
reason, | ||
moderatorID, | ||
interaction.createdAt, | ||
]); | ||
return interaction.editReply(`Banned ${member.displayName} for ${reason}!`); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { ChannelType, ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js'; | ||
|
||
import { closeTicket } from '../utils/tickets'; | ||
|
||
export default { | ||
data: new SlashCommandBuilder().setName('close').setDescription('Close a support or mail ticket'), | ||
|
||
category: 'Tickets', | ||
guildOnly: true, | ||
|
||
async execute(interaction: ChatInputCommandInteraction) { | ||
if (!interaction.inCachedGuild() || interaction.channel?.type !== ChannelType.GuildText) return interaction.client.error.ONLY_IN_GUILD(interaction); | ||
|
||
await interaction.editReply({ content: 'This support or mail ticket will be closed!' }); | ||
|
||
const result = await closeTicket(interaction.channelId, interaction.guildId, interaction.channel); | ||
if (!result.success) return interaction.client.error.ONLY_IN_TICKET(interaction, true); | ||
else if (result.embed && result.memberID) { | ||
// Ticket was a mail ticket | ||
try { | ||
const member = await interaction.client.users.fetch(result.memberID); | ||
await member.send({ embeds: [result.embed] }); | ||
} catch (e) { | ||
// | ||
} | ||
} | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { ChatInputCommandInteraction, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js'; | ||
|
||
import { query } from '../utils/postgres'; | ||
|
||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName('delwarn') | ||
.setDescription('Delete a warning') | ||
.addStringOption((option) => option.setName('warning').setDescription('The ID of the warning').setRequired(true)) | ||
.addStringOption((option) => option.setName('reason').setDescription('The reason to delete a warning').setRequired(true).setMaxLength(512).setMinLength(2)) | ||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages), | ||
|
||
category: 'Moderation', | ||
guildOnly: true, | ||
|
||
async execute(interaction: ChatInputCommandInteraction) { | ||
if (!interaction.inCachedGuild()) return interaction.client.error.ONLY_IN_GUILD(interaction); | ||
if (!interaction.member.permissions.has(PermissionFlagsBits.ManageMessages)) return interaction.client.error.NO_PERMISSION(interaction); | ||
|
||
const moderator = interaction.member; | ||
const moderatorID = moderator.id; | ||
|
||
const warningID = interaction.options.getString('warning', true); | ||
if (!warningID) return interaction.client.error.INVALID_INPUT(interaction, 'warning', 'should be nonzero'); | ||
|
||
const reason = interaction.options.getString('reason', true); | ||
if (reason.length < 2 || reason.length > 512) return interaction.client.error.INVALID_INPUT(interaction, 'reason', 'should be 512 characters or less'); | ||
|
||
const { rows: warningRows } = await query('SELECT guild, member, reason FROM warnings WHERE id = $1;', [warningID]); | ||
if (warningRows[0].length === 0 || warningRows[0].guild !== interaction.guildId) return interaction.editReply('This warning does not exists!'); | ||
if (warningRows[0].member === moderatorID) return interaction.client.error.INVALID_INPUT(interaction, 'warning', 'should not be a warning of yours'); | ||
|
||
await query('DELETE FROM warnings WHERE id = $1 AND guild = $2;', [warningID, interaction.guildId]); | ||
return interaction.editReply(`Deleted warning "${warningRows[0].reason}" for ${reason}!`); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { ChatInputCommandInteraction, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js'; | ||
|
||
import { createEmbed } from '../utils/embed'; | ||
import { query } from '../utils/postgres'; | ||
|
||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName('giveaway') | ||
.setDescription('Create a giveaway') | ||
.addStringOption((option) => option.setName('prize').setDescription('The prize of the giveaway').setRequired(true).setMinLength(2).setMaxLength(512)) | ||
.addIntegerOption((option) => | ||
option.setName('minutes').setDescription('The amount of minutes you want to mute this user for').setMinValue(1).setMaxValue(59) | ||
) | ||
.addIntegerOption((option) => option.setName('hours').setDescription('The amount of hours you want to mute this user for').setMinValue(1).setMaxValue(168)) | ||
.addIntegerOption((option) => option.setName('winners').setDescription('The amount of winners').setMinValue(1).setMaxValue(25)) | ||
.addRoleOption((option) => option.setName('role').setDescription('Required role to enter')) | ||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageEvents), | ||
|
||
category: 'General', | ||
|
||
async execute(interaction: ChatInputCommandInteraction) { | ||
if (!interaction.inCachedGuild()) return interaction.client.error.ONLY_IN_GUILD(interaction); | ||
if (!interaction.member.permissions.has(PermissionFlagsBits.ManageGuild)) return interaction.client.error.NO_PERMISSION(interaction); | ||
|
||
const prize = interaction.options.getString('prize', true); | ||
const winnersAmount = interaction.options.getInteger('winners') || 1; | ||
const roleRequirement = interaction.options.getRole('role'); | ||
|
||
const hours = interaction.options.getInteger('hours'); | ||
if (hours && (hours < 1 || hours > 168)) return interaction.client.error.INVALID_INPUT(interaction, 'hours', 'should be between 1 and 168'); | ||
const minutes = interaction.options.getInteger('minutes'); | ||
if (minutes && (minutes < 1 || minutes > 59)) return interaction.client.error.INVALID_INPUT(interaction, 'minutes', 'should be between 1 and 59'); | ||
const minutesToAdd = (minutes || 0) + (hours || 0) * 60; | ||
if (minutesToAdd < 1 || minutesToAdd > Number.MAX_SAFE_INTEGER) | ||
return interaction.client.error.INVALID_INPUT(interaction, 'hours/minutes', 'should be nonzero'); | ||
|
||
if (prize.length < 2 || prize.length > 512) | ||
return interaction.client.error.INVALID_INPUT(interaction, 'prize', 'should have a length of max 512 characters'); | ||
if (winnersAmount < 1 || winnersAmount > 25) return interaction.client.error.INVALID_INPUT(interaction, 'winners', 'should be between 1 and 25'); | ||
|
||
const endTime = interaction.createdTimestamp + minutesToAdd * 60 * 1000; | ||
|
||
const embed = await createEmbed(); | ||
embed.setTitle(`🎉 ${winnersAmount} Winner${winnersAmount > 1 ? 's' : ''} 🎉`); | ||
embed.setDescription(` | ||
Prize: **${prize}**\n\nEnds in <t:${Math.round(endTime / 1000)}:R> (<t:${Math.round(endTime / 1000)}:f>)! | ||
${roleRequirement ? `\nMust have: ${roleRequirement}` : ''} | ||
`); | ||
|
||
const sentResponse = await interaction.editReply({ embeds: [embed] }); | ||
await sentResponse.react('🎉'); | ||
|
||
return query('INSERT INTO giveaways (message, channel, endtime, prize, winners, role) VALUES ($1,$2,$3,$4,$5,$6);', [ | ||
sentResponse.id, | ||
sentResponse.channelId, | ||
new Date(endTime), | ||
prize, | ||
winnersAmount, | ||
roleRequirement?.id || null, | ||
]); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { ChatInputCommandInteraction, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js'; | ||
import { v4 as uuidv4 } from 'uuid'; | ||
|
||
import { query } from '../utils/postgres'; | ||
|
||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName('kick') | ||
.setDescription('Kick a member') | ||
.addUserOption((option) => option.setName('member').setDescription('The member to kick').setRequired(true)) | ||
.addStringOption((option) => option.setName('reason').setDescription('The reason to kick').setRequired(true).setMaxLength(512).setMinLength(2)) | ||
.setDefaultMemberPermissions(PermissionFlagsBits.KickMembers), | ||
|
||
category: 'Moderation', | ||
guildOnly: true, | ||
|
||
async execute(interaction: ChatInputCommandInteraction) { | ||
if (!interaction.inCachedGuild()) return interaction.client.error.ONLY_IN_GUILD(interaction); | ||
if (!interaction.member.permissions.has(PermissionFlagsBits.KickMembers)) return interaction.client.error.NO_PERMISSION(interaction); | ||
|
||
const moderator = interaction.member; | ||
const moderatorID = moderator.id; | ||
|
||
const member = interaction.options.getMember('member'); | ||
if (!member) return interaction.client.error.INVALID_INPUT(interaction, 'member', 'should be nonzero'); | ||
const memberID = member.id; | ||
if (memberID === moderatorID) return interaction.client.error.INVALID_INPUT(interaction, 'member', 'should not be you'); | ||
|
||
const reason = interaction.options.getString('reason', true); | ||
if (reason.length < 2 || reason.length > 512) return interaction.client.error.INVALID_INPUT(interaction, 'reason', 'should be 512 characters or less'); | ||
|
||
const positionDifference = moderator.roles.highest.comparePositionTo(member.roles.highest); | ||
if (positionDifference <= 0) return interaction.client.error.NO_PERMISSION(interaction); | ||
|
||
if (!member.kickable) return interaction.editReply('I have no permissions to kick this member!'); | ||
|
||
member.send(`You are kicked for ${reason} in ${interaction.guild.name}, goodbye!`).catch(); | ||
|
||
try { | ||
await member.kick(reason); | ||
} catch (error) { | ||
return interaction.client.error.UNKNOWN_ERROR(interaction, error); | ||
} | ||
|
||
await query('INSERT INTO guilds (id) VALUES ($1) ON CONFLICT DO NOTHING;', [interaction.guildId]); | ||
await query('INSERT INTO users (id) VALUES ($1) ON CONFLICT DO NOTHING;', [memberID]); | ||
await query('INSERT INTO users (id) VALUES ($1) ON CONFLICT DO NOTHING;', [moderatorID]); | ||
|
||
const id = uuidv4(); | ||
|
||
await query('INSERT INTO kicks (id, guild, member, reason, moderator, time) VALUES ($1,$2,$3,$4,$5,$6);', [ | ||
id, | ||
interaction.guildId, | ||
memberID, | ||
reason, | ||
moderatorID, | ||
interaction.createdAt, | ||
]); | ||
return interaction.editReply(`Kicked ${member.displayName} for ${reason}!`); | ||
}, | ||
}; |
Oops, something went wrong.