Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
346 changes: 136 additions & 210 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
"format:check": "prettier --check ."
},
"dependencies": {
"@prisma/client": "^3.9.2",
"@discordjs/rest": "^0.5.0",
"@prisma/client": "^3.15.2",
"@sentry/node": "^6.19.6",
"@sinclair/typebox": "^0.20.5",
"axios": "^0.26.0",
"detritus-client-rest": "^0.10.5",
"discord-interactions": "^2.4.1",
"env-schema": "^4.0.0",
"fastify": "^3.22.0",
Expand Down Expand Up @@ -60,7 +60,7 @@
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"prettier": "2.6.1",
"prisma": "^3.9.2",
"prisma": "^3.15.2",
"tap": "^16.0.1",
"ts-node": "^10.5.0",
"tsc-watch": "^4.6.0",
Expand Down
38 changes: 38 additions & 0 deletions prisma/migrations/20220624062431_add_embeds/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-- AlterTable
ALTER TABLE "Message" ADD COLUMN "internalId" SERIAL NOT NULL,
ADD CONSTRAINT "Message_pkey" PRIMARY KEY ("internalId");

-- CreateTable
CREATE TABLE "MessageEmbed" (
"id" SERIAL NOT NULL,
"title" TEXT,
"description" TEXT,
"url" TEXT,
"authorName" TEXT,
"footerText" TEXT,
"timestamp" TIMESTAMP(3),
"color" INTEGER,
"messageId" INTEGER NOT NULL,

CONSTRAINT "MessageEmbed_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "EmbedField" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"value" TEXT NOT NULL,
"inline" BOOLEAN NOT NULL DEFAULT false,
"embedId" INTEGER NOT NULL,

CONSTRAINT "EmbedField_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "MessageEmbed_messageId_key" ON "MessageEmbed"("messageId");

-- AddForeignKey
ALTER TABLE "MessageEmbed" ADD CONSTRAINT "MessageEmbed_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "Message"("internalId") ON DELETE CASCADE ON UPDATE NO ACTION;

-- AddForeignKey
ALTER TABLE "EmbedField" ADD CONSTRAINT "EmbedField_embedId_fkey" FOREIGN KEY ("embedId") REFERENCES "MessageEmbed"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "MessageEmbed" ADD COLUMN "authorIconUrl" TEXT,
ADD COLUMN "authorUrl" TEXT,
ADD COLUMN "footerIconUrl" TEXT,
ADD COLUMN "thumbnailUrl" TEXT;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Message" ALTER COLUMN "content" DROP NOT NULL;
135 changes: 80 additions & 55 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,79 @@ datasource db {
url = env("DATABASE_URL")
}


model Channel {
id BigInt @id
permissions Json?
webhookId BigInt?
webhookToken String? @db.VarChar(255) /// @encrypted
guildId BigInt
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade, onUpdate: NoAction)
messages Message[]

}
id BigInt @id
permissions Json?
webhookId BigInt?
webhookToken String? @db.VarChar(255) /// @encrypted
guildId BigInt
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade, onUpdate: NoAction)
messages Message[]

}

model Guild {
id BigInt @id
logChannelId BigInt?
permissions Json?
beforeMigration Boolean @default(false) // This indicates if the guild existed before the migration to storing message content.
id BigInt @id
logChannelId BigInt?
permissions Json?
beforeMigration Boolean @default(false) // This indicates if the guild existed before the migration to storing message content.
// If it was it gains access to adding any previous bot sent message to the database.
messages Message[]
channels Channel[]
messages Message[]
channels Channel[]
}

model Message {
id BigInt
guildId BigInt
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade, onUpdate: NoAction)
channelId BigInt
channel Channel @relation(fields: [channelId], references: [id], onDelete: Cascade, onUpdate: NoAction)
content String /// @encrypted
editedAt DateTime
editedBy BigInt
deleted Boolean @default(false)
addedByUser Boolean @default(false) // This indicates if the message was a message previously sent by the bot, and then added to the database.
internalId Int @id @default(autoincrement()) // Exists to allow for storage of message history and ease of relating
id BigInt
guildId BigInt
guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade, onUpdate: NoAction)
channelId BigInt
channel Channel @relation(fields: [channelId], references: [id], onDelete: Cascade, onUpdate: NoAction)
content String? /// @encrypted
editedAt DateTime
editedBy BigInt
deleted Boolean @default(false)
addedByUser Boolean @default(false) // This indicates if the message was a message previously sent by the bot, and then added to the database.

@@unique([id, editedAt])
embed MessageEmbed?

}

@@unique([id, editedAt])
}

model MessageEmbed {
id Int @id @default(autoincrement())
title String? /// @encrypted
description String? /// @encrypted
url String? /// @encrypted
authorName String? /// @encrypted
authorUrl String? /// @encrypted
authorIconUrl String? /// @encrypted
footerText String? /// @encrypted
footerIconUrl String? /// @encrypted
thumbnailUrl String? /// @encrypted
timestamp DateTime?
color Int?
fields EmbedField[]
messageId Int @unique
message Message @relation(fields: [messageId], references: [internalId], onDelete: Cascade, onUpdate: NoAction)
}

model EmbedField {
id Int @id @default(autoincrement())
name String /// @encrypted
value String /// @encrypted
inline Boolean @default(false)
embedId Int
embed MessageEmbed @relation(fields: [embedId], references: [id], onDelete: Cascade, onUpdate: NoAction)
}

model User {
id BigInt @id
oauthToken String? /// @encrypted
id BigInt @id
oauthToken String? /// @encrypted
oauthTokenExpiration DateTime?
refreshToken String? /// @encrypted
staff Boolean @default(false)
refreshToken String? /// @encrypted
staff Boolean @default(false)
}

enum ReportStatus {
Expand All @@ -67,35 +92,35 @@ enum ReportStatus {
}

model Report {
id BigInt @id @default(autoincrement())
userId BigInt
content String /// @encrypted
messageId BigInt
guildId BigInt
channelId BigInt
reportedAt DateTime
resolvedAt DateTime? // Report should be resolved closed if this is set
status ReportStatus @default(Pending)
userReportReason String /// @encrypted
id BigInt @id @default(autoincrement())
userId BigInt
content String /// @encrypted
messageId BigInt
guildId BigInt
channelId BigInt
reportedAt DateTime
resolvedAt DateTime? // Report should be resolved closed if this is set
status ReportStatus @default(Pending)
userReportReason String /// @encrypted
staffResolvedReasonId BigInt?
staffResolvedReason ReportReason? @relation(fields: [staffResolvedReasonId], references: [id], onDelete: Cascade, onUpdate: NoAction)
messages ReportMessage[]
}
staffResolvedReason ReportReason? @relation(fields: [staffResolvedReasonId], references: [id], onDelete: Cascade, onUpdate: NoAction)
messages ReportMessage[]
}

model ReportReason {
model ReportReason {
// Set by staff when closing the ticket
id BigInt @id @default(autoincrement())
name String
id BigInt @id @default(autoincrement())
name String
description String
reports Report[]
reports Report[]
}

model ReportMessage {
// Communication between the user and staff - doesn't include the inital report
id BigInt @id @default(autoincrement())
authorId BigInt
id BigInt @id @default(autoincrement())
authorId BigInt
fromStaff Boolean // If the author of the message was staff
content String /// @encrypted
reportId BigInt
report Report @relation(fields: [reportId], references: [id], onDelete: Cascade, onUpdate: NoAction)
}
content String /// @encrypted
reportId BigInt
report Report @relation(fields: [reportId], references: [id], onDelete: Cascade, onUpdate: NoAction)
}
10 changes: 8 additions & 2 deletions src/discord_commands/global.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"type": 7,
"name": "channel",
"required": false,
"description": "The channel to manage / view permissions of the target on. Leave this blank to manage permissions on the entire server",
"description": "The channel to manage / view permissions of the target on. Leave this blank for the entire server",
"channel_types": [0, 5]
}
]
Expand Down Expand Up @@ -92,7 +92,7 @@
"type": 7,
"name": "channel",
"required": false,
"description": "The channel to setup permissions of the target on. Leave this blank to setup permissions on the entire server",
"description": "The channel to setup permissions of the target on. Leave this blank for the entire server",
"channel_types": [0, 5]
}
]
Expand Down Expand Up @@ -135,6 +135,12 @@
"description": "Channel to send the message to",
"channel_types": [0, 5, 10, 11, 12],
"required": true
},
{
"name": "content-only",
"type": 5,
"description": "Send a message quickly by only sending content",
"required": false
}
]
},
Expand Down
14 changes: 14 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ enum InteractionOrRequestFinalStatus {
TAG_NOT_FOUND,
NO_PERMISSIONS_PRESET_SELECTED,
MANAGEMENT_PERMISSIONS_CANNOT_BE_SET_ON_CHANNEL_LEVEL,
MESSAGE_HAS_NO_CONTENT,
ATTEMPTING_TO_SEND_WHEN_NO_CONTENT_SET,
EMBED_VALUE_EDITING_MALFORMED,
EMBED_EDITING_MISSING_REQUIRED_VALUE,
EMBED_REQUIRES_TITLE_OR_DESCRIPTION,
MESSAGE_GENERATION_CACHE_NOT_FOUND,
MIGRATION_ATTEMPTED_ON_MESSAGE_WITH_MULTIPLE_EMBEDS,
GENERIC_EXPECTED_PERMISSIONS_FAILURE = 3000,
USER_MISSING_DISCORD_PERMISSION,
BOT_MISSING_DISCORD_PERMISSION,
Expand All @@ -42,6 +49,7 @@ enum InteractionOrRequestFinalStatus {
MAX_USER_PERMISSIONS,
MAX_ROLE_CHANNEL_PERMISSIONS,
MAX_USER_CHANNEL_PERMISSIONS,
EMBED_EXCEEDS_DISCORD_LIMITS,
GENERIC_UNEXPECTED_FAILURE = 6000,
INTERACTION_TYPE_MISSING_HANDLER,
APPLICATION_COMMAND_TYPE_MISSING_HANDLER,
Expand All @@ -62,6 +70,12 @@ enum InteractionOrRequestFinalStatus {
CREATE_WEBHOOK_RESULT_MISSING_TOKEN,
ROLE_NOT_IN_CACHE,
PERMISSIONS_CANNOT_CROSSOVER_WHEN_UPDATING,
TOO_MANY_EMBEDS,
MESSAGE_NOT_FOUND_IN_DATABASE_AFTER_CHECKS_DONE,
FIELD_SELECT_OUT_OF_INDEX,
EMBED_EDITING_MISSING_DISCORD_REQUIRED_VALUE,
MESSAGE_ID_MISSING_ON_MESSAGE_EDIT_CACHE,
INTERACTION_TIMED_OUT_HTTP,
}

class CustomError extends Error {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ instance.setErrorHandler(async (error, request, reply) => {
// These are plugins that are separate from versioning
await instance.register(prismaPlugin);
await instance.register(discordRestPlugin, {
detritus: { token: instance.envVars.DISCORD_TOKEN },
discord: { token: instance.envVars.DISCORD_TOKEN },
});
await instance.register(redisRestPlugin, {
redis: {
Expand Down
2 changes: 1 addition & 1 deletion src/interactions/buttons/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default async function handleDeleteButton(
title: "Delete Message",
url: `https://discord.com/channels/${interaction.guild_id}/${databaseMessage.channelId}/${messageId}`,
description: `Are you sure you want to delete this message?\n**Content:**\n\n${
content.length > maxLength
content !== null && content.length > maxLength
? `${content.substring(0, maxLength)}...`
: content
}`,
Expand Down
Loading