diff --git a/src/commands/checkperms.ts b/src/commands/checkperms.ts index 9cfe42b..0e9653f 100644 --- a/src/commands/checkperms.ts +++ b/src/commands/checkperms.ts @@ -2,7 +2,7 @@ import { type CommandInteraction, SlashCommandBuilder, EmbedBuilder, type GuildMember } from 'discord.js' -import { execute, role2obj } from '../db' +import { getMemberPermissionsRaw } from '../db' module.exports = { data: new SlashCommandBuilder() @@ -11,7 +11,7 @@ module.exports = { option .setName('user') .setDescription('The user to check the roles of') - .setRequired(true)) + .setRequired(false)) .setDescription('Check permission of an user for goobot'), async execute (interaction: CommandInteraction) { if (interaction.guild === null) { @@ -26,21 +26,16 @@ module.exports = { return } - const allPermissions = await execute('SELECT * FROM permissions WHERE guild=$guild', { $guild: interaction.guildId }) as Array<{ guild: string, role: string, permissions: number }> - console.log(allPermissions) - const userPermsBitField = allPermissions.reduce((acc, val) => - member?.roles.cache.some(r => r.id === val.role.toString()) === true ? acc | val.permissions : acc - , 0) - - const permissions = role2obj(userPermsBitField) + const permissions = await getMemberPermissionsRaw(member) const statusUpdate = new EmbedBuilder() .setColor(0x0099FF) .setTitle('List of roles') .setTimestamp() .addFields( { name: 'User', value: `<@${member.id}>` }, - { name: 'Can add goobs', value: permissions.create ? '🟩' : '🟥', inline: true }, - { name: 'Can delete goobs', value: permissions.delete ? '🟩' : '🟥', inline: true } + { name: 'Can add goobs', value: `${permissions.create > 0 ? '🟩' : '🟥'} (${permissions.create})`, inline: true }, + { name: 'Can delete goobs', value: `${permissions.delete > 0 ? '🟩' : '🟥'} (${permissions.delete})`, inline: true }, + { name: 'Can read goobs', value: `${permissions.read > 0 ? '🟩' : '🟥'} (${permissions.read})`, inline: true } ) await interaction.reply({ embeds: [statusUpdate], ephemeral: true }) diff --git a/src/commands/checkroles.ts b/src/commands/checkroles.ts index 7dbeb0b..db9f5cb 100644 --- a/src/commands/checkroles.ts +++ b/src/commands/checkroles.ts @@ -2,7 +2,7 @@ import { type CommandInteraction, SlashCommandBuilder, EmbedBuilder, PermissionsBitField } from 'discord.js' -import { execute, role2obj } from '../db' +import { execute, type PermsNumbers } from '../db' module.exports = { data: new SlashCommandBuilder() @@ -19,7 +19,7 @@ module.exports = { return } - const permissionList = await execute('SELECT * FROM permissions') as Array<{ guild: string, role: string, permissions: number }> + const permissionList = await execute('SELECT * FROM permissions') as Array<{ guild: string, role: string } & PermsNumbers> const statusUpdate = new EmbedBuilder() .setColor(0x0099FF) @@ -27,12 +27,11 @@ module.exports = { .setTimestamp() permissionList.forEach(e => { - const permissions = role2obj(e.permissions) - statusUpdate.addFields( { name: 'Role', value: `<@&${e.role.toString()}>` }, - { name: 'Can add goobs', value: permissions.create ? '🟩' : '🟥', inline: true }, - { name: 'Can delete goobs', value: permissions.delete ? '🟩' : '🟥', inline: true } + { name: 'Can add goobs', value: `${e.create > 0 ? '🟩' : '🟥'} (${e.create})`, inline: true }, + { name: 'Can delete goobs', value: `${e.delete > 0 ? '🟩' : '🟥'} (${e.delete})`, inline: true }, + { name: 'Can read goobs', value: `${e.read > 0 ? '🟩' : '🟥'} (${e.read})`, inline: true } ) }) await interaction.reply({ embeds: [statusUpdate], ephemeral: true }) diff --git a/src/commands/load.ts b/src/commands/load.ts index cb410dc..619dba2 100644 --- a/src/commands/load.ts +++ b/src/commands/load.ts @@ -4,9 +4,9 @@ import { type Message } from 'discord.js' import { owner_id } from '../config.json' -import db from '../db' +import db, { checkMemberPermissions } from '../db' -function insertGoob (message: Message): void { +function insertGoob (message: Message): number { const attachments = message.attachments.filter( (e) => e.contentType !== null && @@ -30,6 +30,7 @@ function insertGoob (message: Message): void { })) if (attachments.size > 0 || embeds.length > 0) void message.react('📥') + return attachments.size + embeds.length } module.exports = { @@ -62,7 +63,7 @@ module.exports = { }) let loaded = 0 - const loadedImages = 0 + let loadedImages = 0 let messages = await interaction.channel?.messages .fetch() .catch(console.error) @@ -76,26 +77,17 @@ module.exports = { ) while (messages !== undefined && messages.size > 0) { - (messages as unknown as Message[]) - .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); + const permissionFilter = await Promise.all((messages as unknown as Message[]).map(async e => { + if (e.member === null) throw new Error('member is null') + return (await checkMemberPermissions(e.member)).create + })) - (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 filteredMessages = (messages as unknown as Message[]).map(e => e).filter((e, i) => permissionFilter[i] && !e.author.bot) + + console.log(filteredMessages) + // parses the messages + // shenanigans to save goobs into the database + loadedImages += filteredMessages.map(insertGoob).reduce((acc, v) => v + acc, 0) const lastmessage = messages.last() as Message | undefined if (lastmessage === undefined) { diff --git a/src/commands/setrole.ts b/src/commands/setrole.ts index 410fb35..3685c92 100644 --- a/src/commands/setrole.ts +++ b/src/commands/setrole.ts @@ -1,8 +1,8 @@ import { type CommandInteraction, - SlashCommandBuilder, EmbedBuilder, PermissionsBitField + SlashCommandBuilder, PermissionsBitField } from 'discord.js' -import { execute, obj2role } from '../db' +import { execute } from '../db' module.exports = { data: new SlashCommandBuilder() @@ -13,15 +13,20 @@ module.exports = { .setName('role') .setDescription('The role') .setRequired(true)) - .addBooleanOption(option => + .addIntegerOption(option => option .setName('delete_permission') .setDescription('Permission to delete goobs') .setRequired(true)) - .addBooleanOption(option => + .addIntegerOption(option => option .setName('create_permission') .setDescription('Permission to add goobs') + .setRequired(true)) + .addIntegerOption(option => + option + .setName('read_permission') + .setDescription('Permission to run the goob command') .setRequired(true)), async execute (interaction: CommandInteraction) { /* const totalweight = (await execute('SELECT SUM(weight) as totalweight from goob'))[0].totalweight @@ -45,26 +50,20 @@ module.exports = { }) const permissions = { - create: Boolean(interaction.options.get('create_permission')?.value), - delete: Boolean(interaction.options.get('delete_permission')?.value) + create: interaction.options.get('create_permission')?.value as number, + delete: interaction.options.get('delete_permission')?.value as number, + read: interaction.options.get('read_permission')?.value as number } - await execute('INSERT INTO permissions (guild, role, permissions) VALUES($guild, $role, $permissions)', + await execute('INSERT INTO permissions (guild, role, \'create\', \'read\', \'delete\') VALUES($guild, $role, $create, $read, $delete)', { $guild: interaction.guildId, $role: role, - $permissions: obj2role(permissions) + $create: permissions.create, + $read: permissions.read, + $delete: permissions.delete }) - 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 }) + await interaction.client.commands.get('checkroles')?.execute(interaction) } } diff --git a/src/db/index.ts b/src/db/index.ts index 206c3a4..1d9e942 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,3 +1,4 @@ +import { Guild, type GuildMember } from 'discord.js' import { verbose } from 'sqlite3' const sqlite = verbose() const db = new sqlite.Database('goobers.db') @@ -18,18 +19,31 @@ export async function execute (query: string, args = {} as any): Promise db.serialize(() => { 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))') + db.run('CREATE TABLE IF NOT EXISTS permissions (guild TEXT NOT NULL, role TEXT NOT NULL, \'create\' INTEGER DEFAULT 0, \'delete\' INTEGER DEFAULT 0, \'read\' INTEGER DEFAULT 1, PRIMARY KEY (guild, role))') }) -export function role2obj (role: number): { create: boolean, delete: boolean } { +export interface PermsNumbers { create: number, read: number, delete: number } +export interface Perms { create: boolean, delete: boolean, read: boolean } + +export async function getMemberPermissionsRaw (member: GuildMember): Promise { + const allPermissions = await execute('SELECT * FROM permissions WHERE guild=$guild', { $guild: member.guild.id }) as Array + const userPerms = allPermissions.reduce((acc, val) => { + if (!member?.roles.cache.some(r => r.id === val.role.toString())) return acc + return { + create: acc.create + val.create, + read: acc.read + val.read, + delete: acc.delete + val.delete + } + }, { create: 0, read: 0, delete: 0 }) + return userPerms +} + +export async function checkMemberPermissions (member: GuildMember): Promise { + const userPerms = await getMemberPermissionsRaw(member) return { - create: Boolean(role & 1), - delete: Boolean(role & 2) + create: userPerms.create > 0, + read: userPerms.read > 0, + delete: userPerms.read > 0 } } - -export function obj2role (role: ReturnType): number { - return Number(role.create) | (Number(role.delete) * 2) -} - export default db