1
0
mirror of https://github.com/spacebarchat/server.git synced 2024-11-23 02:42:28 +01:00
This commit is contained in:
Flam3rboy 2021-08-24 16:35:59 +02:00
parent 271e439b1a
commit 62b6ba4002
45 changed files with 7575 additions and 35804 deletions

1
util/.gitignore vendored
View File

@ -105,3 +105,4 @@ typings/
# Compiled TypeScript code # Compiled TypeScript code
dist/ dist/
database.db

View File

@ -1,67 +0,0 @@
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[];
}

View File

@ -1,220 +0,0 @@
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,
}

View File

@ -1,32 +0,0 @@
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");

View File

@ -1,111 +0,0 @@
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
}

View File

@ -1,29 +0,0 @@
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");

View File

@ -1,159 +0,0 @@
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");

View File

@ -1,95 +0,0 @@
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");

View File

@ -1,109 +0,0 @@
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;
}

View File

@ -1,368 +0,0 @@
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");

View File

@ -1,25 +0,0 @@
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");

View File

@ -1,26 +0,0 @@
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");

View File

@ -1,42 +0,0 @@
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");

View File

@ -1,17 +0,0 @@
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,
}

View File

@ -1,51 +0,0 @@
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");

View File

@ -1,34 +0,0 @@
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");

View File

@ -1,84 +0,0 @@
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");

View File

@ -1,93 +0,0 @@
// @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";

7846
util/package-lock.json generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
import "reflect-metadata"; import "reflect-metadata";
// export * as Constants from "../util/Constants"; // export * as Constants from "../util/Constants";
export * from "./models/index"; export * from "./interfaces/index";
// export * from "../util/index"; export * from "./entities/index";
export * from "./util/index";
import "./test";
// import Config from "../util/Config"; // import Config from "../util/Config";
// import db, { MongooseCache, toObject } from "./util/Database"; // import db, { MongooseCache, toObject } from "./util/Database";

View File

@ -1,14 +1,3 @@
import { User } from "./User";
import { ClientStatus, Status } from "./Status";
export interface Presence {
user: User;
guild_id?: string;
status: Status;
activities: Activity[];
client_status: ClientStatus;
}
export interface Activity { export interface Activity {
name: string; name: string;
type: ActivityType; type: ActivityType;

View File

@ -1,15 +1,17 @@
import { ConnectedAccount, PublicUser, Relationship, User, UserSettings } from "./User"; import { PublicUser, User, UserSettings } from "../entities/User";
import { DMChannel, Channel } from "./Channel"; import { Channel } from "../entities/Channel";
import { Guild } from "./Guild"; import { Guild } from "../entities/Guild";
import { Member, PublicMember, UserGuildSettings } from "./Member"; import { Member, PublicMember, UserGuildSettings } from "../entities/Member";
import { Emoji } from "./Emoji"; import { Emoji } from "../entities/Emoji";
import { Presence } from "../models/Activity"; import { Role } from "../entities/Role";
import { Role } from "./Role"; import { Invite } from "../entities/Invite";
import { Invite } from "./Invite"; import { Message, PartialEmoji } from "../entities/Message";
import { Message, PartialEmoji } from "./Message"; import { VoiceState } from "../entities/VoiceState";
import { VoiceState } from "./VoiceState"; import { ApplicationCommand } from "../entities/Application";
import { ApplicationCommand } from "./Application";
import { Interaction } from "./Interaction"; import { Interaction } from "./Interaction";
import { ConnectedAccount } from "../entities/ConnectedAccount";
import { Relationship } from "../entities/Relationship";
import { Presence } from "./Presence";
export interface Event { export interface Event {
guild_id?: string; guild_id?: string;
@ -43,7 +45,7 @@ export interface ReadyEventData {
verified: boolean; verified: boolean;
bot: boolean; bot: boolean;
}; };
private_channels: DMChannel[]; // this will be empty for bots private_channels: Channel[]; // this will be empty for bots
session_id: string; // resuming session_id: string; // resuming
guilds: Guild[]; guilds: Guild[];
analytics_token?: string; analytics_token?: string;
@ -67,12 +69,12 @@ export interface ReadyEventData {
[number, [[number, [number, number]]]], [number, [[number, [number, number]]]],
{ b: number; k: bigint[] }[] { b: number; k: bigint[] }[]
][]; ][];
guild_join_requests?: []; // ? what is this? this is new guild_join_requests?: any[]; // ? what is this? this is new
shard?: [number, number]; shard?: [number, number];
user_settings?: UserSettings; user_settings?: UserSettings;
relationships?: Relationship[]; // TODO relationships?: Relationship[]; // TODO
read_state: { read_state: {
entries: []; // TODO entries: any[]; // TODO
partial: boolean; partial: boolean;
version: number; version: number;
}; };

View File

@ -1,4 +1,4 @@
import { AllowedMentions, Embed } from "./Message"; import { AllowedMentions, Embed } from "../entities/Message";
export interface Interaction { export interface Interaction {
id: string; id: string;

View File

@ -0,0 +1,10 @@
import { ClientStatus, Status } from "./Status";
import { Activity } from "./Activity";
export interface Presence {
user_id: string;
guild_id?: string;
status: Status;
activities: Activity[];
client_status: ClientStatus;
}

View File

@ -0,0 +1,5 @@
export * from "./Activity";
export * from "./Presence";
export * from "./Interaction";
export * from "./Event";
export * from "./Status";

View File

@ -1,30 +0,0 @@
import "reflect-metadata";
import { BaseEntity, BeforeInsert, BeforeUpdate, Column, PrimaryGeneratedColumn } from "typeorm";
import { Snowflake } from "../util/Snowflake";
import { IsString, validateOrReject } from "class-validator";
export class BaseClass extends BaseEntity {
@PrimaryGeneratedColumn()
@Column()
@IsString()
id: string;
constructor(props?: any, opts: { id?: string } = {}) {
super();
this.id = opts.id || Snowflake.generate();
Object.defineProperties(this, props);
}
@BeforeUpdate()
@BeforeInsert()
async validate() {
await validateOrReject(this, {});
}
}
// @ts-ignore
global.BaseClass = BaseClass;
var test = new BaseClass({});
setTimeout(() => {}, 10000 * 1000);

View File

@ -1,209 +0,0 @@
import { Column, PrimaryColumn, PrimaryGeneratedColumn } from "typeorm";
import { Activity } from "./Activity";
import { BaseClass } from "./BaseClass";
import { ClientStatus, Status } from "./Status";
import { validateOrReject, IsInt, IsEmail, IsPhoneNumber, IsBoolean, IsString, ValidateNested } from "class-validator";
export const PublicUserProjection = {
username: true,
discriminator: true,
id: true,
public_flags: true,
avatar: true,
accent_color: true,
banner: true,
bio: true,
bot: true,
};
export class User extends BaseClass {
@Column()
@IsString()
username: string; // username max length 32, min 2 (should be configurable)
@Column()
@IsInt()
discriminator: string; // #0001 4 digit long string from #0001 - #9999
@Column()
@IsString()
avatar: string | null; // hash of the user avatar
@Column()
@IsInt()
accent_color: number | null; // banner color of user
@Column()
banner: string | null; // hash of the user banner
@Column()
@IsPhoneNumber()
phone: string | null; // phone number of the user
@Column()
@IsBoolean()
desktop: boolean; // if the user has desktop app installed
@Column()
@IsBoolean()
mobile: boolean; // if the user has mobile app installed
@Column()
@IsBoolean()
premium: boolean; // if user bought nitro
@Column()
premium_type: number; // nitro level
@Column()
@IsBoolean()
bot: boolean; // if user is bot
@Column()
bio: string; // short description of the user (max 190 chars -> should be configurable)
@Column()
@IsBoolean()
system: boolean; // shouldn't be used, the api sents this field type true, if the generated message comes from a system generated author
@Column()
@IsBoolean()
nsfw_allowed: boolean; // if the user is older than 18 (resp. Config)
@Column()
@IsBoolean()
mfa_enabled: boolean; // if multi factor authentication is enabled
@Column()
created_at: Date; // registration date
@Column()
@IsBoolean()
verified: boolean; // if the user is offically verified
@Column()
@IsBoolean()
disabled: boolean; // if the account is disabled
@Column()
@IsBoolean()
deleted: boolean; // if the user was deleted
@Column()
@IsEmail()
email: string | null; // email of the user
@Column()
flags: bigint; // UserFlags
@Column()
public_flags: bigint;
@Column("simple-array") // string in simple-array must not contain commas
@IsString({ each: true })
guilds: string[]; // array of guild ids the user is part of
@Column("simple-json")
@ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects
user_data: {
valid_tokens_since: Date; // all tokens with a previous issue date are invalid
hash: string; // hash of the password, salt is saved in password (bcrypt)
fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts
};
@Column("simple-json")
@ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects
presence: {
status: Status;
activities: Activity[];
client_status: ClientStatus;
};
@Column("simple-json")
@ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects
relationships: {
id: string;
nickname?: string;
type: RelationshipType;
}[];
@Column("simple-json")
@ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects
connected_accounts: {
access_token: string;
friend_sync: boolean;
id: string;
name: string;
revoked: boolean;
show_activity: boolean;
type: string;
verifie: boolean;
visibility: number;
}[];
@Column("simple-json")
@ValidateNested() // TODO: https://github.com/typestack/class-validator#validating-nested-objects
user_settings: {
afk_timeout: number;
allow_accessibility_detection: boolean;
animate_emoji: boolean;
animate_stickers: number;
contact_sync_enabled: boolean;
convert_emoticons: boolean;
custom_status: {
emoji_id: string | null;
emoji_name: string | null;
expires_at: number | null;
text: string | null;
};
default_guilds_restricted: boolean;
detect_platform_accounts: boolean;
developer_mode: boolean;
disable_games_tab: boolean;
enable_tts_command: boolean;
explicit_content_filter: number;
friend_source_flags: { all: boolean };
gateway_connected: boolean;
gif_auto_play: boolean;
guild_folders: // every top guild is displayed as a "folder"
{
color: number;
guild_ids: string[];
id: number;
name: string;
}[];
guild_positions: string[]; // guild ids ordered by position
inline_attachment_media: boolean;
inline_embed_media: boolean;
locale: string; // en_US
message_display_compact: boolean;
native_phone_integration_enabled: boolean;
render_embeds: boolean;
render_reactions: boolean;
restricted_guilds: string[];
show_current_game: boolean;
status: "online" | "offline" | "dnd" | "idle";
stream_notifications_enabled: boolean;
theme: "dark" | "white"; // dark
timezone_offset: number; // e.g -60
};
}
// Private user data that should never get sent to the client
export interface PublicUser {
id: string;
discriminator: string;
username: string;
avatar: string | null;
accent_color: number;
banner: string | null;
public_flags: bigint;
bot: boolean;
}
export enum RelationshipType {
outgoing = 4,
incoming = 3,
blocked = 2,
friends = 1,
}

View File

@ -1,4 +0,0 @@
export * from "./Activity";
export * from "./BaseClass";
export * from "./Status";
export * from "./User";

View File

@ -21,7 +21,7 @@ export class BitField {
* Checks whether the bitfield has a bit, or any of multiple bits. * Checks whether the bitfield has a bit, or any of multiple bits.
*/ */
any(bit: BitFieldResolvable): boolean { any(bit: BitFieldResolvable): boolean {
return (this.bitfield & BitField.resolve.call(this, bit)) !== 0n; return (this.bitfield & BitField.resolve.call(this, bit)) !== BigInt(0);
} }
/** /**
@ -61,7 +61,7 @@ export class BitField {
* @returns {BitField} These bits or new BitField if the instance is frozen. * @returns {BitField} These bits or new BitField if the instance is frozen.
*/ */
add(...bits: BitFieldResolvable[]): BitField { add(...bits: BitFieldResolvable[]): BitField {
let total = 0n; let total = BigInt(0);
for (const bit of bits) { for (const bit of bits) {
total |= BitField.resolve.call(this, bit); total |= BitField.resolve.call(this, bit);
} }
@ -75,7 +75,7 @@ export class BitField {
* @param {...BitFieldResolvable} [bits] Bits to remove * @param {...BitFieldResolvable} [bits] Bits to remove
*/ */
remove(...bits: BitFieldResolvable[]) { remove(...bits: BitFieldResolvable[]) {
let total = 0n; let total = BigInt(0);
for (const bit of bits) { for (const bit of bits) {
total |= BitField.resolve.call(this, bit); total |= BitField.resolve.call(this, bit);
} }
@ -127,15 +127,15 @@ export class BitField {
* @param {BitFieldResolvable} [bit=0] - bit(s) to resolve * @param {BitFieldResolvable} [bit=0] - bit(s) to resolve
* @returns {number} * @returns {number}
*/ */
static resolve(bit: BitFieldResolvable = 0n): bigint { static resolve(bit: BitFieldResolvable = BigInt(0)): bigint {
// @ts-ignore // @ts-ignore
const FLAGS = this.FLAGS || this.constructor?.FLAGS; const FLAGS = this.FLAGS || this.constructor?.FLAGS;
if ((typeof bit === "number" || typeof bit === "bigint") && bit >= 0n) return BigInt(bit); if ((typeof bit === "number" || typeof bit === "bigint") && bit >= BigInt(0)) return BigInt(bit);
if (bit instanceof BitField) return bit.bitfield; if (bit instanceof BitField) return bit.bitfield;
if (Array.isArray(bit)) { if (Array.isArray(bit)) {
// @ts-ignore // @ts-ignore
const resolve = this.constructor?.resolve || this.resolve; const resolve = this.constructor?.resolve || this.resolve;
return bit.map((p) => resolve.call(this, p)).reduce((prev, p) => BigInt(prev) | BigInt(p), 0n); return bit.map((p) => resolve.call(this, p)).reduce((prev, p) => BigInt(prev) | BigInt(p), BigInt(0));
} }
if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined") return FLAGS[bit]; if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined") return FLAGS[bit];
throw new RangeError("BITFIELD_INVALID: " + bit); throw new RangeError("BITFIELD_INVALID: " + bit);

View File

@ -1,28 +0,0 @@
import { VerifyOptions } from "jsonwebtoken";
export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
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,
GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16,
GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17,
THREAD_CREATED = 18,
REPLY = 19,
APPLICATION_COMMAND = 20,
THREAD_STARTER_MESSAGE = 21,
GUILD_INVITE_REMINDER = 22,
}

25
util/src/util/Database.ts Normal file
View File

@ -0,0 +1,25 @@
import "reflect-metadata";
import { createConnection } from "typeorm";
import * as Models from "../entities";
// UUID extension option is only supported with postgres
// We want to generate all id's with Snowflakes that's why we have our own BaseEntity class
var promise: Promise<any>;
export function initDatabase() {
if (promise) return promise; // prevent initalizing multiple times
// @ts-ignore
promise = createConnection({
type: "sqlite",
database: "database.db",
entities: Object.values(Models).filter((x) => x.constructor.name !== "Object"),
synchronize: true,
logging: false,
});
return promise;
}
initDatabase();

View File

@ -1,7 +1,7 @@
import { Channel } from "amqplib"; import { Channel } from "amqplib";
import { EVENT, Event } from "../models";
import { RabbitMQ } from "./RabbitMQ"; import { RabbitMQ } from "./RabbitMQ";
import EventEmitter from "events"; import EventEmitter from "events";
import { EVENT, Event } from "../interfaces";
const events = new EventEmitter(); const events = new EventEmitter();
export async function emitEvent(payload: Omit<Event, "created_at">) { export async function emitEvent(payload: Omit<Event, "created_at">) {

View File

@ -1,11 +1,8 @@
// https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js // https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah // Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
import { MemberDocument, MemberModel } from "../models/Member"; import { In } from "typeorm";
import { ChannelDocument, ChannelModel } from "../models/Channel"; import { Channel, ChannelPermissionOverwrite, Guild, Member, Role } from "../entities";
import { ChannelPermissionOverwrite } from "../models/Channel";
import { Role, RoleDocument, RoleModel } from "../models/Role";
import { BitField } from "./BitField"; import { BitField } from "./BitField";
import { GuildDocument, GuildModel } from "../models/Guild";
// TODO: check role hierarchy permission // TODO: check role hierarchy permission
var HTTPError: any; var HTTPError: any;
@ -138,12 +135,12 @@ export class Permissions extends BitField {
// ~ operator inverts deny (e.g. 011 -> 100) // ~ operator inverts deny (e.g. 011 -> 100)
// & operator only allows 1 for both ~deny and permission (e.g. 010 & 100 -> 000) // & operator only allows 1 for both ~deny and permission (e.g. 010 & 100 -> 000)
// | operators adds both together (e.g. 000 + 100 -> 100) // | operators adds both together (e.g. 000 + 100 -> 100)
}, init || 0n); }, init || BigInt(0));
} }
static rolePermission(roles: Role[]) { static rolePermission(roles: Role[]) {
// adds all permissions of all roles together (Bit OR) // adds all permissions of all roles together (Bit OR)
return roles.reduce((permission, role) => permission | BigInt(role.permissions), 0n); return roles.reduce((permission, role) => permission | BigInt(role.permissions), BigInt(0));
} }
static finalPermission({ static finalPermission({
@ -201,10 +198,10 @@ export class Permissions extends BitField {
} }
export type PermissionCache = { export type PermissionCache = {
channel?: ChannelDocument | null; channel?: Channel | null;
member?: MemberDocument | null; member?: Member | null;
guild?: GuildDocument | null; guild?: Guild | null;
roles?: RoleDocument[] | null; roles?: Role[] | null;
user_id?: string; user_id?: string;
}; };
@ -219,23 +216,23 @@ export async function getPermission(
if (!user_id) throw new HTTPError("User not found"); if (!user_id) throw new HTTPError("User not found");
if (channel_id && !channel) { if (channel_id && !channel) {
channel = await ChannelModel.findOne( channel = await Channel.findOneOrFail(
{ id: channel_id }, { id: channel_id },
{ permission_overwrites: true, recipient_ids: true, owner_id: true, guild_id: true } { select: ["permission_overwrites", "recipients", "owner", "guild"] }
).exec(); );
if (!channel) throw new HTTPError("Channel not found", 404); if (!channel) throw new HTTPError("Channel not found", 404);
if (channel.guild_id) guild_id = channel.guild_id; if (channel.guild_id) guild_id = channel.guild_id;
} }
if (guild_id) { if (guild_id) {
if (!guild) guild = await GuildModel.findOne({ id: guild_id }, { owner_id: true }).exec(); if (!guild) guild = await Guild.findOneOrFail({ id: guild_id }, { select: ["owner"] });
if (!guild) throw new HTTPError("Guild not found"); if (!guild) throw new HTTPError("Guild not found");
if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR); if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR);
if (!member) member = await MemberModel.findOne({ guild_id, id: user_id }, "roles").exec(); if (!member) member = await Member.findOneOrFail({ guild_id, id: user_id }, { select: ["roles"] });
if (!member) throw new HTTPError("Member not found"); if (!member) throw new HTTPError("Member not found");
if (!roles) roles = await RoleModel.find({ guild_id, id: { $in: member.roles } }).exec(); if (!roles) roles = await Role.find({ guild_id, id: In(member.roles) });
} }
var permission = Permissions.finalPermission({ var permission = Permissions.finalPermission({

View File

@ -1,18 +1,19 @@
import amqp, { Connection, Channel } from "amqplib"; import amqp, { Connection, Channel } from "amqplib";
import Config from "./Config"; // import Config from "./Config";
export const RabbitMQ: { connection: Connection | null; channel: Channel | null; init: () => Promise<void> } = { export const RabbitMQ: { connection: Connection | null; channel: Channel | null; init: () => Promise<void> } = {
connection: null, connection: null,
channel: null, channel: null,
init: async function () { init: async function () {
const host = Config.get().rabbitmq.host; return;
if (!host) return; // const host = Config.get().rabbitmq.host;
console.log(`[RabbitMQ] connect: ${host}`); // if (!host) return;
this.connection = await amqp.connect(host, { // console.log(`[RabbitMQ] connect: ${host}`);
timeout: 1000 * 60, // this.connection = await amqp.connect(host, {
}); // timeout: 1000 * 60,
console.log(`[RabbitMQ] connected`); // });
this.channel = await this.connection.createChannel(); // console.log(`[RabbitMQ] connected`);
console.log(`[RabbitMQ] channel created`); // this.channel = await this.connection.createChannel();
// console.log(`[RabbitMQ] channel created`);
}, },
}; };

View File

@ -1,22 +0,0 @@
// https://github.com/discordjs/discord.js/blob/master/src/util/UserFlags.js
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
import { BitField } from "./BitField";
export class UserFlags extends BitField {
static FLAGS = {
DISCORD_EMPLOYEE: BigInt(1) << BigInt(0),
PARTNERED_SERVER_OWNER: BigInt(1) << BigInt(1),
HYPESQUAD_EVENTS: BigInt(1) << BigInt(2),
BUGHUNTER_LEVEL_1: BigInt(1) << BigInt(3),
HOUSE_BRAVERY: BigInt(1) << BigInt(6),
HOUSE_BRILLIANCE: BigInt(1) << BigInt(7),
HOUSE_BALANCE: BigInt(1) << BigInt(8),
EARLY_SUPPORTER: BigInt(1) << BigInt(9),
TEAM_USER: BigInt(1) << BigInt(10),
SYSTEM: BigInt(1) << BigInt(12),
BUGHUNTER_LEVEL_2: BigInt(1) << BigInt(14),
VERIFIED_BOT: BigInt(1) << BigInt(16),
EARLY_VERIFIED_BOT_DEVELOPER: BigInt(1) << BigInt(17),
};
}

View File

@ -1,6 +1,7 @@
import { JWTOptions } from "./Constants"; import jwt, { VerifyOptions } from "jsonwebtoken";
import jwt from "jsonwebtoken"; import { User } from "../entities";
import { UserModel } from "../models";
export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
export function checkToken(token: string, jwtSecret: string): Promise<any> { export function checkToken(token: string, jwtSecret: string): Promise<any> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
@ -8,10 +9,10 @@ export function checkToken(token: string, jwtSecret: string): Promise<any> {
jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded: any) => { jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded: any) => {
if (err || !decoded) return rej("Invalid Token"); if (err || !decoded) return rej("Invalid Token");
const user = await UserModel.findOne( const user = await User.findOneOrFail(
{ id: decoded.id }, { id: decoded.id },
{ "user_data.valid_tokens_since": true, bot: true, disabled: true, deleted: true } { select: ["user_data", "bot", "disabled", "deleted"] }
).exec(); );
if (!user) return rej("Invalid Token"); if (!user) return rej("Invalid Token");
// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds // we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
if (decoded.iat * 1000 < user.user_data.valid_tokens_since.setSeconds(0, 0)) return rej("Invalid Token"); if (decoded.iat * 1000 < user.user_data.valid_tokens_since.setSeconds(0, 0)) return rej("Invalid Token");

View File

@ -1,11 +1,11 @@
export * from "./Regex"; export * from "./Regex";
export * from "./String"; export * from "./String";
export * from "./BitField"; export * from "./BitField";
export * from "./Database";
export * from "./Intents"; export * from "./Intents";
export * from "./MessageFlags"; export * from "./MessageFlags";
export * from "./Permissions"; export * from "./Permissions";
export * from "./Snowflake"; export * from "./Snowflake";
export * from "./UserFlags";
export * from "./toBigInt"; export * from "./toBigInt";
export * from "./RabbitMQ"; export * from "./RabbitMQ";
export * from "./Event"; export * from "./Event";

View File

@ -5,7 +5,7 @@
/* Basic Options */ /* Basic Options */
// "incremental": true, /* Enable incremental compilation */ // "incremental": true, /* Enable incremental compilation */
"target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, "target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
"lib": ["ES2020"] /* Specify library files to be included in the compilation. */, "lib": ["ES2020"] /* Specify library files to be included in the compilation. */,
"allowJs": true /* Allow javascript files to be compiled. */, "allowJs": true /* Allow javascript files to be compiled. */,
@ -68,6 +68,7 @@
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"resolveJsonModule": true,
"plugins": [ "plugins": [
{ {
"transform": "ts-transform-json-schema", "transform": "ts-transform-json-schema",

View File

@ -1,6 +1,5 @@
import { Schema, model, Types, Document } from "mongoose"; import { Schema, model, Types, Document } from "mongoose";
import "missing-native-js-functions"; import "missing-native-js-functions";
import db from "./Database";
import { Snowflake } from "./Snowflake"; import { Snowflake } from "./Snowflake";
import crypto from "crypto"; import crypto from "crypto";
@ -8,7 +7,7 @@ var config: any;
export default { export default {
init: async function init(defaultOpts: any = DefaultOptions) { init: async function init(defaultOpts: any = DefaultOptions) {
config = await db.collection("config").findOne({}); config = await db.collection("config").findOneOrFail({});
return this.set((config || {}).merge(defaultOpts)); return this.set((config || {}).merge(defaultOpts));
}, },
get: function get() { get: function get() {
@ -16,7 +15,7 @@ export default {
}, },
set: function set(val: any) { set: function set(val: any) {
config = val.merge(config); config = val.merge(config);
return db.collection("config").updateOne({}, { $set: val }, { upsert: true }); return db.collection("config").update({}, { $set: val }, { upsert: true });
}, },
}; };

View File

@ -1,7 +0,0 @@
import "reflect-metadata";
import { createConnection } from "typeorm";
// UUID extension option is only supported with postgres
// We want to generate all id's with Snowflakes that's why we have our own BaseEntity class
createConnection({ type: "sqlite", database: "database.db", entities: [], synchronize: true, logging: true });

View File

@ -1,83 +0,0 @@
// @ts-nocheck
import mongoose from "mongoose";
class LongSchema extends mongoose.SchemaType {
public $conditionalHandlers = {
$lt: this.handleSingle,
$lte: this.handleSingle,
$gt: this.handleSingle,
$gte: this.handleSingle,
$ne: this.handleSingle,
$in: this.handleArray,
$nin: this.handleArray,
$mod: this.handleArray,
$all: this.handleArray,
$bitsAnySet: this.handleArray,
$bitsAllSet: this.handleArray,
};
handleSingle(val: any) {
return this.cast(val, null, null, "handle");
}
handleArray(val: any) {
var self = this;
return val.map(function (m: any) {
return self.cast(m, null, null, "handle");
});
}
checkRequired(val: any) {
return null != val;
}
cast(val: any, scope?: any, init?: any, type?: string) {
if (null === val) return val;
if ("" === val) return null;
if (typeof val === "bigint") {
return mongoose.mongo.Long.fromString(val.toString());
}
if (val instanceof mongoose.mongo.Long) {
if (type === "handle" || init == false) return val;
return BigInt(val.toString());
}
if (val instanceof Number || "number" == typeof val) return BigInt(val as number);
if (!Array.isArray(val) && val.toString) return BigInt(val.toString());
//@ts-ignore
throw new SchemaType.CastError("Long", val);
}
castForQuery($conditional: string, value: any) {
var handler;
if (2 === arguments.length) {
// @ts-ignore
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error("Can't use " + $conditional + " with Long.");
}
return handler.call(this, value);
} else {
return this.cast($conditional, null, null, "query");
}
}
}
LongSchema.cast = mongoose.SchemaType.cast;
LongSchema.set = mongoose.SchemaType.set;
LongSchema.get = mongoose.SchemaType.get;
declare module "mongoose" {
namespace Types {
class Long extends mongoose.mongo.Long {}
}
namespace Schema {
namespace Types {
class Long extends LongSchema {}
}
}
}
mongoose.Schema.Types.Long = LongSchema;
mongoose.Types.Long = mongoose.mongo.Long;