Working on roles
This commit is contained in:
@@ -130,3 +130,5 @@ dist
|
|||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
config.json
|
config.json
|
||||||
|
|
||||||
|
*.db
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import {
|
||||||
|
type CommandInteraction,
|
||||||
|
SlashCommandBuilder, EmbedBuilder, PermissionsBitField
|
||||||
|
} from 'discord.js'
|
||||||
|
import { execute, obj2role } from '../db'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('checkroles')
|
||||||
|
.setDescription('Prints all role permissions'),
|
||||||
|
async execute (interaction: CommandInteraction) {
|
||||||
|
const role = interaction.options.get('role')?.value
|
||||||
|
if (role === undefined) {
|
||||||
|
await interaction.reply({ content: 'Cannot find role', ephemeral: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ((interaction.memberPermissions?.has(PermissionsBitField.Flags.ManageRoles, true)) !== true) {
|
||||||
|
await interaction.reply({ content: 'I am sorry dave, I cannot do that\nYou don\'t have the permission to manage roles on this server', ephemeral: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Set Role
|
||||||
|
|
||||||
|
await execute('DELETE FROM permissions WHERE guild=$guild AND role=$role',
|
||||||
|
{
|
||||||
|
$guild: interaction.guildId,
|
||||||
|
$role: role
|
||||||
|
})
|
||||||
|
|
||||||
|
const permissions = {
|
||||||
|
create: Boolean(interaction.options.get('create_permission')?.value),
|
||||||
|
delete: Boolean(interaction.options.get('delete_permission')?.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
await execute('INSERT INTO permissions (guild, role, permissions) VALUES($guild, $role, $permissions)',
|
||||||
|
{
|
||||||
|
$guild: interaction.guildId,
|
||||||
|
$role: role,
|
||||||
|
$permissions: obj2role(permissions)
|
||||||
|
})
|
||||||
|
|
||||||
|
const statusUpdate = new EmbedBuilder()
|
||||||
|
.setColor(0x0099FF)
|
||||||
|
.setTitle('Role updated successfully')
|
||||||
|
.addFields(
|
||||||
|
{ name: 'Role', value: `<@&${role.toString()}>` },
|
||||||
|
{ name: 'Can add goobs', value: permissions.create ? '🟩' : '🟥', inline: true },
|
||||||
|
{ name: 'Can delete goobs', value: permissions.delete ? '🟩' : '🟥', inline: true }
|
||||||
|
)
|
||||||
|
.setTimestamp()
|
||||||
|
await interaction.reply({ embeds: [statusUpdate], ephemeral: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
type CommandInteraction,
|
||||||
|
SlashCommandBuilder, EmbedBuilder, type Message, ButtonStyle, ButtonBuilder, ActionRowBuilder, ComponentType
|
||||||
|
} from 'discord.js'
|
||||||
|
import { execute } from '../db'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('goob')
|
||||||
|
.setDescription('meow').addIntegerOption(option =>
|
||||||
|
option
|
||||||
|
.setName('gooberid')
|
||||||
|
.setDescription('The goob to see')
|
||||||
|
.setRequired(false)),
|
||||||
|
async execute (interaction: CommandInteraction) {
|
||||||
|
// Pick the right goober
|
||||||
|
const amountOfGoobs = (await execute('SELECT COUNT(*) as totalweight from goob'))[0].totalweight
|
||||||
|
let number = Number(interaction.options.get('gooberid')?.value)
|
||||||
|
let targetImage
|
||||||
|
if (!Number.isNaN(number)) {
|
||||||
|
targetImage = (await execute('SELECT * from goob WHERE id = $messageid', { $messageid: number }))[0]
|
||||||
|
} else {
|
||||||
|
number = Math.ceil(Math.random() * amountOfGoobs)
|
||||||
|
targetImage = (await execute('WITH indexed as (SELECT *, COUNT(*) over(order by messageid) as theRow from goob) SELECT * from indexed WHERE theRow = $messageid', { $messageid: number }))[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the original message
|
||||||
|
const messageGuild = await interaction.client.guilds.fetch(targetImage.guild)
|
||||||
|
const messageChannel = await messageGuild.channels.fetch(targetImage.channel)
|
||||||
|
let message = undefined as Message | undefined
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||||
|
if (messageChannel?.isTextBased()) {
|
||||||
|
message = await messageChannel.messages.fetch(targetImage.messageid).catch(() => undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if goob is a video or not and send the goob
|
||||||
|
const data = await fetch(targetImage.url)
|
||||||
|
const contentType = data.headers.get('content-type')
|
||||||
|
|
||||||
|
let exampleEmbed = new EmbedBuilder()
|
||||||
|
.setColor(0x0099FF)
|
||||||
|
.setTitle(`Goob #${targetImage.id as number}`)
|
||||||
|
.setURL(message?.url ?? targetImage.url)
|
||||||
|
.setTimestamp(message?.createdTimestamp ?? undefined)
|
||||||
|
.setAuthor({ name: message?.author.username ?? 'deleted message', iconURL: message?.author.avatarURL() ?? undefined, url: message?.url })
|
||||||
|
|
||||||
|
let files: any[] | undefined
|
||||||
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||||
|
if (contentType?.startsWith('video')) {
|
||||||
|
files = [{ attachment: targetImage.url }]
|
||||||
|
} else {
|
||||||
|
exampleEmbed = exampleEmbed.setImage(targetImage.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
const gulag = new ButtonBuilder()
|
||||||
|
.setCustomId('Delete')
|
||||||
|
.setLabel('Delete')
|
||||||
|
.setStyle(ButtonStyle.Danger)
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder()
|
||||||
|
.addComponents(gulag) as any
|
||||||
|
const response = await interaction.reply({ embeds: [exampleEmbed], files, components: [row] })
|
||||||
|
|
||||||
|
const collector = response.createMessageComponentCollector({ componentType: ComponentType.Button, time: 3_600_00 })
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
const roles = (await execute('SELECT * from permissions WHERE guild = $guild', { $guild: i.guild?.id }))
|
||||||
|
console.log(roles)
|
||||||
|
console.log(i.member?.roles)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+107
-23
@@ -1,54 +1,138 @@
|
|||||||
import { type CommandInteraction, SlashCommandBuilder, type Message } from 'discord.js'
|
import {
|
||||||
|
type CommandInteraction,
|
||||||
|
SlashCommandBuilder,
|
||||||
|
type Message
|
||||||
|
} from 'discord.js'
|
||||||
import { owner_id } from '../config.json'
|
import { owner_id } from '../config.json'
|
||||||
import db from '../db'
|
import db from '../db'
|
||||||
|
|
||||||
|
function insertGoob (message: Message): void {
|
||||||
|
const attachments = message.attachments.filter(
|
||||||
|
(e) =>
|
||||||
|
e.contentType !== null &&
|
||||||
|
(e.contentType?.startsWith('image') || e.contentType?.startsWith('video'))
|
||||||
|
)
|
||||||
|
|
||||||
|
const embeds = message.embeds.filter((e) => e.image !== undefined || e.video !== undefined)
|
||||||
|
|
||||||
|
attachments.forEach(a => db.run('INSERT INTO goob (messageid, guild, channel, url) VALUES ($messageid, $guild, $channel, $url)', {
|
||||||
|
$messageid: message.id,
|
||||||
|
$guild: message.guildId,
|
||||||
|
$channel: message.channelId,
|
||||||
|
$url: a.url
|
||||||
|
}))
|
||||||
|
|
||||||
|
embeds.forEach(e => db.run('INSERT INTO goob (messageid, guild, channel, url) VALUES ($messageid, $guild, $channel, $url)', {
|
||||||
|
$messageid: message.id,
|
||||||
|
$guild: message.guildId,
|
||||||
|
$channel: message.channelId,
|
||||||
|
$url: e.video !== undefined ? e.video?.url : e.image?.url
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (attachments.size > 0 || embeds.length > 0) void message.react('📥')
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('load')
|
.setName('load')
|
||||||
.setDescription('Provides information about the user.'),
|
.setDescription('Sync data for '),
|
||||||
async execute (interaction: CommandInteraction) {
|
async execute (interaction: CommandInteraction) {
|
||||||
if (interaction.user.id !== owner_id) {
|
if (interaction.user.id !== owner_id) {
|
||||||
await interaction.reply({ content: 'You do not have access to this command!', ephemeral: true })
|
await interaction.reply({
|
||||||
|
content: 'You do not have access to this command!',
|
||||||
|
ephemeral: true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (interaction.channel?.isDMBased() === true) {
|
if (
|
||||||
await interaction.reply({ content: 'This command is disabled for DM channels', ephemeral: true })
|
interaction.channel?.isDMBased() === true ||
|
||||||
|
interaction.guild === undefined
|
||||||
|
) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: 'This command is disabled for DM channels',
|
||||||
|
ephemeral: true
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db.run('DELETE FROM goob WHERE guild = $guild', {
|
||||||
|
$guild: interaction.guildId
|
||||||
|
})
|
||||||
|
db.run('DELETE FROM tracked WHERE guild = $guild', {
|
||||||
|
$guild: interaction.guildId
|
||||||
|
})
|
||||||
|
|
||||||
let loaded = 0
|
let loaded = 0
|
||||||
const images = new Set<string>()
|
const loadedImages = 0
|
||||||
let messages = await interaction.channel?.messages.fetch().catch(console.error)
|
let messages = await interaction.channel?.messages
|
||||||
|
.fetch()
|
||||||
|
.catch(console.error)
|
||||||
if (messages === undefined) {
|
if (messages === undefined) {
|
||||||
await interaction.reply('Couldn\'t fetch messages')
|
await interaction.reply("Couldn't fetch messages")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
loaded += messages.size
|
loaded += messages.size
|
||||||
await interaction.reply(`Loading messages... loaded ${loaded} with ${images.size} images`)
|
await interaction.reply(
|
||||||
|
`Loading messages... loaded ${loaded} with ${loadedImages} images`
|
||||||
|
)
|
||||||
|
|
||||||
while (messages !== undefined && messages.size > 0) {
|
while (messages !== undefined && messages.size > 0) {
|
||||||
const imagesURL = (messages as unknown as Message[]).map(e => e.attachments).filter(e => e.size > 0).map(e => e.map(v => v)).flat().filter(e => e.contentType?.startsWith('image')).map(e => e.url).flat()
|
(messages as unknown as Message[])
|
||||||
imagesURL.forEach(images.add, images)
|
.map((e) => e).filter(e => !e.author.bot)
|
||||||
|
.filter(
|
||||||
|
(e) =>
|
||||||
|
e.attachments.filter(
|
||||||
|
(e) =>
|
||||||
|
e.contentType !== null &&
|
||||||
|
(e.contentType?.startsWith('image') ||
|
||||||
|
e.contentType?.startsWith('video'))
|
||||||
|
).size > 0
|
||||||
|
).map(insertGoob);
|
||||||
|
|
||||||
|
(messages as unknown as Message[])
|
||||||
|
.map((e) => e).filter(e => !e.author.bot)
|
||||||
|
.filter(
|
||||||
|
(e) =>
|
||||||
|
e.embeds.filter(
|
||||||
|
(e) => e.image !== undefined
|
||||||
|
).length > 0
|
||||||
|
).map(insertGoob)
|
||||||
|
|
||||||
const lastmessage = messages.last() as Message | undefined
|
const lastmessage = messages.last() as Message | undefined
|
||||||
if (lastmessage === undefined) {
|
if (lastmessage === undefined) {
|
||||||
await interaction.editReply('Coudn\'t fetch message data')
|
await interaction.editReply("Coudn't fetch message data")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
await interaction.editReply(`Loading messages... loaded ${loaded} messages with ${images.size} images`)
|
await interaction.editReply(
|
||||||
|
`Loading messages... loaded ${loaded} messages with ${loadedImages} images`
|
||||||
|
)
|
||||||
|
|
||||||
messages = await interaction.channel?.messages.fetch({ before: lastmessage.id }).catch(console.error)
|
messages = await interaction.channel?.messages
|
||||||
|
.fetch({ before: lastmessage.id })
|
||||||
|
.catch(console.error)
|
||||||
if (messages !== undefined) loaded += messages.size
|
if (messages !== undefined) loaded += messages.size
|
||||||
}
|
}
|
||||||
|
|
||||||
await interaction.editReply(`Loading complete ! loaded ${loaded} messages with ${images.size} images`)
|
await interaction.editReply(
|
||||||
const stmt = db.prepare('INSERT INTO goob VALUES (?)')
|
`Loading complete ! loaded ${loaded} messages with ${loadedImages} images`
|
||||||
|
)
|
||||||
|
|
||||||
images.forEach(e => stmt.run(e))
|
const reply = await interaction.fetchReply()
|
||||||
stmt.finalize()
|
if (reply === undefined) {
|
||||||
|
await interaction.reply({
|
||||||
db.each('SELECT rowid AS id, url FROM goob', (err, row: any) => {
|
content: 'Impossible to fetch reply. Did something go wrong ?',
|
||||||
console.log(`${row.id as string} : ${row.url as string}`)
|
ephemeral: true
|
||||||
if (err != null) console.error(err)
|
|
||||||
})
|
})
|
||||||
console.log(images)
|
return
|
||||||
|
}
|
||||||
|
db.run(
|
||||||
|
'INSERT INTO tracked (guild, last_message, channel) VALUES ($guild, $last_message, $channel)',
|
||||||
|
{
|
||||||
|
$guild: interaction.guildId,
|
||||||
|
$channel: interaction.channelId,
|
||||||
|
$last_message: reply.id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// interaction.user is the object representing the User who ran the command
|
// interaction.user is the object representing the User who ran the command
|
||||||
// interaction.member is the GuildMember object, which represents the user in the specific guild
|
// interaction.member is the GuildMember object, which represents the user in the specific guild
|
||||||
// await interaction.reply(`This command was run by ${interaction.user.username}`)
|
// await interaction.reply(`This command was run by ${interaction.user.username}`)
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import {
|
||||||
|
type CommandInteraction,
|
||||||
|
SlashCommandBuilder, EmbedBuilder, PermissionsBitField
|
||||||
|
} from 'discord.js'
|
||||||
|
import { execute, obj2role } from '../db'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('setrole')
|
||||||
|
.setDescription('Adds permissions to a discord role')
|
||||||
|
.addRoleOption(option =>
|
||||||
|
option
|
||||||
|
.setName('role')
|
||||||
|
.setDescription('The role')
|
||||||
|
.setRequired(true))
|
||||||
|
.addBooleanOption(option =>
|
||||||
|
option
|
||||||
|
.setName('delete_permission')
|
||||||
|
.setDescription('Permission to delete goobs')
|
||||||
|
.setRequired(true))
|
||||||
|
.addBooleanOption(option =>
|
||||||
|
option
|
||||||
|
.setName('create_permission')
|
||||||
|
.setDescription('Permission to add goobs')
|
||||||
|
.setRequired(true)),
|
||||||
|
async execute (interaction: CommandInteraction) {
|
||||||
|
/* const totalweight = (await execute('SELECT SUM(weight) as totalweight from goob'))[0].totalweight
|
||||||
|
const number = Math.floor(Math.random() * totalweight) */
|
||||||
|
|
||||||
|
const role = interaction.options.get('role')?.value
|
||||||
|
if (role === undefined) {
|
||||||
|
await interaction.reply({ content: 'Cannot find role', ephemeral: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ((interaction.memberPermissions?.has(PermissionsBitField.Flags.ManageRoles, true)) !== true) {
|
||||||
|
await interaction.reply({ content: 'I am sorry dave, I cannot do that\nYou don\'t have the permission to manage roles on this server', ephemeral: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Set Role
|
||||||
|
|
||||||
|
await execute('DELETE FROM permissions WHERE guild=$guild AND role=$role',
|
||||||
|
{
|
||||||
|
$guild: interaction.guildId,
|
||||||
|
$role: role
|
||||||
|
})
|
||||||
|
|
||||||
|
const permissions = {
|
||||||
|
create: Boolean(interaction.options.get('create_permission')?.value),
|
||||||
|
delete: Boolean(interaction.options.get('delete_permission')?.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
await execute('INSERT INTO permissions (guild, role, permissions) VALUES($guild, $role, $permissions)',
|
||||||
|
{
|
||||||
|
$guild: interaction.guildId,
|
||||||
|
$role: role,
|
||||||
|
$permissions: obj2role(permissions)
|
||||||
|
})
|
||||||
|
|
||||||
|
const statusUpdate = new EmbedBuilder()
|
||||||
|
.setColor(0x0099FF)
|
||||||
|
.setTitle('Role updated successfully')
|
||||||
|
.addFields(
|
||||||
|
{ name: 'Role', value: `<@&${role.toString()}>` },
|
||||||
|
{ name: 'Can add goobs', value: permissions.create ? '🟩' : '🟥', inline: true },
|
||||||
|
{ name: 'Can delete goobs', value: permissions.delete ? '🟩' : '🟥', inline: true }
|
||||||
|
)
|
||||||
|
.setTimestamp()
|
||||||
|
await interaction.reply({ embeds: [statusUpdate], ephemeral: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
-2
@@ -1,9 +1,35 @@
|
|||||||
import { verbose } from 'sqlite3'
|
import { verbose } from 'sqlite3'
|
||||||
const sqlite = verbose()
|
const sqlite = verbose()
|
||||||
const db = new sqlite.Database('goobers')
|
const db = new sqlite.Database('goobers.db')
|
||||||
|
|
||||||
|
export async function execute (query: string, args = {} as any): Promise<any[]> {
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
db.all(query, args, (err: string, rows: any) => {
|
||||||
|
if (err !== null) {
|
||||||
|
reject(err)
|
||||||
|
console.error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(rows)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
db.serialize(() => {
|
db.serialize(() => {
|
||||||
db.run('CREATE TABLE IF NOT EXISTS goob (url TEXT UNIQUE)')
|
db.run('CREATE TABLE IF NOT EXISTS goob (id INTEGER PRIMARY KEY AUTOINCREMENT, messageid TEXT, guild TEXT, channel TEXT, url TEXT NOT NULL UNIQUE)')
|
||||||
|
db.run('CREATE TABLE IF NOT EXISTS tracked (guild TEXT UNIQUE, last_message TEXT, channel TEXT)')
|
||||||
|
db.run('CREATE TABLE IF NOT EXISTS permissions (guild TEXT NOT NULL, role TEXT NOT NULL, permissions INTEGER, PRIMARY KEY (guild, role))')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export function role2obj (role: number): { create: boolean, delete: boolean } {
|
||||||
|
return {
|
||||||
|
create: Boolean(role & 1),
|
||||||
|
delete: Boolean(role & 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function obj2role (role: ReturnType<typeof role2obj>): number {
|
||||||
|
return Number(role.create) | (Number(role.delete) * 2)
|
||||||
|
}
|
||||||
|
|
||||||
export default db
|
export default db
|
||||||
|
|||||||
+2
-2
@@ -9,13 +9,12 @@ const commands = [] as SlashCommand[]
|
|||||||
const commandsPath = path.join(__dirname, 'commands')
|
const commandsPath = path.join(__dirname, 'commands')
|
||||||
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'))
|
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'))
|
||||||
|
|
||||||
console.log(commandFiles)
|
|
||||||
const promises = [] as Array<Promise<void>>
|
const promises = [] as Array<Promise<void>>
|
||||||
for (const file of commandFiles) {
|
for (const file of commandFiles) {
|
||||||
const filePath = path.join(commandsPath, file)
|
const filePath = path.join(commandsPath, file)
|
||||||
promises.push(import(filePath).then(({ default: command }) => {
|
promises.push(import(filePath).then(({ default: command }) => {
|
||||||
if ('data' in command && 'execute' in command) {
|
if ('data' in command && 'execute' in command) {
|
||||||
commands.push(command)
|
commands.push(command.data.toJSON())
|
||||||
} else {
|
} else {
|
||||||
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`)
|
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`)
|
||||||
}
|
}
|
||||||
@@ -36,6 +35,7 @@ void Promise.all(promises).then(async () => {
|
|||||||
const data = await rest.put(
|
const data = await rest.put(
|
||||||
Routes.applicationGuildCommands(discord_app_id, discord_guild_id),
|
Routes.applicationGuildCommands(discord_app_id, discord_guild_id),
|
||||||
{ body: commands }
|
{ body: commands }
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(`Successfully reloaded ${(data as string[]).length} application (/) commands.`)
|
console.log(`Successfully reloaded ${(data as string[]).length} application (/) commands.`)
|
||||||
|
|||||||
+2
-1
@@ -104,5 +104,6 @@
|
|||||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"exclude": ["jest.config.ts", "./tests"]
|
"exclude": ["jest.config.ts", "./tests"],
|
||||||
|
"include": ["./src"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user