spacebar/src/models/Message.ts
2021-08-07 17:11:47 +02:00

369 lines
8.4 KiB
TypeScript

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");