diff --git a/util/oldModels/Message.ts b/util/oldModels/Message.ts
new file mode 100644
index 00000000..15a6f40d
--- /dev/null
+++ b/util/oldModels/Message.ts
@@ -0,0 +1,368 @@
+import { Schema, Types, Document } from "mongoose";
+import db from "../util/Database";
+import { PublicUser, PublicUserProjection, UserModel } from "./User";
+import { MemberModel, PublicMember } from "./Member";
+import { Role, RoleModel } from "./Role";
+import { Channel } from "./Channel";
+import { Snowflake } from "../util";
+import { InteractionType } from "./Interaction";
+
+export interface Message {
+ id: string;
+ channel_id: string;
+ guild_id?: string;
+ author_id?: string;
+ webhook_id?: string;
+ application_id?: string;
+ content?: string;
+ timestamp: Date;
+ edited_timestamp: Date | null;
+ tts?: boolean;
+ mention_everyone?: boolean;
+ mention_user_ids: string[];
+ mention_role_ids: string[];
+ mention_channels_ids: string[];
+ attachments: Attachment[];
+ embeds: Embed[];
+ reactions: Reaction[];
+ nonce?: string | number;
+ pinned?: boolean;
+ type: MessageType;
+ activity?: {
+ type: number;
+ party_id: string;
+ };
+ flags?: bigint;
+ stickers?: any[];
+ message_reference?: {
+ message_id: string;
+ channel_id?: string;
+ guild_id?: string;
+ };
+ interaction?: {
+ id: string;
+ type: InteractionType;
+ name: string;
+ user_id: string; // the user who invoked the interaction
+ // user: User; // TODO: autopopulate user
+ };
+ components: MessageComponent[];
+
+ // * mongoose virtuals:
+ // TODO:
+ // application: Application; // TODO: auto pouplate application
+ author?: PublicUser;
+ member?: PublicMember;
+ mentions?: (PublicUser & {
+ member: PublicMember;
+ })[];
+ mention_roles?: Role[];
+ mention_channels?: Channel[];
+ created_at?: Date;
+ // thread // TODO
+}
+
+const PartialEmoji = {
+ id: String,
+ name: { type: String, required: true },
+ animated: { type: Boolean, required: true },
+};
+
+const MessageComponent: any = {
+ type: { type: Number, required: true },
+ style: Number,
+ label: String,
+ emoji: PartialEmoji,
+ custom_id: String,
+ url: String,
+ disabled: Boolean,
+ components: [Object],
+};
+
+export interface MessageComponent {
+ type: number;
+ style?: number;
+ label?: string;
+ emoji?: PartialEmoji;
+ custom_id?: string;
+ url?: string;
+ disabled?: boolean;
+ components: MessageComponent[];
+}
+
+export enum MessageComponentType {
+ ActionRow = 1,
+ Button = 2,
+}
+
+export interface MessageDocument extends Document, Message {
+ id: string;
+}
+
+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,
+ GUILD_DISCOVERY_DISQUALIFIED = 14,
+ GUILD_DISCOVERY_REQUALIFIED = 15,
+ REPLY = 19,
+ APPLICATION_COMMAND = 20,
+}
+
+export interface Attachment {
+ id: string; // attachment id
+ filename: string; // name of file attached
+ size: number; // size of file in bytes
+ url: string; // source url of file
+ proxy_url: string; // a proxied url of file
+ height?: number; // height of file (if image)
+ width?: number; // width of file (if image)
+ content_type?: string;
+}
+
+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;
+}
+
+export const Attachment = {
+ id: String, // attachment id
+ filename: String, // name of file attached
+ size: Number, // size of file in bytes
+ url: String, // source url of file
+ proxy_url: String, // a proxied url of file
+ height: Number, // height of file (if image)
+ width: Number, // width of file (if image)
+ content_type: String,
+};
+
+export const EmbedImage = {
+ url: String,
+ proxy_url: String,
+ height: Number,
+ width: Number,
+};
+
+const Reaction = {
+ count: Number,
+ user_ids: [String],
+ emoji: {
+ id: String,
+ name: String,
+ animated: Boolean,
+ },
+};
+
+export const Embed = {
+ title: String, //title of embed
+ type: { type: String }, // 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 const MessageSchema = new Schema({
+ id: String,
+ channel_id: String,
+ author_id: String,
+ webhook_id: String,
+ guild_id: String,
+ application_id: String,
+ content: String,
+ timestamp: Date,
+ edited_timestamp: Date,
+ tts: Boolean,
+ mention_everyone: Boolean,
+ mention_user_ids: [String],
+ mention_role_ids: [String],
+ mention_channel_ids: [String],
+ attachments: [Attachment],
+ embeds: [Embed],
+ reactions: [Reaction],
+ nonce: Schema.Types.Mixed, // can be a long or a string
+ pinned: Boolean,
+ type: { type: Number },
+ activity: {
+ type: { type: Number },
+ party_id: String,
+ },
+ flags: Types.Long,
+ stickers: [],
+ message_reference: {
+ message_id: String,
+ channel_id: String,
+ guild_id: String,
+ },
+ components: [MessageComponent],
+ // virtual:
+ // author: {
+ // ref: UserModel,
+ // localField: "author_id",
+ // foreignField: "id",
+ // justOne: true,
+ // autopopulate: { select: { id: true, user_data: false } },
+ // },
+});
+
+MessageSchema.virtual("author", {
+ ref: UserModel,
+ localField: "author_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: { select: PublicUserProjection },
+});
+
+MessageSchema.virtual("member", {
+ ref: MemberModel,
+ localField: "author_id",
+ foreignField: "id",
+ justOne: true,
+});
+
+MessageSchema.virtual("mentions", {
+ ref: UserModel,
+ localField: "mention_user_ids",
+ foreignField: "id",
+ justOne: false,
+ autopopulate: { select: PublicUserProjection },
+});
+
+MessageSchema.virtual("mention_roles", {
+ ref: RoleModel,
+ localField: "mention_role_ids",
+ foreignField: "id",
+ justOne: false,
+ autopopulate: true,
+});
+
+MessageSchema.virtual("mention_channels", {
+ ref: RoleModel,
+ localField: "mention_channel_ids",
+ foreignField: "id",
+ justOne: false,
+ autopopulate: { select: { id: true, guild_id: true, type: true, name: true } },
+});
+
+MessageSchema.virtual("referenced_message", {
+ ref: "Message",
+ localField: "message_reference.message_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: true,
+});
+
+MessageSchema.virtual("created_at").get(function (this: MessageDocument) {
+ return new Date(Snowflake.deconstruct(this.id).timestamp);
+});
+
+MessageSchema.set("removeResponse", ["mention_channel_ids", "mention_role_ids", "mention_user_ids", "author_id"]);
+
+// TODO: missing Application Model
+// MessageSchema.virtual("application", {
+// ref: Application,
+// localField: "mention_role_ids",
+// foreignField: "id",
+// justOne: true,
+// });
+
+// @ts-ignore
+export const MessageModel = db.model<MessageDocument>("Message", MessageSchema, "messages");
|