summary refs log tree commit diff
path: root/src/util/entities/Message.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/entities/Message.ts')
-rw-r--r--src/util/entities/Message.ts296
1 files changed, 296 insertions, 0 deletions
diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts
new file mode 100644
index 00000000..3a3dd5e4
--- /dev/null
+++ b/src/util/entities/Message.ts
@@ -0,0 +1,296 @@
+import { User } from "./User";
+import { Member } from "./Member";
+import { Role } from "./Role";
+import { Channel } from "./Channel";
+import { InteractionType } from "../interfaces/Interaction";
+import { Application } from "./Application";
+import {
+	BeforeInsert,
+	BeforeUpdate,
+	Column,
+	CreateDateColumn,
+	Entity,
+	Index,
+	JoinColumn,
+	JoinTable,
+	ManyToMany,
+	ManyToOne,
+	OneToMany,
+	RelationId,
+} from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+import { Webhook } from "./Webhook";
+import { Sticker } from "./Sticker";
+import { Attachment } from "./Attachment";
+import { BannedWords } from "../util";
+import { HTTPError } from "lambert-server";
+import { ValidatorConstraint } from "class-validator";
+
+export enum MessageType {
+	DEFAULT = 0,
+	RECIPIENT_ADD = 1,
+	RECIPIENT_REMOVE = 2,
+	CALL = 3,
+	CHANNEL_NAME_CHANGE = 4,
+	CHANNEL_ICON_CHANGE = 5,
+	CHANNEL_PINNED_MESSAGE = 6,
+	GUILD_MEMBER_JOIN = 7,
+	USER_PREMIUM_GUILD_SUBSCRIPTION = 8,
+	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9,
+	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10,
+	USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11,
+	CHANNEL_FOLLOW_ADD = 12,
+	ACTION = 13, // /me messages
+	GUILD_DISCOVERY_DISQUALIFIED = 14,
+	GUILD_DISCOVERY_REQUALIFIED = 15,
+	ENCRYPTED = 16,
+	REPLY = 19,
+	APPLICATION_COMMAND = 20, // application command or self command invocation
+	ROUTE_ADDED = 41, // custom message routing: new route affecting that channel
+	ROUTE_DISABLED = 42, // custom message routing: given route no longer affecting that channel
+	SELF_COMMAND_SCRIPT = 43, // self command scripts
+	ENCRYPTION = 50,
+	CUSTOM_START = 63,
+	UNHANDLED = 255
+}
+
+@Entity("messages")
+@Index(["channel_id", "id"], { unique: true })
+export class Message extends BaseClass {
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.channel)
+	@Index()
+	channel_id?: string;
+
+	@JoinColumn({ name: "channel_id" })
+	@ManyToOne(() => Channel, {
+		onDelete: "CASCADE",
+	})
+	channel: Channel;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.guild)
+	guild_id?: string;
+
+	@JoinColumn({ name: "guild_id" })
+	@ManyToOne(() => Guild, {
+		onDelete: "CASCADE",
+	})
+	guild?: Guild;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.author)
+	@Index()
+	author_id?: string;
+
+	@JoinColumn({ name: "author_id", referencedColumnName: "id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE",
+	})
+	author?: User;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.member)
+	member_id?: string;
+
+	@JoinColumn({ name: "member_id", referencedColumnName: "id" })
+	@ManyToOne(() => User, {
+		onDelete: "CASCADE",
+	})
+	member?: Member;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.webhook)
+	webhook_id?: string;
+
+	@JoinColumn({ name: "webhook_id" })
+	@ManyToOne(() => Webhook)
+	webhook?: Webhook;
+
+	@Column({ nullable: true })
+	@RelationId((message: Message) => message.application)
+	application_id?: string;
+
+	@JoinColumn({ name: "application_id" })
+	@ManyToOne(() => Application)
+	application?: Application;
+
+	@Column({ nullable: true, type: process.env.PRODUCTION ? "longtext" : undefined })
+	content?: string;
+
+	@Column()
+	@CreateDateColumn()
+	timestamp: Date;
+
+	@Column({ nullable: true })
+	edited_timestamp?: Date;
+
+	@Column({ nullable: true })
+	tts?: boolean;
+
+	@Column({ nullable: true })
+	mention_everyone?: boolean;
+
+	@JoinTable({ name: "message_user_mentions" })
+	@ManyToMany(() => User)
+	mentions: User[];
+
+	@JoinTable({ name: "message_role_mentions" })
+	@ManyToMany(() => Role)
+	mention_roles: Role[];
+
+	@JoinTable({ name: "message_channel_mentions" })
+	@ManyToMany(() => Channel)
+	mention_channels: Channel[];
+
+	@JoinTable({ name: "message_stickers" })
+	@ManyToMany(() => Sticker, { cascade: true, onDelete: "CASCADE" })
+	sticker_items?: Sticker[];
+
+	@OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, {
+		cascade: true,
+		orphanedRowAction: "delete",
+	})
+	attachments?: Attachment[];
+
+	@Column({ type: "simple-json" })
+	embeds: Embed[];
+
+	@Column({ type: "simple-json" })
+	reactions: Reaction[];
+
+	@Column({ type: "text", nullable: true })
+	nonce?: string;
+
+	@Column({ nullable: true })
+	pinned?: boolean;
+
+	@Column({ type: "int" })
+	type: MessageType;
+
+	@Column({ type: "simple-json", nullable: true })
+	activity?: {
+		type: number;
+		party_id: string;
+	};
+
+	@Column({ nullable: true })
+	flags?: string;
+	
+	@Column({ type: "simple-json", nullable: true })
+	message_reference?: {
+		message_id: string;
+		channel_id?: string;
+		guild_id?: string;
+	};
+
+	@JoinColumn({ name: "message_reference_id" })
+	@ManyToOne(() => Message)
+	referenced_message?: Message;
+
+	@Column({ type: "simple-json", nullable: true })
+	interaction?: {
+		id: string;
+		type: InteractionType;
+		name: string;
+		user_id: string; // the user who invoked the interaction
+		// user: User; // TODO: autopopulate user
+	};
+
+	@Column({ type: "simple-json", nullable: true })
+	components?: MessageComponent[];
+
+	@BeforeUpdate()
+	@BeforeInsert()
+	validate() {
+		if (this.content) {
+			if (BannedWords.find(this.content)) throw new HTTPError("Message was blocked by automatic moderation", 200000);
+		}
+	}
+}
+
+export interface MessageComponent {
+	type: number;
+	style?: number;
+	label?: string;
+	emoji?: PartialEmoji;
+	custom_id?: string;
+	url?: string;
+	disabled?: boolean;
+	components: MessageComponent[];
+}
+
+export enum MessageComponentType {
+	Script = 0, // self command script
+	ActionRow = 1,
+	Button = 2,
+}
+
+export interface Embed {
+	title?: string; //title of embed
+	type?: EmbedType; // type of embed (always "rich" for webhook embeds)
+	description?: string; // description of embed
+	url?: string; // url of embed
+	timestamp?: Date; // timestamp of embed content
+	color?: number; // color code of the embed
+	footer?: {
+		text: string;
+		icon_url?: string;
+		proxy_icon_url?: string;
+	}; // footer object	footer information
+	image?: EmbedImage; // image object	image information
+	thumbnail?: EmbedImage; // thumbnail object	thumbnail information
+	video?: EmbedImage; // video object	video information
+	provider?: {
+		name?: string;
+		url?: string;
+	}; // provider object	provider information
+	author?: {
+		name?: string;
+		url?: string;
+		icon_url?: string;
+		proxy_icon_url?: string;
+	}; // author object	author information
+	fields?: {
+		name: string;
+		value: string;
+		inline?: boolean;
+	}[];
+}
+
+export enum EmbedType {
+	rich = "rich",
+	image = "image",
+	video = "video",
+	gifv = "gifv",
+	article = "article",
+	link = "link",
+}
+
+export interface EmbedImage {
+	url?: string;
+	proxy_url?: string;
+	height?: number;
+	width?: number;
+}
+
+export interface Reaction {
+	count: number;
+	//// not saved in the database // me: boolean; // whether the current user reacted using this emoji
+	emoji: PartialEmoji;
+	user_ids: string[];
+}
+
+export interface PartialEmoji {
+	id?: string;
+	name: string;
+	animated?: boolean;
+}
+
+export interface AllowedMentions {
+	parse?: ("users" | "roles" | "everyone")[];
+	roles?: string[];
+	users?: string[];
+	replied_user?: boolean;
+}