diff --git a/util/oldModels/Application.ts b/util/oldModels/Application.ts
new file mode 100644
index 00000000..fae6e8db
--- /dev/null
+++ b/util/oldModels/Application.ts
@@ -0,0 +1,67 @@
+import { Team } from "./Team";
+
+export interface Application {
+ id: string;
+ name: string;
+ icon: string | null;
+ description: string;
+ rpc_origins: string[] | null;
+ bot_public: boolean;
+ bot_require_code_grant: boolean;
+ terms_of_service_url: string | null;
+ privacy_policy_url: string | null;
+ owner_id: string;
+ summary: string | null;
+ verify_key: string;
+ team: Team | null;
+ guild_id: string; // if this application is a game sold on Discord, this field will be the guild to which it has been linked
+ primary_sku_id: string | null; // if this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists
+ slug: string | null; // if this application is a game sold on Discord, this field will be the URL slug that links to the store page
+ cover_image: string | null; // the application's default rich presence invite cover image hash
+ flags: number; // the application's public flags
+}
+
+export interface ApplicationCommand {
+ id: string;
+ application_id: string;
+ name: string;
+ description: string;
+ options?: ApplicationCommandOption[];
+}
+
+export interface ApplicationCommandOption {
+ type: ApplicationCommandOptionType;
+ name: string;
+ description: string;
+ required?: boolean;
+ choices?: ApplicationCommandOptionChoice[];
+ options?: ApplicationCommandOption[];
+}
+
+export interface ApplicationCommandOptionChoice {
+ name: string;
+ value: string | number;
+}
+
+export enum ApplicationCommandOptionType {
+ SUB_COMMAND = 1,
+ SUB_COMMAND_GROUP = 2,
+ STRING = 3,
+ INTEGER = 4,
+ BOOLEAN = 5,
+ USER = 6,
+ CHANNEL = 7,
+ ROLE = 8,
+}
+
+export interface ApplicationCommandInteractionData {
+ id: string;
+ name: string;
+ options?: ApplicationCommandInteractionDataOption[];
+}
+
+export interface ApplicationCommandInteractionDataOption {
+ name: string;
+ value?: any;
+ options?: ApplicationCommandInteractionDataOption[];
+}
diff --git a/util/oldModels/AuditLog.ts b/util/oldModels/AuditLog.ts
new file mode 100644
index 00000000..02b2c444
--- /dev/null
+++ b/util/oldModels/AuditLog.ts
@@ -0,0 +1,220 @@
+import { Schema, Document, Types } from "mongoose";
+import db from "../util/Database";
+import { ChannelPermissionOverwrite } from "./Channel";
+import { PublicUser } from "./User";
+
+export interface AuditLogResponse {
+ webhooks: []; // TODO:
+ users: PublicUser[];
+ audit_log_entries: AuditLogEntries[];
+ integrations: []; // TODO:
+}
+
+export interface AuditLogEntries {
+ target_id?: string;
+ user_id: string;
+ id: string;
+ action_type: AuditLogEvents;
+ options?: {
+ delete_member_days?: string;
+ members_removed?: string;
+ channel_id?: string;
+ messaged_id?: string;
+ count?: string;
+ id?: string;
+ type?: string;
+ role_name?: string;
+ };
+ changes: AuditLogChange[];
+ reason?: string;
+}
+
+export interface AuditLogChange {
+ new_value?: AuditLogChangeValue;
+ old_value?: AuditLogChangeValue;
+ key: string;
+}
+
+export interface AuditLogChangeValue {
+ name?: string;
+ description?: string;
+ icon_hash?: string;
+ splash_hash?: string;
+ discovery_splash_hash?: string;
+ banner_hash?: string;
+ owner_id?: string;
+ region?: string;
+ preferred_locale?: string;
+ afk_channel_id?: string;
+ afk_timeout?: number;
+ rules_channel_id?: string;
+ public_updates_channel_id?: string;
+ mfa_level?: number;
+ verification_level?: number;
+ explicit_content_filter?: number;
+ default_message_notifications?: number;
+ vanity_url_code?: string;
+ $add?: {}[];
+ $remove?: {}[];
+ prune_delete_days?: number;
+ widget_enabled?: boolean;
+ widget_channel_id?: string;
+ system_channel_id?: string;
+ position?: number;
+ topic?: string;
+ bitrate?: number;
+ permission_overwrites?: ChannelPermissionOverwrite[];
+ nsfw?: boolean;
+ application_id?: string;
+ rate_limit_per_user?: number;
+ permissions?: string;
+ color?: number;
+ hoist?: boolean;
+ mentionable?: boolean;
+ allow?: string;
+ deny?: string;
+ code?: string;
+ channel_id?: string;
+ inviter_id?: string;
+ max_uses?: number;
+ uses?: number;
+ max_age?: number;
+ temporary?: boolean;
+ deaf?: boolean;
+ mute?: boolean;
+ nick?: string;
+ avatar_hash?: string;
+ id?: string;
+ type?: number;
+ enable_emoticons?: boolean;
+ expire_behavior?: number;
+ expire_grace_period?: number;
+ user_limit?: number;
+}
+
+export interface AuditLogEntriesDocument extends Document, AuditLogEntries {
+ id: string;
+}
+
+export const AuditLogChanges = {
+ name: String,
+ description: String,
+ icon_hash: String,
+ splash_hash: String,
+ discovery_splash_hash: String,
+ banner_hash: String,
+ owner_id: String,
+ region: String,
+ preferred_locale: String,
+ afk_channel_id: String,
+ afk_timeout: Number,
+ rules_channel_id: String,
+ public_updates_channel_id: String,
+ mfa_level: Number,
+ verification_level: Number,
+ explicit_content_filter: Number,
+ default_message_notifications: Number,
+ vanity_url_code: String,
+ $add: [{}],
+ $remove: [{}],
+ prune_delete_days: Number,
+ widget_enabled: Boolean,
+ widget_channel_id: String,
+ system_channel_id: String,
+ position: Number,
+ topic: String,
+ bitrate: Number,
+ permission_overwrites: [{}],
+ nsfw: Boolean,
+ application_id: String,
+ rate_limit_per_user: Number,
+ permissions: String,
+ color: Number,
+ hoist: Boolean,
+ mentionable: Boolean,
+ allow: String,
+ deny: String,
+ code: String,
+ channel_id: String,
+ inviter_id: String,
+ max_uses: Number,
+ uses: Number,
+ max_age: Number,
+ temporary: Boolean,
+ deaf: Boolean,
+ mute: Boolean,
+ nick: String,
+ avatar_hash: String,
+ id: String,
+ type: Number,
+ enable_emoticons: Boolean,
+ expire_behavior: Number,
+ expire_grace_period: Number,
+ user_limit: Number,
+};
+
+export const AuditLogSchema = new Schema({
+ target_id: String,
+ user_id: { type: String, required: true },
+ id: { type: String, required: true },
+ action_type: { type: Number, required: true },
+ options: {
+ delete_member_days: String,
+ members_removed: String,
+ channel_id: String,
+ messaged_id: String,
+ count: String,
+ id: String,
+ type: { type: Number },
+ role_name: String,
+ },
+ changes: [
+ {
+ new_value: AuditLogChanges,
+ old_value: AuditLogChanges,
+ key: String,
+ },
+ ],
+ reason: String,
+});
+
+// @ts-ignore
+export const AuditLogModel = db.model<AuditLogEntries>("AuditLog", AuditLogSchema, "auditlogs");
+
+export enum AuditLogEvents {
+ GUILD_UPDATE = 1,
+ CHANNEL_CREATE = 10,
+ CHANNEL_UPDATE = 11,
+ CHANNEL_DELETE = 12,
+ CHANNEL_OVERWRITE_CREATE = 13,
+ CHANNEL_OVERWRITE_UPDATE = 14,
+ CHANNEL_OVERWRITE_DELETE = 15,
+ MEMBER_KICK = 20,
+ MEMBER_PRUNE = 21,
+ MEMBER_BAN_ADD = 22,
+ MEMBER_BAN_REMOVE = 23,
+ MEMBER_UPDATE = 24,
+ MEMBER_ROLE_UPDATE = 25,
+ MEMBER_MOVE = 26,
+ MEMBER_DISCONNECT = 27,
+ BOT_ADD = 28,
+ ROLE_CREATE = 30,
+ ROLE_UPDATE = 31,
+ ROLE_DELETE = 32,
+ INVITE_CREATE = 40,
+ INVITE_UPDATE = 41,
+ INVITE_DELETE = 42,
+ WEBHOOK_CREATE = 50,
+ WEBHOOK_UPDATE = 51,
+ WEBHOOK_DELETE = 52,
+ EMOJI_CREATE = 60,
+ EMOJI_UPDATE = 61,
+ EMOJI_DELETE = 62,
+ MESSAGE_DELETE = 72,
+ MESSAGE_BULK_DELETE = 73,
+ MESSAGE_PIN = 74,
+ MESSAGE_UNPIN = 75,
+ INTEGRATION_CREATE = 80,
+ INTEGRATION_UPDATE = 81,
+ INTEGRATION_DELETE = 82,
+}
diff --git a/util/oldModels/Ban.ts b/util/oldModels/Ban.ts
new file mode 100644
index 00000000..f09950ee
--- /dev/null
+++ b/util/oldModels/Ban.ts
@@ -0,0 +1,32 @@
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+import { PublicUserProjection, UserModel } from "./User";
+
+export interface Ban extends Document {
+ user_id: string;
+ guild_id: string;
+ executor_id: string;
+ ip: string;
+ reason?: string;
+}
+
+export const BanSchema = new Schema({
+ user_id: { type: String, required: true },
+ guild_id: { type: String, required: true },
+ executor_id: { type: String, required: true },
+ reason: String,
+ ip: String, // ? Should we store this in here, or in the UserModel?
+});
+
+BanSchema.virtual("user", {
+ ref: UserModel,
+ localField: "user_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: { select: PublicUserProjection },
+});
+
+BanSchema.set("removeResponse", ["user_id"]);
+
+// @ts-ignore
+export const BanModel = db.model<Ban>("Ban", BanSchema, "bans");
diff --git a/util/oldModels/Channel.ts b/util/oldModels/Channel.ts
new file mode 100644
index 00000000..2959decd
--- /dev/null
+++ b/util/oldModels/Channel.ts
@@ -0,0 +1,111 @@
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+import toBigInt from "../util/toBigInt";
+import { PublicUserProjection, UserModel } from "./User";
+
+// @ts-ignore
+export interface AnyChannel extends Channel, DMChannel, TextChannel, VoiceChannel {
+ recipient_ids: null | string[];
+}
+
+export interface ChannelDocument extends Document, AnyChannel {
+ id: string;
+}
+
+export const ChannelSchema = new Schema({
+ id: String,
+ created_at: { type: Schema.Types.Date, required: true },
+ name: String, // can't be required for dm channels
+ type: { type: Number, required: true },
+ guild_id: String,
+ owner_id: String,
+ parent_id: String,
+ recipient_ids: [String],
+ position: Number,
+ last_message_id: String,
+ last_pin_timestamp: Date,
+ nsfw: Boolean,
+ rate_limit_per_user: Number,
+ default_auto_archive_duration: Number,
+ topic: String,
+ permission_overwrites: [
+ {
+ allow: { type: String, get: toBigInt },
+ deny: { type: String, get: toBigInt },
+ id: String,
+ type: { type: Number },
+ },
+ ],
+});
+
+ChannelSchema.virtual("recipients", {
+ ref: UserModel,
+ localField: "recipient_ids",
+ foreignField: "id",
+ justOne: false,
+ autopopulate: { select: PublicUserProjection },
+});
+
+ChannelSchema.set("removeResponse", ["recipient_ids"]);
+
+// @ts-ignore
+export const ChannelModel = db.model<ChannelDocument>("Channel", ChannelSchema, "channels");
+
+export interface Channel {
+ id: string;
+ created_at: Date;
+ name: string;
+ type: number;
+}
+
+export interface TextBasedChannel {
+ last_message_id?: string;
+ last_pin_timestamp?: number;
+ default_auto_archive_duration?: number;
+}
+
+export interface GuildChannel extends Channel {
+ guild_id: string;
+ position: number;
+ parent_id?: string;
+ permission_overwrites: ChannelPermissionOverwrite[];
+}
+
+export interface ChannelPermissionOverwrite {
+ allow: bigint; // for bitfields we use bigints
+ deny: bigint; // for bitfields we use bigints
+ id: string;
+ type: ChannelPermissionOverwriteType;
+}
+
+export enum ChannelPermissionOverwriteType {
+ role = 0,
+ member = 1,
+}
+
+export interface VoiceChannel extends GuildChannel {
+ video_quality_mode?: number;
+ bitrate?: number;
+ user_limit?: number;
+}
+
+export interface TextChannel extends GuildChannel, TextBasedChannel {
+ nsfw: boolean;
+ rate_limit_per_user: number;
+ topic?: string;
+}
+// @ts-ignore
+export interface DMChannel extends Channel, TextBasedChannel {
+ owner_id: string;
+ recipient_ids: string[];
+}
+
+export enum ChannelType {
+ GUILD_TEXT = 0, // a text channel within a server
+ DM = 1, // a direct message between users
+ GUILD_VOICE = 2, // a voice channel within a server
+ GROUP_DM = 3, // a direct message between multiple users
+ GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels
+ GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server
+ GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord
+}
diff --git a/util/oldModels/Emoji.ts b/util/oldModels/Emoji.ts
new file mode 100644
index 00000000..3e5cad53
--- /dev/null
+++ b/util/oldModels/Emoji.ts
@@ -0,0 +1,29 @@
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+
+export interface Emoji extends Document {
+ id: string;
+ animated: boolean;
+ available: boolean;
+ guild_id: string;
+ managed: boolean;
+ name: string;
+ require_colons: boolean;
+ url: string;
+ roles: string[]; // roles this emoji is whitelisted to (new discord feature?)
+}
+
+export const EmojiSchema = new Schema({
+ id: { type: String, required: true },
+ animated: Boolean,
+ available: Boolean,
+ guild_id: String,
+ managed: Boolean,
+ name: String,
+ require_colons: Boolean,
+ url: String,
+ roles: [String],
+});
+
+// @ts-ignore
+export const EmojiModel = db.model<Emoji>("Emoji", EmojiSchema, "emojis");
diff --git a/util/oldModels/Event.ts b/util/oldModels/Event.ts
new file mode 100644
index 00000000..904522a8
--- /dev/null
+++ b/util/oldModels/Event.ts
@@ -0,0 +1,524 @@
+import { ConnectedAccount, PublicUser, Relationship, User, UserSettings } from "./User";
+import { DMChannel, Channel } from "./Channel";
+import { Guild } from "./Guild";
+import { Member, PublicMember, UserGuildSettings } from "./Member";
+import { Emoji } from "./Emoji";
+import { Presence } from "../models/Activity";
+import { Role } from "./Role";
+import { Invite } from "./Invite";
+import { Message, PartialEmoji } from "./Message";
+import { VoiceState } from "./VoiceState";
+import { ApplicationCommand } from "./Application";
+import { Interaction } from "./Interaction";
+
+export interface Event {
+ guild_id?: string;
+ user_id?: string;
+ channel_id?: string;
+ created_at?: Date;
+ event: EVENT;
+ data?: any;
+}
+
+// ! Custom Events that shouldn't get sent to the client but processed by the server
+
+export interface InvalidatedEvent extends Event {
+ event: "INVALIDATED";
+}
+
+// ! END Custom Events that shouldn't get sent to the client but processed by the server
+
+export interface ReadyEventData {
+ v: number;
+ user: PublicUser & {
+ mobile: boolean;
+ desktop: boolean;
+ email: string | null;
+ flags: bigint;
+ mfa_enabled: boolean;
+ nsfw_allowed: boolean;
+ phone: string | null;
+ premium: boolean;
+ premium_type: number;
+ verified: boolean;
+ bot: boolean;
+ };
+ private_channels: DMChannel[]; // this will be empty for bots
+ session_id: string; // resuming
+ guilds: Guild[];
+ analytics_token?: string;
+ connected_accounts?: ConnectedAccount[];
+ consents?: {
+ personalization?: {
+ consented?: boolean;
+ };
+ };
+ country_code?: string; // e.g. DE
+ friend_suggestion_count?: number;
+ geo_ordered_rtc_regions?: string[]; // ["europe","russie","india","us-east","us-central"]
+ experiments?: [number, number, number, number, number][];
+ guild_experiments?: [
+ // ? what are guild_experiments?
+ // this is the structure of it:
+ number,
+ null,
+ number,
+ [[number, { e: number; s: number }[]]],
+ [number, [[number, [number, number]]]],
+ { b: number; k: bigint[] }[]
+ ][];
+ guild_join_requests?: []; // ? what is this? this is new
+ shard?: [number, number];
+ user_settings?: UserSettings;
+ relationships?: Relationship[]; // TODO
+ read_state: {
+ entries: []; // TODO
+ partial: boolean;
+ version: number;
+ };
+ user_guild_settings?: {
+ entries: UserGuildSettings[];
+ version: number;
+ partial: boolean;
+ };
+ application?: {
+ id: string;
+ flags: bigint;
+ };
+ merged_members?: Omit<Member, "settings" | "user">[][];
+ // probably all users who the user is in contact with
+ users?: {
+ avatar: string | null;
+ discriminator: string;
+ id: string;
+ username: string;
+ bot: boolean;
+ public_flags: bigint;
+ }[];
+}
+
+export interface ReadyEvent extends Event {
+ event: "READY";
+ data: ReadyEventData;
+}
+
+export interface ChannelCreateEvent extends Event {
+ event: "CHANNEL_CREATE";
+ data: Channel;
+}
+
+export interface ChannelUpdateEvent extends Event {
+ event: "CHANNEL_UPDATE";
+ data: Channel;
+}
+
+export interface ChannelDeleteEvent extends Event {
+ event: "CHANNEL_DELETE";
+ data: Channel;
+}
+
+export interface ChannelPinsUpdateEvent extends Event {
+ event: "CHANNEL_PINS_UPDATE";
+ data: {
+ guild_id?: string;
+ channel_id: string;
+ last_pin_timestamp?: number;
+ };
+}
+
+export interface GuildCreateEvent extends Event {
+ event: "GUILD_CREATE";
+ data: Guild;
+}
+
+export interface GuildUpdateEvent extends Event {
+ event: "GUILD_UPDATE";
+ data: Guild;
+}
+
+export interface GuildDeleteEvent extends Event {
+ event: "GUILD_DELETE";
+ data: {
+ id: string;
+ unavailable?: boolean;
+ };
+}
+
+export interface GuildBanAddEvent extends Event {
+ event: "GUILD_BAN_ADD";
+ data: {
+ guild_id: string;
+ user: User;
+ };
+}
+
+export interface GuildBanRemoveEvent extends Event {
+ event: "GUILD_BAN_REMOVE";
+ data: {
+ guild_id: string;
+ user: User;
+ };
+}
+
+export interface GuildEmojiUpdateEvent extends Event {
+ event: "GUILD_EMOJI_UPDATE";
+ data: {
+ guild_id: string;
+ emojis: Emoji[];
+ };
+}
+
+export interface GuildIntegrationUpdateEvent extends Event {
+ event: "GUILD_INTEGRATIONS_UPDATE";
+ data: {
+ guild_id: string;
+ };
+}
+
+export interface GuildMemberAddEvent extends Event {
+ event: "GUILD_MEMBER_ADD";
+ data: PublicMember & {
+ guild_id: string;
+ };
+}
+
+export interface GuildMemberRemoveEvent extends Event {
+ event: "GUILD_MEMBER_REMOVE";
+ data: {
+ guild_id: string;
+ user: User;
+ };
+}
+
+export interface GuildMemberUpdateEvent extends Event {
+ event: "GUILD_MEMBER_UPDATE";
+ data: {
+ guild_id: string;
+ roles: string[];
+ user: User;
+ nick?: string;
+ joined_at?: Date;
+ premium_since?: number;
+ pending?: boolean;
+ };
+}
+
+export interface GuildMembersChunkEvent extends Event {
+ event: "GUILD_MEMBERS_CHUNK";
+ data: {
+ guild_id: string;
+ members: PublicMember[];
+ chunk_index: number;
+ chunk_count: number;
+ not_found: string[];
+ presences: Presence[];
+ nonce?: string;
+ };
+}
+
+export interface GuildRoleCreateEvent extends Event {
+ event: "GUILD_ROLE_CREATE";
+ data: {
+ guild_id: string;
+ role: Role;
+ };
+}
+
+export interface GuildRoleUpdateEvent extends Event {
+ event: "GUILD_ROLE_UPDATE";
+ data: {
+ guild_id: string;
+ role: Role;
+ };
+}
+
+export interface GuildRoleDeleteEvent extends Event {
+ event: "GUILD_ROLE_DELETE";
+ data: {
+ guild_id: string;
+ role_id: string;
+ };
+}
+
+export interface InviteCreateEvent extends Event {
+ event: "INVITE_CREATE";
+ data: Omit<Invite, "guild" | "channel"> & {
+ channel_id: string;
+ guild_id?: string;
+ };
+}
+
+export interface InviteDeleteEvent extends Event {
+ event: "INVITE_DELETE";
+ data: {
+ channel_id: string;
+ guild_id?: string;
+ code: string;
+ };
+}
+
+export type MessagePayload = Omit<Message, "author_id"> & {
+ channel_id: string;
+ guild_id?: string;
+ author: PublicUser;
+ member: PublicMember;
+ mentions: (PublicUser & { member: PublicMember })[];
+};
+
+export interface MessageCreateEvent extends Event {
+ event: "MESSAGE_CREATE";
+ data: MessagePayload;
+}
+
+export interface MessageUpdateEvent extends Event {
+ event: "MESSAGE_UPDATE";
+ data: MessagePayload;
+}
+
+export interface MessageDeleteEvent extends Event {
+ event: "MESSAGE_DELETE";
+ data: {
+ id: string;
+ channel_id: string;
+ guild_id?: string;
+ };
+}
+
+export interface MessageDeleteBulkEvent extends Event {
+ event: "MESSAGE_DELETE_BULK";
+ data: {
+ ids: string[];
+ channel_id: string;
+ guild_id?: string;
+ };
+}
+
+export interface MessageReactionAddEvent extends Event {
+ event: "MESSAGE_REACTION_ADD";
+ data: {
+ user_id: string;
+ channel_id: string;
+ message_id: string;
+ guild_id?: string;
+ member?: PublicMember;
+ emoji: PartialEmoji;
+ };
+}
+
+export interface MessageReactionRemoveEvent extends Event {
+ event: "MESSAGE_REACTION_REMOVE";
+ data: {
+ user_id: string;
+ channel_id: string;
+ message_id: string;
+ guild_id?: string;
+ emoji: PartialEmoji;
+ };
+}
+
+export interface MessageReactionRemoveAllEvent extends Event {
+ event: "MESSAGE_REACTION_REMOVE_ALL";
+ data: {
+ channel_id: string;
+ message_id: string;
+ guild_id?: string;
+ };
+}
+
+export interface MessageReactionRemoveEmojiEvent extends Event {
+ event: "MESSAGE_REACTION_REMOVE_EMOJI";
+ data: {
+ channel_id: string;
+ message_id: string;
+ guild_id?: string;
+ emoji: PartialEmoji;
+ };
+}
+
+export interface PresenceUpdateEvent extends Event {
+ event: "PRESENCE_UPDATE";
+ data: Presence;
+}
+
+export interface TypingStartEvent extends Event {
+ event: "TYPING_START";
+ data: {
+ channel_id: string;
+ user_id: string;
+ timestamp: number;
+ guild_id?: string;
+ member?: PublicMember;
+ };
+}
+
+export interface UserUpdateEvent extends Event {
+ event: "USER_UPDATE";
+ data: User;
+}
+
+export interface VoiceStateUpdateEvent extends Event {
+ event: "VOICE_STATE_UPDATE";
+ data: VoiceState & {
+ member: PublicMember;
+ };
+}
+
+export interface VoiceServerUpdateEvent extends Event {
+ event: "VOICE_SERVER_UPDATE";
+ data: {
+ token: string;
+ guild_id: string;
+ endpoint: string;
+ };
+}
+
+export interface WebhooksUpdateEvent extends Event {
+ event: "WEBHOOKS_UPDATE";
+ data: {
+ guild_id: string;
+ channel_id: string;
+ };
+}
+
+export type ApplicationCommandPayload = ApplicationCommand & {
+ guild_id: string;
+};
+
+export interface ApplicationCommandCreateEvent extends Event {
+ event: "APPLICATION_COMMAND_CREATE";
+ data: ApplicationCommandPayload;
+}
+
+export interface ApplicationCommandUpdateEvent extends Event {
+ event: "APPLICATION_COMMAND_UPDATE";
+ data: ApplicationCommandPayload;
+}
+
+export interface ApplicationCommandDeleteEvent extends Event {
+ event: "APPLICATION_COMMAND_DELETE";
+ data: ApplicationCommandPayload;
+}
+
+export interface InteractionCreateEvent extends Event {
+ event: "INTERACTION_CREATE";
+ data: Interaction;
+}
+
+export interface MessageAckEvent extends Event {
+ event: "MESSAGE_ACK";
+ data: {
+ channel_id: string;
+ message_id: string;
+ version?: number;
+ manual?: boolean;
+ mention_count?: number;
+ };
+}
+
+export interface RelationshipAddEvent extends Event {
+ event: "RELATIONSHIP_ADD";
+ data: Relationship & {
+ should_notify?: boolean;
+ user: PublicUser;
+ };
+}
+
+export interface RelationshipRemoveEvent extends Event {
+ event: "RELATIONSHIP_REMOVE";
+ data: Omit<Relationship, "nickname">;
+}
+
+// located in collection events
+
+export enum EVENTEnum {
+ Ready = "READY",
+ ChannelCreate = "CHANNEL_CREATE",
+ ChannelUpdate = "CHANNEL_UPDATE",
+ ChannelDelete = "CHANNEL_DELETE",
+ ChannelPinsUpdate = "CHANNEL_PINS_UPDATE",
+ GuildCreate = "GUILD_CREATE",
+ GuildUpdate = "GUILD_UPDATE",
+ GuildDelete = "GUILD_DELETE",
+ GuildBanAdd = "GUILD_BAN_ADD",
+ GuildBanRemove = "GUILD_BAN_REMOVE",
+ GuildEmojUpdate = "GUILD_EMOJI_UPDATE",
+ GuildIntegrationsUpdate = "GUILD_INTEGRATIONS_UPDATE",
+ GuildMemberAdd = "GUILD_MEMBER_ADD",
+ GuildMemberRempve = "GUILD_MEMBER_REMOVE",
+ GuildMemberUpdate = "GUILD_MEMBER_UPDATE",
+ GuildMemberSpeaking = "GUILD_MEMBER_SPEAKING",
+ GuildMembersChunk = "GUILD_MEMBERS_CHUNK",
+ GuildRoleCreate = "GUILD_ROLE_CREATE",
+ GuildRoleDelete = "GUILD_ROLE_DELETE",
+ GuildRoleUpdate = "GUILD_ROLE_UPDATE",
+ InviteCreate = "INVITE_CREATE",
+ InviteDelete = "INVITE_DELETE",
+ MessageCreate = "MESSAGE_CREATE",
+ MessageUpdate = "MESSAGE_UPDATE",
+ MessageDelete = "MESSAGE_DELETE",
+ MessageDeleteBulk = "MESSAGE_DELETE_BULK",
+ MessageReactionAdd = "MESSAGE_REACTION_ADD",
+ MessageReactionRemove = "MESSAGE_REACTION_REMOVE",
+ MessageReactionRemoveAll = "MESSAGE_REACTION_REMOVE_ALL",
+ MessageReactionRemoveEmoji = "MESSAGE_REACTION_REMOVE_EMOJI",
+ PresenceUpdate = "PRESENCE_UPDATE",
+ TypingStart = "TYPING_START",
+ UserUpdate = "USER_UPDATE",
+ WebhooksUpdate = "WEBHOOKS_UPDATE",
+ InteractionCreate = "INTERACTION_CREATE",
+ VoiceStateUpdate = "VOICE_STATE_UPDATE",
+ VoiceServerUpdate = "VOICE_SERVER_UPDATE",
+ ApplicationCommandCreate = "APPLICATION_COMMAND_CREATE",
+ ApplicationCommandUpdate = "APPLICATION_COMMAND_UPDATE",
+ ApplicationCommandDelete = "APPLICATION_COMMAND_DELETE",
+}
+
+export type EVENT =
+ | "READY"
+ | "CHANNEL_CREATE"
+ | "CHANNEL_UPDATE"
+ | "CHANNEL_DELETE"
+ | "CHANNEL_PINS_UPDATE"
+ | "GUILD_CREATE"
+ | "GUILD_UPDATE"
+ | "GUILD_DELETE"
+ | "GUILD_BAN_ADD"
+ | "GUILD_BAN_REMOVE"
+ | "GUILD_EMOJI_UPDATE"
+ | "GUILD_INTEGRATIONS_UPDATE"
+ | "GUILD_MEMBER_ADD"
+ | "GUILD_MEMBER_REMOVE"
+ | "GUILD_MEMBER_UPDATE"
+ | "GUILD_MEMBER_SPEAKING"
+ | "GUILD_MEMBERS_CHUNK"
+ | "GUILD_ROLE_CREATE"
+ | "GUILD_ROLE_DELETE"
+ | "GUILD_ROLE_UPDATE"
+ | "INVITE_CREATE"
+ | "INVITE_DELETE"
+ | "MESSAGE_CREATE"
+ | "MESSAGE_UPDATE"
+ | "MESSAGE_DELETE"
+ | "MESSAGE_DELETE_BULK"
+ | "MESSAGE_REACTION_ADD"
+ // TODO: add a new event: bulk add reaction:
+ // | "MESSAGE_REACTION_BULK_ADD"
+ | "MESSAGE_REACTION_REMOVE"
+ | "MESSAGE_REACTION_REMOVE_ALL"
+ | "MESSAGE_REACTION_REMOVE_EMOJI"
+ | "PRESENCE_UPDATE"
+ | "TYPING_START"
+ | "USER_UPDATE"
+ | "WEBHOOKS_UPDATE"
+ | "INTERACTION_CREATE"
+ | "VOICE_STATE_UPDATE"
+ | "VOICE_SERVER_UPDATE"
+ | "APPLICATION_COMMAND_CREATE"
+ | "APPLICATION_COMMAND_UPDATE"
+ | "APPLICATION_COMMAND_DELETE"
+ | "MESSAGE_ACK"
+ | "RELATIONSHIP_ADD"
+ | "RELATIONSHIP_REMOVE"
+ | CUSTOMEVENTS;
+
+export type CUSTOMEVENTS = "INVALIDATED";
diff --git a/util/oldModels/Guild.ts b/util/oldModels/Guild.ts
new file mode 100644
index 00000000..a5dcd8e3
--- /dev/null
+++ b/util/oldModels/Guild.ts
@@ -0,0 +1,159 @@
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+import { ChannelModel } from "./Channel";
+import { EmojiModel } from "./Emoji";
+import { MemberModel } from "./Member";
+import { RoleModel } from "./Role";
+
+export interface GuildDocument extends Document, Guild {
+ id: string;
+}
+
+export interface Guild {
+ id: string;
+ afk_channel_id?: string;
+ afk_timeout?: number;
+ application_id?: string;
+ banner?: string;
+ default_message_notifications?: number;
+ description?: string;
+ discovery_splash?: string;
+ explicit_content_filter?: number;
+ features: string[];
+ icon?: string;
+ large?: boolean;
+ max_members?: number; // e.g. default 100.000
+ max_presences?: number;
+ max_video_channel_users?: number; // ? default: 25, is this max 25 streaming or watching
+ member_count?: number;
+ presence_count?: number; // users online
+ // members?: Member[]; // * Members are stored in a seperate collection
+ // roles: Role[]; // * Role are stored in a seperate collection
+ // channels: GuildChannel[]; // * Channels are stored in a seperate collection
+ // emojis: Emoji[]; // * Emojis are stored in a seperate collection
+ // voice_states: []; // * voice_states are stored in a seperate collection
+ //TODO:
+ presences?: object[];
+ mfa_level?: number;
+ name: string;
+ owner_id: string;
+ preferred_locale?: string; // only community guilds can choose this
+ premium_subscription_count?: number;
+ premium_tier?: number; // nitro boost level
+ public_updates_channel_id?: string;
+ region?: string;
+ rules_channel_id?: string;
+ splash?: string;
+ system_channel_flags?: number;
+ system_channel_id?: string;
+ unavailable?: boolean;
+ vanity_url_code?: string;
+ verification_level?: number;
+ welcome_screen: {
+ enabled: boolean;
+ description: string;
+ welcome_channels: {
+ description: string;
+ emoji_id?: string;
+ emoji_name: string;
+ channel_id: string;
+ }[];
+ };
+ widget_channel_id?: string;
+ widget_enabled?: boolean;
+}
+
+export const GuildSchema = new Schema({
+ id: { type: String, required: true },
+ afk_channel_id: String,
+ afk_timeout: Number,
+ application_id: String,
+ banner: String,
+ default_message_notifications: Number,
+ description: String,
+ discovery_splash: String,
+ explicit_content_filter: Number,
+ features: { type: [String], default: [] },
+ icon: String,
+ large: Boolean,
+ max_members: { type: Number, default: 100000 },
+ max_presences: Number,
+ max_video_channel_users: { type: Number, default: 25 },
+ member_count: Number,
+ presences: { type: [Object], default: [] },
+ presence_count: Number,
+ mfa_level: Number,
+ name: { type: String, required: true },
+ owner_id: { type: String, required: true },
+ preferred_locale: String,
+ premium_subscription_count: Number,
+ premium_tier: Number,
+ public_updates_channel_id: String,
+ region: String,
+ rules_channel_id: String,
+ splash: String,
+ system_channel_flags: Number,
+ system_channel_id: String,
+ unavailable: Boolean,
+ vanity_url_code: String,
+ verification_level: Number,
+ voice_states: { type: [Object], default: [] },
+ welcome_screen: {
+ enabled: Boolean,
+ description: String,
+ welcome_channels: [
+ {
+ description: String,
+ emoji_id: String,
+ emoji_name: String,
+ channel_id: String,
+ },
+ ],
+ },
+ widget_channel_id: String,
+ widget_enabled: Boolean,
+});
+
+GuildSchema.virtual("channels", {
+ ref: ChannelModel,
+ localField: "id",
+ foreignField: "guild_id",
+ justOne: false,
+ autopopulate: true,
+});
+
+GuildSchema.virtual("roles", {
+ ref: RoleModel,
+ localField: "id",
+ foreignField: "guild_id",
+ justOne: false,
+ autopopulate: true,
+});
+
+// nested populate is needed for member users: https://gist.github.com/yangsu/5312204
+GuildSchema.virtual("members", {
+ ref: MemberModel,
+ localField: "id",
+ foreignField: "guild_id",
+ justOne: false,
+});
+
+GuildSchema.virtual("emojis", {
+ ref: EmojiModel,
+ localField: "id",
+ foreignField: "guild_id",
+ justOne: false,
+ autopopulate: true,
+});
+
+GuildSchema.virtual("joined_at", {
+ ref: MemberModel,
+ localField: "id",
+ foreignField: "guild_id",
+ justOne: true,
+}).get((member: any, virtual: any, doc: any) => {
+ return member?.joined_at;
+});
+
+// @ts-ignore
+export const GuildModel = db.model<GuildDocument>("Guild", GuildSchema, "guilds");
diff --git a/util/oldModels/Interaction.ts b/util/oldModels/Interaction.ts
new file mode 100644
index 00000000..764247a5
--- /dev/null
+++ b/util/oldModels/Interaction.ts
@@ -0,0 +1,32 @@
+import { AllowedMentions, Embed } from "./Message";
+
+export interface Interaction {
+ id: string;
+ type: InteractionType;
+ data?: {};
+ guild_id: string;
+ channel_id: string;
+ member_id: string;
+ token: string;
+ version: number;
+}
+
+export enum InteractionType {
+ Ping = 1,
+ ApplicationCommand = 2,
+}
+
+export enum InteractionResponseType {
+ Pong = 1,
+ Acknowledge = 2,
+ ChannelMessage = 3,
+ ChannelMessageWithSource = 4,
+ AcknowledgeWithSource = 5,
+}
+
+export interface InteractionApplicationCommandCallbackData {
+ tts?: boolean;
+ content: string;
+ embeds?: Embed[];
+ allowed_mentions?: AllowedMentions;
+}
diff --git a/util/oldModels/Invite.ts b/util/oldModels/Invite.ts
new file mode 100644
index 00000000..01f12003
--- /dev/null
+++ b/util/oldModels/Invite.ts
@@ -0,0 +1,95 @@
+import { Schema, Document, Types } from "mongoose";
+import db from "../util/Database";
+import { ChannelModel } from "./Channel";
+import { PublicUserProjection, UserModel } from "./User";
+import { GuildModel } from "./Guild";
+
+export interface Invite {
+ code: string;
+ temporary: boolean;
+ uses: number;
+ max_uses: number;
+ max_age: number;
+ created_at: Date;
+ expires_at: Date;
+ guild_id: string;
+ channel_id: string;
+ inviter_id: string;
+
+ // ? What is this?
+ target_user_id?: string;
+ target_user_type?: number;
+}
+
+export interface InviteDocument extends Invite, Document {}
+
+export const InviteSchema = new Schema({
+ code: String,
+ temporary: Boolean,
+ uses: Number,
+ max_uses: Number,
+ max_age: Number,
+ created_at: Date,
+ expires_at: Date,
+ guild_id: String,
+ channel_id: String,
+ inviter_id: String,
+
+ // ? What is this?
+ target_user_id: String,
+ target_user_type: Number,
+});
+
+InviteSchema.virtual("channel", {
+ ref: ChannelModel,
+ localField: "channel_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: {
+ select: {
+ id: true,
+ name: true,
+ type: true,
+ },
+ },
+});
+
+InviteSchema.virtual("inviter", {
+ ref: UserModel,
+ localField: "inviter_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: {
+ select: PublicUserProjection,
+ },
+});
+
+InviteSchema.virtual("guild", {
+ ref: GuildModel,
+ localField: "guild_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: {
+ select: {
+ id: true,
+ name: true,
+ splash: true,
+ banner: true,
+ description: true,
+ icon: true,
+ features: true,
+ verification_level: true,
+ vanity_url_code: true,
+ welcome_screen: true,
+ nsfw: true,
+
+ // TODO: hide the following entries:
+ // channels: false,
+ // roles: false,
+ // emojis: false,
+ },
+ },
+});
+
+// @ts-ignore
+export const InviteModel = db.model<InviteDocument>("Invite", InviteSchema, "invites");
diff --git a/util/oldModels/Member.ts b/util/oldModels/Member.ts
new file mode 100644
index 00000000..d1c9ad9b
--- /dev/null
+++ b/util/oldModels/Member.ts
@@ -0,0 +1,109 @@
+import { PublicUser, PublicUserProjection, User, UserModel } from "./User";
+import { Schema, Types, Document } from "mongoose";
+import db from "../util/Database";
+
+export const PublicMemberProjection = {
+ id: true,
+ guild_id: true,
+ nick: true,
+ roles: true,
+ joined_at: true,
+ pending: true,
+ deaf: true,
+ mute: true,
+ premium_since: true,
+};
+
+export interface Member {
+ id: string;
+ guild_id: string;
+ nick?: string;
+ roles: string[];
+ joined_at: Date;
+ premium_since?: number;
+ deaf: boolean;
+ mute: boolean;
+ pending: boolean;
+ settings: UserGuildSettings;
+ read_state: Record<string, string | null>;
+ // virtual
+ user?: User;
+}
+
+export interface MemberDocument extends Member, Document {
+ id: string;
+}
+
+export interface UserGuildSettings {
+ channel_overrides: {
+ channel_id: string;
+ message_notifications: number;
+ mute_config: MuteConfig;
+ muted: boolean;
+ }[];
+ message_notifications: number;
+ mobile_push: boolean;
+ mute_config: MuteConfig;
+ muted: boolean;
+ suppress_everyone: boolean;
+ suppress_roles: boolean;
+ version: number;
+}
+
+export interface MuteConfig {
+ end_time: number;
+ selected_time_window: number;
+}
+
+const MuteConfig = {
+ end_time: Number,
+ selected_time_window: Number,
+};
+
+export const MemberSchema = new Schema({
+ id: { type: String, required: true },
+ guild_id: String,
+ nick: String,
+ roles: [String],
+ joined_at: Date,
+ premium_since: Number,
+ deaf: Boolean,
+ mute: Boolean,
+ pending: Boolean,
+ read_state: Object,
+ settings: {
+ channel_overrides: [
+ {
+ channel_id: String,
+ message_notifications: Number,
+ mute_config: MuteConfig,
+ muted: Boolean,
+ },
+ ],
+ message_notifications: Number,
+ mobile_push: Boolean,
+ mute_config: MuteConfig,
+ muted: Boolean,
+ suppress_everyone: Boolean,
+ suppress_roles: Boolean,
+ version: Number,
+ },
+});
+
+MemberSchema.virtual("user", {
+ ref: UserModel,
+ localField: "id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: {
+ select: PublicUserProjection,
+ },
+});
+
+// @ts-ignore
+export const MemberModel = db.model<MemberDocument>("Member", MemberSchema, "members");
+
+// @ts-ignore
+export interface PublicMember extends Omit<Member, "settings" | "id" | "read_state"> {
+ user: PublicUser;
+}
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");
diff --git a/util/oldModels/RateLimit.ts b/util/oldModels/RateLimit.ts
new file mode 100644
index 00000000..6a0e1ffd
--- /dev/null
+++ b/util/oldModels/RateLimit.ts
@@ -0,0 +1,25 @@
+import { Schema, Document, Types } from "mongoose";
+import db from "../util/Database";
+
+export interface Bucket {
+ id: "global" | "error" | string; // channel_239842397 | guild_238927349823 | webhook_238923423498
+ user_id: string;
+ hits: number;
+ blocked: boolean;
+ expires_at: Date;
+}
+
+export interface BucketDocument extends Bucket, Document {
+ id: string;
+}
+
+export const BucketSchema = new Schema({
+ id: { type: String, required: true },
+ user_id: { type: String, required: true }, // bot, user, oauth_application, webhook
+ hits: { type: Number, required: true }, // Number of times the user hit this bucket
+ blocked: { type: Boolean, required: true },
+ expires_at: { type: Date, required: true },
+});
+
+// @ts-ignore
+export const BucketModel = db.model<BucketDocument>("Bucket", BucketSchema, "ratelimits");
diff --git a/util/oldModels/ReadState.ts b/util/oldModels/ReadState.ts
new file mode 100644
index 00000000..9c4fb323
--- /dev/null
+++ b/util/oldModels/ReadState.ts
@@ -0,0 +1,26 @@
+import { PublicMember } from "./Member";
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+
+export interface ReadState extends Document {
+ message_id: string;
+ channel_id: string;
+ user_id: string;
+ last_message_id?: string;
+ last_pin_timestamp?: Date;
+ mention_count: number;
+ manual: boolean;
+}
+
+export const ReadStateSchema = new Schema({
+ message_id: String,
+ channel_id: String,
+ user_id: String,
+ last_message_id: String,
+ last_pin_timestamp: Date,
+ mention_count: Number,
+ manual: Boolean,
+});
+
+// @ts-ignore
+export const ReadStateModel = db.model<ReadState>("ReadState", ReadStateSchema, "readstates");
diff --git a/util/oldModels/Role.ts b/util/oldModels/Role.ts
new file mode 100644
index 00000000..c1111c84
--- /dev/null
+++ b/util/oldModels/Role.ts
@@ -0,0 +1,42 @@
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+import toBigInt from "../util/toBigInt";
+
+export interface Role {
+ id: string;
+ guild_id: string;
+ color: number;
+ hoist: boolean;
+ managed: boolean;
+ mentionable: boolean;
+ name: string;
+ permissions: bigint;
+ position: number;
+ tags?: {
+ bot_id?: string;
+ };
+}
+
+export interface RoleDocument extends Document, Role {
+ id: string;
+}
+
+export const RoleSchema = new Schema({
+ id: String,
+ guild_id: String,
+ color: Number,
+ hoist: Boolean,
+ managed: Boolean,
+ mentionable: Boolean,
+ name: String,
+ permissions: { type: String, get: toBigInt },
+ position: Number,
+ tags: {
+ bot_id: String,
+ },
+});
+
+RoleSchema.set("removeResponse", ["guild_id"]);
+
+// @ts-ignore
+export const RoleModel = db.model<RoleDocument>("Role", RoleSchema, "roles");
diff --git a/util/oldModels/Team.ts b/util/oldModels/Team.ts
new file mode 100644
index 00000000..795c82d2
--- /dev/null
+++ b/util/oldModels/Team.ts
@@ -0,0 +1,17 @@
+export interface Team {
+ icon: string | null;
+ id: string;
+ members: {
+ membership_state: number;
+ permissions: string[];
+ team_id: string;
+ user_id: string;
+ }[];
+ name: string;
+ owner_user_id: string;
+}
+
+export enum TeamMemberState {
+ INVITED = 1,
+ ACCEPTED = 2,
+}
diff --git a/util/oldModels/Template.ts b/util/oldModels/Template.ts
new file mode 100644
index 00000000..ad0f9104
--- /dev/null
+++ b/util/oldModels/Template.ts
@@ -0,0 +1,51 @@
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+import { PublicUser, User, UserModel, PublicUserProjection } from "./User";
+import { Guild, GuildModel } from "./Guild";
+
+export interface Template extends Document {
+ id: string;
+ code: string;
+ name: string;
+ description?: string;
+ usage_count?: number;
+ creator_id: string;
+ creator: User;
+ created_at: Date;
+ updated_at: Date;
+ source_guild_id: String;
+ serialized_source_guild: Guild;
+}
+
+export const TemplateSchema = new Schema({
+ id: String,
+ code: String,
+ name: String,
+ description: String,
+ usage_count: Number,
+ creator_id: String,
+ created_at: Date,
+ updated_at: Date,
+ source_guild_id: String,
+});
+
+TemplateSchema.virtual("creator", {
+ ref: UserModel,
+ localField: "creator_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: {
+ select: PublicUserProjection,
+ },
+});
+
+TemplateSchema.virtual("serialized_source_guild", {
+ ref: GuildModel,
+ localField: "source_guild_id",
+ foreignField: "id",
+ justOne: true,
+ autopopulate: true,
+});
+
+// @ts-ignore
+export const TemplateModel = db.model<Template>("Template", TemplateSchema, "templates");
diff --git a/util/oldModels/VoiceState.ts b/util/oldModels/VoiceState.ts
new file mode 100644
index 00000000..c1f90edd
--- /dev/null
+++ b/util/oldModels/VoiceState.ts
@@ -0,0 +1,34 @@
+import { PublicMember } from "./Member";
+import { Schema, model, Types, Document } from "mongoose";
+import db from "../util/Database";
+
+export interface VoiceState extends Document {
+ guild_id?: string;
+ channel_id: string;
+ user_id: string;
+ session_id: string;
+ deaf: boolean;
+ mute: boolean;
+ self_deaf: boolean;
+ self_mute: boolean;
+ self_stream?: boolean;
+ self_video: boolean;
+ suppress: boolean; // whether this user is muted by the current user
+}
+
+export const VoiceSateSchema = new Schema({
+ guild_id: String,
+ channel_id: String,
+ user_id: String,
+ session_id: String,
+ deaf: Boolean,
+ mute: Boolean,
+ self_deaf: Boolean,
+ self_mute: Boolean,
+ self_stream: Boolean,
+ self_video: Boolean,
+ suppress: Boolean, // whether this user is muted by the current user
+});
+
+// @ts-ignore
+export const VoiceStateModel = db.model<VoiceState>("VoiceState", VoiceSateSchema, "voicestates");
diff --git a/util/oldModels/Webhook.ts b/util/oldModels/Webhook.ts
new file mode 100644
index 00000000..7379e98f
--- /dev/null
+++ b/util/oldModels/Webhook.ts
@@ -0,0 +1,84 @@
+import { Schema, Document, Types } from "mongoose";
+import { transpileModule } from "typescript";
+import db from "../util/Database";
+import { ChannelModel } from "./Channel";
+import { GuildModel } from "./Guild";
+
+export interface Webhook {}
+
+export enum WebhookType {
+ Incoming = 1,
+ ChannelFollower = 2,
+}
+
+export interface WebhookDocument extends Document, Webhook {
+ id: String;
+ type: number;
+ guild_id?: string;
+ channel_id: string;
+ name?: string;
+ avatar?: string;
+ token?: string;
+ application_id?: string;
+ user_id?: string;
+ source_guild_id: string;
+}
+
+export const WebhookSchema = new Schema({
+ id: { type: String, required: true },
+ type: { type: Number, required: true },
+ guild_id: String,
+ channel_id: String,
+ name: String,
+ avatar: String,
+ token: String,
+ application_id: String,
+ user_id: String,
+ source_guild_id: String,
+ source_channel_id: String,
+});
+
+WebhookSchema.virtual("source_guild", {
+ ref: GuildModel,
+ localField: "id",
+ foreignField: "source_guild_id",
+ justOne: true,
+ autopopulate: {
+ select: {
+ icon: true,
+ id: true,
+ name: true,
+ },
+ },
+});
+
+WebhookSchema.virtual("source_channel", {
+ ref: ChannelModel,
+ localField: "id",
+ foreignField: "source_channel_id",
+ justOne: true,
+ autopopulate: {
+ select: {
+ id: true,
+ name: true,
+ },
+ },
+});
+
+WebhookSchema.virtual("source_channel", {
+ ref: ChannelModel,
+ localField: "id",
+ foreignField: "source_channel_id",
+ justOne: true,
+ autopopulate: {
+ select: {
+ id: true,
+ name: true,
+ },
+ },
+});
+
+WebhookSchema.set("removeResponse", ["source_channel_id", "source_guild_id"]);
+
+// @ts-ignore
+export const WebhookModel = db.model<WebhookDocument>("Webhook", WebhookSchema, "webhooks");
diff --git a/util/oldModels/index.ts b/util/oldModels/index.ts
new file mode 100644
index 00000000..63578a13
--- /dev/null
+++ b/util/oldModels/index.ts
@@ -0,0 +1,93 @@
+// @ts-nocheck
+import mongoose, { Schema, Document } from "mongoose";
+import mongooseAutoPopulate from "mongoose-autopopulate";
+
+type UpdateWithAggregationPipeline = UpdateAggregationStage[];
+type UpdateAggregationStage =
+ | { $addFields: any }
+ | { $set: any }
+ | { $project: any }
+ | { $unset: any }
+ | { $replaceRoot: any }
+ | { $replaceWith: any };
+type EnforceDocument<T, TMethods> = T extends Document ? T : T & Document & TMethods;
+
+declare module "mongoose" {
+ interface SchemaOptions {
+ removeResponse?: string[];
+ }
+ interface Model<T, TQueryHelpers = {}, TMethods = {}> {
+ // removed null -> always return document -> throw error if it doesn't exist
+ findOne(
+ filter?: FilterQuery<T>,
+ projection?: any | null,
+ options?: QueryOptions | null,
+ callback?: (err: CallbackError, doc: EnforceDocument<T, TMethods>) => void
+ ): QueryWithHelpers<EnforceDocument<T, TMethods>, EnforceDocument<T, TMethods>, TQueryHelpers>;
+ findOneAndUpdate(
+ filter?: FilterQuery<T>,
+ update?: UpdateQuery<T> | UpdateWithAggregationPipeline,
+ options?: QueryOptions | null,
+ callback?: (err: any, doc: EnforceDocument<T, TMethods> | null, res: any) => void
+ ): QueryWithHelpers<EnforceDocument<T, TMethods>, EnforceDocument<T, TMethods>, TQueryHelpers>;
+ }
+}
+
+var HTTPError: any;
+
+try {
+ HTTPError = require("lambert-server").HTTPError;
+} catch (e) {
+ HTTPError = Error;
+}
+
+mongoose.plugin(mongooseAutoPopulate);
+
+mongoose.plugin((schema: Schema, opts: any) => {
+ schema.set("toObject", {
+ virtuals: true,
+ versionKey: false,
+ transform(doc: any, ret: any) {
+ delete ret._id;
+ delete ret.__v;
+ const props = schema.get("removeResponse") || [];
+ props.forEach((prop: string) => {
+ delete ret[prop];
+ });
+ },
+ });
+ schema.post("findOne", function (doc, next) {
+ try {
+ // @ts-ignore
+ const isExistsQuery = JSON.stringify(this._userProvidedFields) === JSON.stringify({ _id: 1 });
+ if (!doc && !isExistsQuery) {
+ // @ts-ignore
+ return next(new HTTPError(`${this?.mongooseCollection?.name}.${this?._conditions?.id} not found`, 400));
+ }
+ // @ts-ignore
+ return next();
+ } catch (error) {
+ // @ts-ignore
+ next();
+ }
+ });
+});
+
+export * from "../models/Activity";
+export * from "./Application";
+export * from "./Ban";
+export * from "./Channel";
+export * from "./Emoji";
+export * from "./Event";
+export * from "./Template";
+export * from "./Guild";
+export * from "./Invite";
+export * from "./Interaction";
+export * from "./Member";
+export * from "./Message";
+export * from "../models/Status";
+export * from "./Role";
+export * from "./User";
+export * from "./VoiceState";
+export * from "./ReadState";
+export * from "./RateLimit";
|