Message content changes and message deletions are now tracked

This commit is contained in:
Bradley Bickford 2025-06-29 09:28:03 -04:00
parent ac2dd9983e
commit c570f57463
6 changed files with 75 additions and 22 deletions

Binary file not shown.

View File

@ -21,9 +21,8 @@ if (config.DB_MODE == "sqlite") {
db.run("PRAGMA foreign_keys = ON") db.run("PRAGMA foreign_keys = ON")
utilities.tables.makeTables(db) utilities.tables.makeTables(db)
utilities.tables.makeConstraints(db)
//I really don't want this to be here. //TODO I really don't want this to be here.
utilities.events.messages.setupMessageCapture(client, db) utilities.events.messages.setupMessageCapture(client, db)
} }

View File

@ -1,8 +1,10 @@
import { Message, OmitPartialGroupDMChannel } from "discord.js"; import { Message, OmitPartialGroupDMChannel, PartialMessage } from "discord.js";
import { SQLCommon } from "../storage/interfaces"; import { SQLCommon } from "../storage/interfaces";
import { SQLResult } from "../storage/enumerations"; import { SQLResult } from "../storage/enumerations";
export async function doesMessageExist(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>>) : Promise<boolean> { // TODO Do partial messages affect other functionality elsewhere?
export async function doesMessageExist(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) : Promise<boolean> {
const queryResult: Object[] = await db.getAllParameterized( const queryResult: Object[] = await db.getAllParameterized(
"SELECT * FROM messages WHERE message_snowflake = ?", "SELECT * FROM messages WHERE message_snowflake = ?",
[message.id] [message.id]
@ -32,3 +34,47 @@ export async function insertMessage(db: SQLCommon, message: OmitPartialGroupDMCh
return SQLResult.FAILED return SQLResult.FAILED
} }
} }
export async function updateMessageContentHistory(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>>) : Promise<SQLResult> {
const messageIDExists: boolean = await doesMessageExist(db, message)
if(!messageIDExists) {
return SQLResult.FAILED
}
try {
await db.runParameterized(
"INSERT INTO message_content_changes (message_snowflake, message_change_old_timestamp, message_change_old_content) " +
"SELECT message_snowflake, message_timestamp, message_content FROM messages WHERE message_snowflake = ?;" +
"UPDATE messages SET message_timestamp = ?, message_content = ? WHERE message_snowflake = ?;",
[message.id, message.editedTimestamp, message.content, message.id]
)
return SQLResult.UPDATED
} catch (err) {
//TODO Winston should handle this
console.log(err)
return SQLResult.FAILED
}
}
export async function markMessageDeleted(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) : Promise<SQLResult> {
const messageIDExists: boolean = await doesMessageExist(db, message)
if(!messageIDExists) {
return SQLResult.FAILED
}
try {
await db.runParameterized(
"UPDATE messages SET message_deleted = 1 WHERE message_snowflake = ?",
[message.id]
)
return SQLResult.UPDATED
} catch (err) {
// TODO Winston should handle this
console.log(err)
return SQLResult.FAILED
}
}

View File

@ -1,14 +1,22 @@
import { Client, Events, Message, OmitPartialGroupDMChannel } from "discord.js"; import { Client, Events, Message, messageLink, OmitPartialGroupDMChannel, PartialMessage } from "discord.js";
import { SQLResult } from "../storage/enumerations"; import { SQLResult } from "../storage/enumerations";
import { SQLCommon } from "../storage/interfaces"; import { SQLCommon } from "../storage/interfaces";
import { insertChannel } from "../discord/channels"; import { insertChannel } from "../discord/channels";
import { insertUser } from "../discord/users"; import { insertUser } from "../discord/users";
import { insertMessage } from "../discord/messages"; import { doesMessageExist, insertMessage, markMessageDeleted, updateMessageContentHistory } from "../discord/messages";
export function setupMessageCapture(client: Client, db: SQLCommon) { export function setupMessageCapture(client: Client, db: SQLCommon) {
client.on(Events.MessageCreate, async (message) => { client.on(Events.MessageCreate, async (message) => {
processMessageCreate(db, message) processMessageCreate(db, message)
}) })
client.on(Events.MessageUpdate, async (oldMessage, newMessage) => {
await processMessageModify(db, newMessage)
})
client.on(Events.MessageDelete, async (deletedMessage) => {
await processMessageDeleted(db, deletedMessage)
})
} }
async function processMessageCreate(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>>) { async function processMessageCreate(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>>) {
@ -21,3 +29,11 @@ async function processMessageCreate(db: SQLCommon, message: OmitPartialGroupDMCh
await insertMessage(db, message) await insertMessage(db, message)
} }
} }
async function processMessageModify(db: SQLCommon, newMessage: OmitPartialGroupDMChannel<Message<boolean>>) {
await updateMessageContentHistory(db, newMessage)
}
async function processMessageDeleted(db: SQLCommon, deletedMessage: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) {
await markMessageDeleted(db, deletedMessage)
}

View File

@ -11,17 +11,13 @@ export class SqliteDB implements SQLCommon {
async run(query: string): Promise<number> { async run(query: string): Promise<number> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.db.run(query, (result : sqlite3.RunResult, err: Error) => { this.db.run(query, function (this : sqlite3.RunResult, err: Error) {
if (err) { if (err) {
// TODO Winston should handle this // TODO Winston should handle this
console.log(err) console.log(err)
throw err throw err
} else { } else {
if (result != null) { resolve(this.changes)
resolve(result.changes)
} else {
resolve(0)
}
} }
}) })
}) })
@ -29,17 +25,13 @@ export class SqliteDB implements SQLCommon {
async runParameterized(query: string, parameters: any[]): Promise<number> { async runParameterized(query: string, parameters: any[]): Promise<number> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.db.run(query, parameters, (result : sqlite3.RunResult, err: Error) => { this.db.run(query, parameters, function (this : sqlite3.RunResult, err: Error) {
if (err) { if (err) {
// TODO Winston should handle this // TODO Winston should handle this
console.log(err) console.log(err)
throw err throw err
} else { } else {
if (result != null) { resolve(this.changes)
resolve(result.changes)
} else {
resolve(0)
}
} }
}) })
}) })

View File

@ -2,10 +2,10 @@ import { SQLCommon } from "./interfaces";
const tables: string[] = [ 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 servers (server_snowflake bigint NOT NULL PRIMARY KEY,server_name text NOT NULL,server_description mediumtext);",
"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 IF NOT EXISTS 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 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 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_content_changes (message_change_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,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);" "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);"
] ]