DB Storage Re-engineering #1
@ -11,13 +11,25 @@ import { insertChannel } from "./utilties/discord/channels"
|
||||
import { insertRole } from "./utilties/discord/roles"
|
||||
import { setupRoleCapture } from "./utilties/events/roles"
|
||||
import { DBUser } from "./utilties/storage/entities/DBUser"
|
||||
import { DBMessage } from "./utilties/storage/entities/DBMessage"
|
||||
import { DBMessageContentChanges } from "./utilties/storage/entities/DBMessageContentChanges"
|
||||
import { DBMessageAttachments } from "./utilties/storage/entities/DBMessageAttachment"
|
||||
import { setupMessageCapture } from "./utilties/events/messages"
|
||||
|
||||
console.log(__dirname + path.sep + "utilities" + path.sep + "storage" + path.sep + "entities" + path.sep + "*.ts")
|
||||
|
||||
export const dataSource = new DataSource({
|
||||
type: "sqlite",
|
||||
database: "breadbot.db",
|
||||
entities: [DBServer, DBChannel, DBRole, DBUser],
|
||||
entities: [
|
||||
DBServer,
|
||||
DBChannel,
|
||||
DBRole,
|
||||
DBUser,
|
||||
DBMessage,
|
||||
DBMessageContentChanges,
|
||||
DBMessageAttachments
|
||||
],
|
||||
synchronize: true,
|
||||
logging: true
|
||||
})
|
||||
@ -38,6 +50,10 @@ client.once(Events.ClientReady, async () => {
|
||||
const serverRepo = dataSource.getRepository(DBServer)
|
||||
const channelRepo = dataSource.getRepository(DBChannel)
|
||||
const roleRepo = dataSource.getRepository(DBRole)
|
||||
const userRepo = dataSource.getRepository(DBUser)
|
||||
const messageRepo = dataSource.getRepository(DBMessage)
|
||||
const mccRepo = dataSource.getRepository(DBMessageContentChanges)
|
||||
const maRepo = dataSource.getRepository(DBMessageAttachments)
|
||||
|
||||
client.guilds.cache.forEach(async (guild: Guild) => {
|
||||
const server: DBServer | null = await insertGuild(serverRepo, guild)
|
||||
@ -54,6 +70,7 @@ client.once(Events.ClientReady, async () => {
|
||||
})
|
||||
|
||||
setupRoleCapture(client, serverRepo, roleRepo)
|
||||
setupMessageCapture(client, channelRepo, userRepo, messageRepo, mccRepo, maRepo)
|
||||
|
||||
console.log("Breadbot is Ready")
|
||||
})
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
// @ts-nocheck
|
||||
import { ChannelType, ChatInputCommandInteraction, CommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { breadthreadEnsureAutoLock, breadthreadRemoveAutoLock } from "../utilties/breadbot/breadthread";
|
||||
import { db } from "../breadbot";
|
||||
import { timeShorthandToSeconds } from "../utilties/time/conversions";
|
||||
|
||||
export const enabled: boolean = true
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName("breadthread")
|
||||
.setDescription("Manages Breadbot's extended thread features")
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName("autolock")
|
||||
.setDescription("Enables auto locking of a thread after a period of thread inactivity")
|
||||
.addChannelOption(option =>
|
||||
option
|
||||
.setName("channel")
|
||||
.setDescription("The name of the thread you want to autolock")
|
||||
.addChannelTypes(
|
||||
ChannelType.PublicThread,
|
||||
ChannelType.PrivateThread,
|
||||
ChannelType.AnnouncementThread
|
||||
)
|
||||
.setRequired(true)
|
||||
)
|
||||
.addBooleanOption(option =>
|
||||
option
|
||||
.setName("enable")
|
||||
.setDescription("Enable or disable the auto locking")
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName("timeinactive")
|
||||
.setDescription("How long the thread needs to be inactive before locking, default is 3 days")
|
||||
.setRequired(false)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
export async function execute(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply({flags: MessageFlags.Ephemeral})
|
||||
|
||||
if(interaction.options.getSubcommand() === "autolock") {
|
||||
if(interaction.options.getBoolean("enable")) {
|
||||
await breadthreadEnsureAutoLock(
|
||||
db,
|
||||
interaction.options.getChannel("channel", true).id,
|
||||
interaction.options.getString("timeinactive") ?? "3d"
|
||||
)
|
||||
} else {
|
||||
await breadthreadRemoveAutoLock(
|
||||
db,
|
||||
interaction.options.getChannel("channel", true).id
|
||||
)
|
||||
}
|
||||
|
||||
await interaction.editReply("Autolock Action OK")
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,7 @@
|
||||
import * as ping from "./ping";
|
||||
import * as breadalert from "./breadalert"
|
||||
import * as breadthread from "./breadthread"
|
||||
|
||||
export const commands = {
|
||||
ping,
|
||||
breadalert,
|
||||
breadthread
|
||||
breadalert
|
||||
}
|
||||
@ -1,118 +1,100 @@
|
||||
import { Attachment, Message, OmitPartialGroupDMChannel, PartialMessage } from "discord.js";
|
||||
import { SQLCommon } from "../storage/interfaces";
|
||||
import { SQLResult } from "../storage/enumerations";
|
||||
import { Repository } from "typeorm";
|
||||
import { DBMessage } from "../storage/entities/DBMessage";
|
||||
import { DBMessageAttachments } from "../storage/entities/DBMessageAttachment";
|
||||
import { DBMessageContentChanges } from "../storage/entities/DBMessageContentChanges";
|
||||
|
||||
// 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(
|
||||
"SELECT * FROM messages WHERE message_snowflake = ?",
|
||||
[message.id]
|
||||
)
|
||||
|
||||
return queryResult.length != 0
|
||||
export async function doesMessageExist(db: Repository<DBMessage>, message: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) : Promise<boolean> {
|
||||
return (await db.findOne({"where": {message_snowflake: message.id}})) != null
|
||||
}
|
||||
|
||||
export async function doesAttachmentExist(db: SQLCommon, attachment: Attachment) : Promise<boolean> {
|
||||
const queryResult: Object[] = await db.getAllParameterized(
|
||||
"SELECT * FROM message_attachments WHERE attachment_snowflake = ?",
|
||||
[attachment.id]
|
||||
)
|
||||
|
||||
return queryResult.length != 0
|
||||
export async function doesAttachmentExist(db: Repository<DBMessageAttachments>, attachment: Attachment) : Promise<boolean> {
|
||||
return (await db.findOne({"where": {attachment_snowflake: attachment.id}})) != null
|
||||
}
|
||||
|
||||
export async function insertMessage(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>>) : Promise<SQLResult> {
|
||||
const alreadyExists: boolean = await doesMessageExist(db, message)
|
||||
export async function insertMessage(messageDB: Repository<DBMessage>, maDB: Repository<DBMessageAttachments>, message: OmitPartialGroupDMChannel<Message<boolean>>) : Promise<DBMessage | null> {
|
||||
const alreadyExists: boolean = await doesMessageExist(messageDB, message)
|
||||
|
||||
if(alreadyExists) {
|
||||
return SQLResult.ALREADYEXISTS
|
||||
return await messageDB.findOne({"where": {message_snowflake: message.id}})
|
||||
}
|
||||
|
||||
try {
|
||||
await db.runParameterized(
|
||||
"INSERT INTO messages VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[message.id, message.channel.id, message.author.id,
|
||||
message.content, message.createdTimestamp, 0]
|
||||
)
|
||||
const newMessage: DBMessage = await messageDB.create({
|
||||
message_snowflake: message.id,
|
||||
channel: {channel_snowflake: message.channel.id},
|
||||
user: {user_snowflake: message.author.id},
|
||||
message_content: message.content,
|
||||
message_timestamp: message.createdAt,
|
||||
attachments: message.attachments.size == 0 ? null : message.attachments.map((attachment: Attachment) => {
|
||||
return maDB.create({
|
||||
attachment_snowflake: attachment.id,
|
||||
message: {message_snowflake: message.id},
|
||||
attachment_name: attachment.name,
|
||||
attachment_description: attachment.description,
|
||||
attachment_timestamp: message.createdAt,
|
||||
attachment_mime_type: attachment.contentType,
|
||||
attachment_url: attachment.url
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return SQLResult.CREATED
|
||||
return await messageDB.save(newMessage)
|
||||
} catch (err) {
|
||||
//TODO Winston should handle this
|
||||
console.log("MESSAGE INSERTION ERROR")
|
||||
console.log(err)
|
||||
return SQLResult.FAILED
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateMessageContentHistory(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>>) : Promise<SQLResult> {
|
||||
const messageIDExists: boolean = await doesMessageExist(db, message)
|
||||
export async function updateMessageContentHistory(messageDB: Repository<DBMessage>, mccDB: Repository<DBMessageContentChanges>,
|
||||
ma: Repository<DBMessageAttachments>, message: OmitPartialGroupDMChannel<Message<boolean>>) : Promise<DBMessage | null> {
|
||||
let dbMessage: DBMessage | null = await messageDB.findOne({"where": {message_snowflake: message.id}})
|
||||
|
||||
if(!messageIDExists) {
|
||||
return SQLResult.FAILED
|
||||
if(dbMessage == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
console.log([message.id, message.editedTimestamp ?? message.createdTimestamp, message.content, message.id])
|
||||
await db.runParameterized(
|
||||
"INSERT INTO message_content_changes (message_snowflake, message_change_old_timestamp, message_change_old_content) " +
|
||||
"SELECT messages.message_snowflake, message_timestamp, message_content FROM messages WHERE message_snowflake = ?;",
|
||||
[message.id]
|
||||
)
|
||||
const contentChange: DBMessageContentChanges = mccDB.create({
|
||||
message: {message_snowflake: message.id},
|
||||
message_change_old_content: dbMessage.message_content,
|
||||
message_change_old_timestamp: dbMessage.message_timestamp
|
||||
})
|
||||
|
||||
await db.runParameterized(
|
||||
"UPDATE messages SET message_timestamp = ?, message_content = ? WHERE message_snowflake = ?;",
|
||||
[message.editedTimestamp ?? message.createdTimestamp, message.content, message.id]
|
||||
)
|
||||
dbMessage.message_content = message.content
|
||||
dbMessage.message_timestamp = message.editedAt ?? message.createdAt
|
||||
|
||||
return SQLResult.UPDATED
|
||||
// TODO This should really be a transaction
|
||||
// TODO Changes to attachments aren't captured
|
||||
return await mccDB.save(contentChange).then(async (dbmcc: DBMessageContentChanges) => {
|
||||
return await messageDB.save(dbMessage)
|
||||
})
|
||||
} catch (err) {
|
||||
//TODO Winston should handle this
|
||||
console.log("MESSAGE MODIFY FAILED")
|
||||
console.log(err)
|
||||
return SQLResult.FAILED
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function markMessageDeleted(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) : Promise<SQLResult> {
|
||||
const messageIDExists: boolean = await doesMessageExist(db, message)
|
||||
export async function markMessageDeleted(db: Repository<DBMessage>, message: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) : Promise<DBMessage | null> {
|
||||
let dbMessage: DBMessage | null = await db.findOne({"where": {message_snowflake: message.id}})
|
||||
|
||||
if(!messageIDExists) {
|
||||
return SQLResult.FAILED
|
||||
if(dbMessage == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
await db.runParameterized(
|
||||
"UPDATE messages SET message_deleted = 1 WHERE message_snowflake = ?",
|
||||
[message.id]
|
||||
)
|
||||
dbMessage.message_deleted = true
|
||||
|
||||
return SQLResult.UPDATED
|
||||
return await db.save(dbMessage)
|
||||
} catch (err) {
|
||||
// TODO Winston should handle this
|
||||
console.log(err)
|
||||
return SQLResult.FAILED
|
||||
}
|
||||
}
|
||||
|
||||
export async function insertAttachment(db: SQLCommon, attachment: Attachment, message: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) : Promise<SQLResult> {
|
||||
const alreadyExists: boolean = await doesAttachmentExist(db, attachment)
|
||||
|
||||
if(alreadyExists) {
|
||||
return SQLResult.ALREADYEXISTS
|
||||
}
|
||||
|
||||
try {
|
||||
await db.runParameterized(
|
||||
"INSERT INTO message_attachments VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
[attachment.id, message.id, attachment.name, attachment.description, message.createdTimestamp,
|
||||
attachment.contentType, attachment.url, 0]
|
||||
)
|
||||
|
||||
return SQLResult.CREATED
|
||||
} catch (err) {
|
||||
// TODO Winston should handle this
|
||||
console.log(err)
|
||||
return SQLResult.FAILED
|
||||
return null
|
||||
}
|
||||
}
|
||||
@ -1,34 +1,30 @@
|
||||
import { User } from "discord.js";
|
||||
import { SQLCommon } from "../storage/interfaces";
|
||||
import { SQLResult } from "../storage/enumerations";
|
||||
import { Repository } from "typeorm";
|
||||
import { DBUser } from "../storage/entities/DBUser";
|
||||
|
||||
export async function doesUserExist(db: SQLCommon, user: User): Promise<boolean> {
|
||||
const queryResult: Object[] = await db.getAllParameterized(
|
||||
"SELECT * FROM users WHERE user_snowflake = ?",
|
||||
[user.id]
|
||||
)
|
||||
|
||||
return queryResult.length != 0
|
||||
export async function doesUserExist(db: Repository<DBUser>, user: User): Promise<boolean> {
|
||||
return (await db.findOne({"where": {user_snowflake: user.id}})) != null
|
||||
}
|
||||
|
||||
export async function insertUser(db: SQLCommon, user: User): Promise<SQLResult> {
|
||||
export async function insertUser(db: Repository<DBUser>, user: User): Promise<DBUser | null> {
|
||||
const alreadyExists: boolean = await doesUserExist(db, user)
|
||||
|
||||
if(alreadyExists) {
|
||||
return SQLResult.ALREADYEXISTS
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
await db.runParameterized(
|
||||
"INSERT INTO users VALUES (?, ?, ?)",
|
||||
[user.id, user.username, user.displayName]
|
||||
)
|
||||
const newUser: DBUser = db.create({
|
||||
user_snowflake: user.id,
|
||||
user_name: user.username,
|
||||
user_displayname: user.displayName
|
||||
})
|
||||
|
||||
return SQLResult.CREATED
|
||||
return await db.save(newUser)
|
||||
} catch (err) {
|
||||
//TODO Winston should handle this
|
||||
console.log("USER INSERT ERROR")
|
||||
console.log(err)
|
||||
return SQLResult.FAILED
|
||||
return null
|
||||
}
|
||||
}
|
||||
@ -1,64 +1,57 @@
|
||||
// @ts-nocheck
|
||||
import { Client, Events, Message, OmitPartialGroupDMChannel, PartialMessage } from "discord.js";
|
||||
import { SQLResult } from "../storage/enumerations";
|
||||
import { SQLCommon } from "../storage/interfaces";
|
||||
import { insertChannel } from "../discord/channels";
|
||||
import { insertUser } from "../discord/users";
|
||||
import { insertAttachment, insertMessage, markMessageDeleted, updateMessageContentHistory } from "../discord/messages";
|
||||
import { insertMessage, markMessageDeleted, updateMessageContentHistory } from "../discord/messages";
|
||||
import { Repository } from "typeorm";
|
||||
import { DBMessage } from "../storage/entities/DBMessage";
|
||||
import { DBMessageContentChanges } from "../storage/entities/DBMessageContentChanges";
|
||||
import { DBMessageAttachments } from "../storage/entities/DBMessageAttachment";
|
||||
import { DBChannel } from "../storage/entities/DBChannel";
|
||||
import { DBUser } from "../storage/entities/DBUser";
|
||||
|
||||
export function setupMessageCapture(client: Client, db: SQLCommon) {
|
||||
export function setupMessageCapture(client: Client,
|
||||
channelDB: Repository<DBChannel>,
|
||||
userDB: Repository<DBUser>,
|
||||
messageDB: Repository<DBMessage>,
|
||||
mccDB: Repository<DBMessageContentChanges>,
|
||||
maDB: Repository<DBMessageAttachments>
|
||||
) {
|
||||
client.on(Events.MessageCreate, async (message) => {
|
||||
await processMessageCreate(db, message)
|
||||
await processMessageCreate(channelDB, userDB, messageDB, maDB, message)
|
||||
})
|
||||
|
||||
client.on(Events.MessageUpdate, async (oldMessage, newMessage) => {
|
||||
await processMessageModify(db, newMessage)
|
||||
await processMessageModify(messageDB, mccDB, maDB, newMessage)
|
||||
})
|
||||
|
||||
client.on(Events.MessageDelete, async (deletedMessage) => {
|
||||
await processMessageDeleted(db, deletedMessage)
|
||||
await processMessageDeleted(messageDB, deletedMessage)
|
||||
})
|
||||
}
|
||||
|
||||
async function processMessageCreate(db: SQLCommon, message: OmitPartialGroupDMChannel<Message<boolean>>) {
|
||||
const channelOk: SQLResult = await insertChannel(db, message.channel)
|
||||
const userOk: SQLResult = await insertUser(db, message.author)
|
||||
async function processMessageCreate(
|
||||
channelDB: Repository<DBChannel>,
|
||||
userDB: Repository<DBUser>,
|
||||
messageDB: Repository<DBMessage>,
|
||||
maDB: Repository<DBMessageAttachments>,
|
||||
message: OmitPartialGroupDMChannel<Message<boolean>>) {
|
||||
const channelOk: DBChannel | null = await insertChannel(channelDB, message.channel)
|
||||
const userOk: DBUser | null = await insertUser(userDB, message.author)
|
||||
|
||||
if (channelOk == SQLResult.ALREADYEXISTS || channelOk == SQLResult.CREATED ||
|
||||
userOk == SQLResult.ALREADYEXISTS || userOk == SQLResult.CREATED) {
|
||||
|
||||
await insertMessage(db, message)
|
||||
// TODO observe success of message insertion
|
||||
if(message.attachments.size != 0) {
|
||||
const allAttachments: void[] = message.attachments.map((attachment) => {
|
||||
insertAttachment(db, attachment, message)
|
||||
})
|
||||
|
||||
await Promise.all(allAttachments).catch((error) => {
|
||||
// TODO Winston should handle this
|
||||
console.log("MESSAGE ATTACHMENT INSERT ERROR")
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function processMessageModify(db: SQLCommon, newMessage: OmitPartialGroupDMChannel<Message<boolean>>) {
|
||||
await updateMessageContentHistory(db, newMessage)
|
||||
|
||||
if(newMessage.attachments.size != 0) {
|
||||
const allAttachments: void[] = newMessage.attachments.map((attachment) => {
|
||||
insertAttachment(db, attachment, newMessage)
|
||||
})
|
||||
|
||||
await Promise.all(allAttachments).catch((error) => {
|
||||
// TODO Winston should handle this
|
||||
console.log(error)
|
||||
})
|
||||
if (channelOk != null && userOk != null) {
|
||||
await insertMessage(messageDB, maDB, message)
|
||||
}
|
||||
}
|
||||
|
||||
async function processMessageModify(
|
||||
messageDB: Repository<DBMessage>,
|
||||
mccDB: Repository<DBMessageContentChanges>,
|
||||
maDB: Repository<DBMessageAttachments>,
|
||||
newMessage: OmitPartialGroupDMChannel<Message<boolean>>) {
|
||||
await updateMessageContentHistory(messageDB, mccDB, maDB, newMessage)
|
||||
}
|
||||
|
||||
async function processMessageDeleted(db: SQLCommon, deletedMessage: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) {
|
||||
|
||||
async function processMessageDeleted(db: Repository<DBMessage>, deletedMessage: OmitPartialGroupDMChannel<Message<boolean>> | PartialMessage) {
|
||||
await markMessageDeleted(db, deletedMessage)
|
||||
}
|
||||
@ -2,6 +2,7 @@ import { Column, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm";
|
||||
import { DBChannel } from "./DBChannel";
|
||||
import { DBUser } from "./DBUser";
|
||||
import { DBMessageContentChanges } from "./DBMessageContentChanges";
|
||||
import { DBMessageAttachments } from "./DBMessageAttachment";
|
||||
|
||||
@Entity()
|
||||
export class DBMessage {
|
||||
@ -20,9 +21,12 @@ export class DBMessage {
|
||||
@Column({type: "datetime"})
|
||||
message_timestamp: Date
|
||||
|
||||
@Column()
|
||||
@Column({default: false})
|
||||
message_deleted: boolean
|
||||
|
||||
@OneToMany(() => DBMessageContentChanges, (mcc: DBMessageContentChanges) => mcc.message, {nullable: true})
|
||||
changes: DBMessageContentChanges | null
|
||||
changes: DBMessageContentChanges[] | null
|
||||
|
||||
@OneToMany(() => DBMessageAttachments, (ma: DBMessageAttachments) => ma.attachment_snowflake, {nullable: true})
|
||||
attachments: DBMessageAttachments[] | null
|
||||
}
|
||||
29
src/utilties/storage/entities/DBMessageAttachment.ts
Normal file
29
src/utilties/storage/entities/DBMessageAttachment.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm";
|
||||
import { DBMessage } from "./DBMessage";
|
||||
|
||||
@Entity()
|
||||
export class DBMessageAttachments {
|
||||
@PrimaryColumn({"type": "bigint"})
|
||||
attachment_snowflake: string
|
||||
|
||||
@ManyToOne(() => DBMessage, (message: DBMessage) => message.attachments)
|
||||
message: DBMessage
|
||||
|
||||
@Column()
|
||||
attachment_name: string
|
||||
|
||||
@Column({nullable: true})
|
||||
attachment_description: string | null
|
||||
|
||||
@Column({type: "datetime"})
|
||||
attachment_timestamp: Date
|
||||
|
||||
@Column({nullable: true})
|
||||
attachment_mime_type: string | null
|
||||
|
||||
@Column()
|
||||
attachment_url: string
|
||||
|
||||
@Column({default: false})
|
||||
attachment_download: boolean
|
||||
}
|
||||
@ -1,10 +1,6 @@
|
||||
import { SQLCommon } from "./interfaces";
|
||||
|
||||
const tables: string[] = [
|
||||
"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 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 breadthread_autolock (breadthread_autolock_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,channel_snowflake bigint NOT NULL,inactivity_seconds bigint NOT NULL,locked bit NOT NULL);",
|
||||
"CREATE TABLE IF NOT EXISTS message_scan_regex_matches (message_scan_regex_matches_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_snowflake bigint NOT NULL,message_regexes_id bigint NOT NULL);",
|
||||
"CREATE TABLE IF NOT EXISTS message_regex_no_role_check (message_regex_no_role_check_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,role_snowflake bigint NOT NULL);",
|
||||
"CREATE TABLE IF NOT EXISTS message_regexes (message_regexes_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,regex text NOT NULL,priority int NOT NULL,severity int NOT NULL);",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user