From ac2dd9983e1d4ae3cd62a96a9db45b5804deaf62 Mon Sep 17 00:00:00 2001 From: Bradley Bickford Date: Fri, 27 Jun 2025 22:49:09 -0400 Subject: [PATCH] Basic message collection is working again --- breadbot_test.db | Bin 45056 -> 53248 bytes src/breadbot.ts | 8 ++++++- src/utilties/discord/channels.ts | 35 +++++++++++++++++++++++-------- src/utilties/discord/messages.ts | 34 ++++++++++++++++++++++++++++++ src/utilties/discord/users.ts | 33 +++++++++++++++++++++++++++++ src/utilties/events/messages.ts | 23 ++++++++++++++++++++ src/utilties/index.ts | 10 ++++++++- src/utilties/storage/tables.ts | 3 ++- 8 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 src/utilties/discord/messages.ts create mode 100644 src/utilties/discord/users.ts create mode 100644 src/utilties/events/messages.ts diff --git a/breadbot_test.db b/breadbot_test.db index c7e3fc301f164374c81911d9a90c3dd8fe06792e..5dbfce211089df3cfa41d165b72a9361d03dd293 100644 GIT binary patch literal 53248 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 delta 791 zcmYk2Ur19?9LLYS*By87-8sK)Vw+CgozrwRLLK%8-JKdFGE<3y{z&uY?l83}Q>X}< z$q2Hr;=EW-5m7|G*zmn%4-p9U7Co2*5&e1Sp@%?-&i;i5&f)Xr`}_U)o$taUX<=Ku z=W)0ZLMp%IW4Rv;`P}G0>M?;oNKphtqp(IU&|2F=5>mTtQAJRdtV6pYON&@$uW6m2 zur2zXzjtXJ`vT7Fsu~dGPN~vWUoR|%*%nDL0&;V3e8Na3&FNUuxMXVc=9PJEX!xWy zbZT%gcyTT^KanzxI7`zWaa>@M(jkc1gG#$#5wYt`h;4$G-Bx|F#5c9(w|zNVp|v{6 z5`xe02A)6~;&2!gx=q*V3Z0?@w1pD#le{A@$P!=pJi%V41!Et38}VSjgJXaVM7+4x z&e6qYB73kG3I*T79?eZTR$1x#pt~p6HcGDDG(U-B-Qz}FBi!+`XOVhr%ahDTbr0UJ zaz4VY>n(nd!m-9`U+znE<+T5;#$_WFp9{#`>}0EYGj6qV46!!72?r}VcCo*DE8d4W z9%AY6USExcV>KTXq23%yly?|NCT9E<+zPM{x)(P}99x*GH^ki{$0}>7FkEgpcH(HA zz#UJ)*%4=F%1*zTG*ia3!t->33&B^|gx~NHT%f~gh(bFw!7IqZQ+NP(c*H3%d6Yls zahrq%KIB$x5p_88!oD1SG?^JmICcrsUMhROvw^xHFUon+lCxI5G1kE1!;R@eR!XtE zFWR4J>z9k7cV#Mv&RUD2=htKgDV0SLd4Dd0LbxOf8Cmk8^gF$xB(C=M*^#u%35%+P R<$PHo4E}o|YZ=*z{R5V*yUqXr diff --git a/src/breadbot.ts b/src/breadbot.ts index 2d7ab8f..c24cba1 100644 --- a/src/breadbot.ts +++ b/src/breadbot.ts @@ -8,7 +8,8 @@ export const client : Client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, - GatewayIntentBits.DirectMessages + GatewayIntentBits.GuildMembers, + GatewayIntentBits.MessageContent ] }) @@ -21,6 +22,9 @@ if (config.DB_MODE == "sqlite") { utilities.tables.makeTables(db) utilities.tables.makeConstraints(db) + + //I really don't want this to be here. + utilities.events.messages.setupMessageCapture(client, db) } client.once(Events.ClientReady, () => { @@ -58,4 +62,6 @@ client.on(Events.InteractionCreate, async (interaction: Interaction) => { } }) + + client.login(config.DISCORD_TOKEN) \ No newline at end of file diff --git a/src/utilties/discord/channels.ts b/src/utilties/discord/channels.ts index ebc340f..af6b482 100644 --- a/src/utilties/discord/channels.ts +++ b/src/utilties/discord/channels.ts @@ -1,17 +1,26 @@ import { SQLCommon } from "../storage/interfaces"; -import { GuildBasedChannel } from "discord.js"; +import { DMChannel, GuildBasedChannel, PartialDMChannel } from "discord.js"; import { SQLResult } from "../storage/enumerations"; -export async function doesChannelExist(db: SQLCommon, channel : GuildBasedChannel) : Promise { +export async function doesChannelExistByID(db: SQLCommon, channelID: string) : Promise { const queryResult : Object[] = await db.getAllParameterized( - "SELECT * FROM channels WHERE server_snowflake = ? AND channel_snowflake = ?", - [channel.guild.id, channel.id] + "SELECT * FROM channels WHERE channel_snowflake = ?", + [channelID] ) return queryResult.length != 0 } -export async function insertChannel(db: SQLCommon, channel: GuildBasedChannel) : Promise { +export async function doesChannelExist(db: SQLCommon, channel : GuildBasedChannel | DMChannel | PartialDMChannel) : Promise { + const queryResult : Object[] = await db.getAllParameterized( + "SELECT * FROM channels WHERE channel_snowflake = ?", + [channel.id] + ) + + return queryResult.length != 0 +} + +export async function insertChannel(db: SQLCommon, channel: GuildBasedChannel | DMChannel | PartialDMChannel) : Promise { const alreadyExists: boolean = await doesChannelExist(db, channel) if(alreadyExists) { @@ -19,10 +28,18 @@ export async function insertChannel(db: SQLCommon, channel: GuildBasedChannel) : } try { - await db.runParameterized( - "INSERT INTO channels VALUES (?, ?, ?, ?)", - [channel.id, channel.guild.id, channel.name, channel.isThread()] - ) + if (channel.isDMBased()) { + await db.runParameterized( + "INSERT INTO channels VALUES (?, ?, ?, ?, ?)", + [channel.id, null, channel.recipient?.username, channel.isThread(), channel.isDMBased()] + ) + } else { + await db.runParameterized( + "INSERT INTO channels VALUES (?, ?, ?, ?, ?)", + [channel.id, channel.guild.id, channel.name, channel.isThread(), channel.isDMBased()] + ) + } + return SQLResult.CREATED } catch (err) { diff --git a/src/utilties/discord/messages.ts b/src/utilties/discord/messages.ts new file mode 100644 index 0000000..fe01049 --- /dev/null +++ b/src/utilties/discord/messages.ts @@ -0,0 +1,34 @@ +import { Message, OmitPartialGroupDMChannel } from "discord.js"; +import { SQLCommon } from "../storage/interfaces"; +import { SQLResult } from "../storage/enumerations"; + +export async function doesMessageExist(db: SQLCommon, message: OmitPartialGroupDMChannel>) : Promise { + const queryResult: Object[] = await db.getAllParameterized( + "SELECT * FROM messages WHERE message_snowflake = ?", + [message.id] + ) + + return queryResult.length != 0 +} + +export async function insertMessage(db: SQLCommon, message: OmitPartialGroupDMChannel>) : Promise { + const alreadyExists: boolean = await doesMessageExist(db, message) + + if(alreadyExists) { + return SQLResult.ALREADYEXISTS + } + + try { + await db.runParameterized( + "INSERT INTO messages VALUES (?, ?, ?, ?, ?, ?)", + [message.id, message.channel.id, message.author.id, + message.content, message.createdTimestamp, 0] + ) + + return SQLResult.CREATED + } catch (err) { + //TODO Winston should handle this + console.log(err) + return SQLResult.FAILED + } +} \ No newline at end of file diff --git a/src/utilties/discord/users.ts b/src/utilties/discord/users.ts new file mode 100644 index 0000000..c8a0694 --- /dev/null +++ b/src/utilties/discord/users.ts @@ -0,0 +1,33 @@ +import { User } from "discord.js"; +import { SQLCommon } from "../storage/interfaces"; +import { SQLResult } from "../storage/enumerations"; + +export async function doesUserExist(db: SQLCommon, user: User): Promise { + const queryResult: Object[] = await db.getAllParameterized( + "SELECT * FROM users WHERE user_snowflake = ?", + [user.id] + ) + + return queryResult.length != 0 +} + +export async function insertUser(db: SQLCommon, user: User): Promise { + const alreadyExists: boolean = await doesUserExist(db, user) + + if(alreadyExists) { + return SQLResult.ALREADYEXISTS + } + + try { + await db.runParameterized( + "INSERT INTO users VALUES (?, ?, ?)", + [user.id, user.username, user.displayName] + ) + + return SQLResult.CREATED + } catch (err) { + //TODO Winston should handle this + console.log(err) + return SQLResult.FAILED + } +} \ No newline at end of file diff --git a/src/utilties/events/messages.ts b/src/utilties/events/messages.ts new file mode 100644 index 0000000..d9ed299 --- /dev/null +++ b/src/utilties/events/messages.ts @@ -0,0 +1,23 @@ +import { Client, Events, Message, OmitPartialGroupDMChannel } from "discord.js"; +import { SQLResult } from "../storage/enumerations"; +import { SQLCommon } from "../storage/interfaces"; +import { insertChannel } from "../discord/channels"; +import { insertUser } from "../discord/users"; +import { insertMessage } from "../discord/messages"; + +export function setupMessageCapture(client: Client, db: SQLCommon) { + client.on(Events.MessageCreate, async (message) => { + processMessageCreate(db, message) + }) +} + +async function processMessageCreate(db: SQLCommon, message: OmitPartialGroupDMChannel>) { + const channelOk: SQLResult = await insertChannel(db, message.channel) + const userOk: SQLResult = await insertUser(db, message.author) + + if (channelOk == SQLResult.ALREADYEXISTS || channelOk == SQLResult.CREATED || + userOk == SQLResult.ALREADYEXISTS || userOk == SQLResult.CREATED) { + + await insertMessage(db, message) + } +} \ No newline at end of file diff --git a/src/utilties/index.ts b/src/utilties/index.ts index 6f9e2ca..3c15413 100644 --- a/src/utilties/index.ts +++ b/src/utilties/index.ts @@ -3,11 +3,19 @@ import * as sqlite from "./storage/sqlite" import * as tables from "./storage/tables" import * as guilds from "./discord/guilds" import * as channels from "./discord/channels" +import * as users from "./discord/users" +import * as messages from "./events/messages" + +const events = { + messages +} export const utilities = { commands, sqlite, tables, guilds, - channels + channels, + users, + events } \ No newline at end of file diff --git a/src/utilties/storage/tables.ts b/src/utilties/storage/tables.ts index ddb07fb..1d87112 100644 --- a/src/utilties/storage/tables.ts +++ b/src/utilties/storage/tables.ts @@ -2,7 +2,8 @@ import { SQLCommon } from "./interfaces"; const tables: string[] = [ "CREATE TABLE IF NOT EXISTS servers (server_snowflake bigint NOT NULL PRIMARY KEY,server_name text NOT NULL,server_description mediumtext);", - "CREATE TABLE IF NOT EXISTS channels (channel_snowflake bigint NOT NULL PRIMARY KEY,server_snowflake bigint NOT NULL,channel_name text NOT NULL,is_thread bit NOT NULL);", + "CREATE TABLE channels (channel_snowflake bigint NOT NULL PRIMARY KEY,server_snowflake bigint,channel_name text,is_thread bit NOT NULL,is_dm bit NOT NULL);", + "CREATE TABLE users (user_snowflake bigint NOT NULL PRIMARY KEY,user_name text NOT NULL,user_displayname text);", "CREATE TABLE IF NOT EXISTS messages (message_snowflake bigint NOT NULL PRIMARY KEY,channel_snowflake bigint NOT NULL,user_snowflake bigint NOT NULL,message_content longtext NOT NULL,message_timestamp datetime NOT NULL,message_deleted bit NOT NULL);", "CREATE TABLE IF NOT EXISTS message_content_changes (message_change_id bigint NOT NULL PRIMARY KEY,message_snowflake bigint NOT NULL,message_change_old_timestamp datetime NOT NULL,message_change_old_content longtext NOT NULL);", "CREATE TABLE IF NOT EXISTS message_attachments (attachment_snowflake bigint NOT NULL PRIMARY KEY,message_snowflake bigint NOT NULL,attachment_name text NOT NULL,attachment_description text,attachment_timestamp datetime NOT NULL,attachment_mime_type text,attachment_url text NOT NULL,attachment_downloaded bit NOT NULL);"