diff --git a/src/util/dtos/DmChannelDTO.ts b/src/util/dtos/DmChannelDTO.ts
index 226b2f9d..fcc91204 100644
--- a/src/util/dtos/DmChannelDTO.ts
+++ b/src/util/dtos/DmChannelDTO.ts
@@ -11,7 +11,11 @@ export class DmChannelDTO {
recipients: MinimalPublicUserDTO[];
type: number;
- static async from(channel: Channel, excluded_recipients: string[] = [], origin_channel_id?: string) {
+ static async from(
+ channel: Channel,
+ excluded_recipients: string[] = [],
+ origin_channel_id?: string,
+ ) {
const obj = new DmChannelDTO();
obj.icon = channel.icon || null;
obj.id = channel.id;
@@ -23,10 +27,15 @@ export class DmChannelDTO {
obj.recipients = (
await Promise.all(
channel
- .recipients!.filter((r) => !excluded_recipients.includes(r.user_id))
+ .recipients!.filter(
+ (r) => !excluded_recipients.includes(r.user_id),
+ )
.map(async (r) => {
- return await User.findOneOrFail({ where: { id: r.user_id }, select: PublicUserProjection });
- })
+ return await User.findOneOrFail({
+ where: { id: r.user_id },
+ select: PublicUserProjection,
+ });
+ }),
)
).map((u) => new MinimalPublicUserDTO(u));
return obj;
@@ -35,7 +44,9 @@ export class DmChannelDTO {
excludedRecipients(excluded_recipients: string[]): DmChannelDTO {
return {
...this,
- recipients: this.recipients.filter((r) => !excluded_recipients.includes(r.id)),
+ recipients: this.recipients.filter(
+ (r) => !excluded_recipients.includes(r.id),
+ ),
};
}
}
diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts
index 7b4b17eb..055b6f4b 100644
--- a/src/util/entities/Attachment.ts
+++ b/src/util/entities/Attachment.ts
@@ -1,4 +1,11 @@
-import { BeforeRemove, Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import {
+ BeforeRemove,
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToOne,
+ RelationId,
+} from "typeorm";
import { URL } from "url";
import { deleteFile } from "../util/cdn";
import { BaseClass } from "./BaseClass";
@@ -31,9 +38,13 @@ export class Attachment extends BaseClass {
message_id: string;
@JoinColumn({ name: "message_id" })
- @ManyToOne(() => require("./Message").Message, (message: import("./Message").Message) => message.attachments, {
- onDelete: "CASCADE",
- })
+ @ManyToOne(
+ () => require("./Message").Message,
+ (message: import("./Message").Message) => message.attachments,
+ {
+ onDelete: "CASCADE",
+ },
+ )
message: import("./Message").Message;
@BeforeRemove()
diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts
index b003e7ba..9cc97742 100644
--- a/src/util/entities/AuditLog.ts
+++ b/src/util/entities/AuditLog.ts
@@ -5,24 +5,24 @@ import { User } from "./User";
export enum AuditLogEvents {
// guild level
- GUILD_UPDATE = 1,
+ GUILD_UPDATE = 1,
GUILD_IMPORT = 2,
GUILD_EXPORTED = 3,
GUILD_ARCHIVE = 4,
GUILD_UNARCHIVE = 5,
// join-leave
- USER_JOIN = 6,
+ USER_JOIN = 6,
USER_LEAVE = 7,
// channels
- CHANNEL_CREATE = 10,
+ CHANNEL_CREATE = 10,
CHANNEL_UPDATE = 11,
CHANNEL_DELETE = 12,
// permission overrides
- CHANNEL_OVERWRITE_CREATE = 13,
+ CHANNEL_OVERWRITE_CREATE = 13,
CHANNEL_OVERWRITE_UPDATE = 14,
CHANNEL_OVERWRITE_DELETE = 15,
// kick and ban
- MEMBER_KICK = 20,
+ MEMBER_KICK = 20,
MEMBER_PRUNE = 21,
MEMBER_BAN_ADD = 22,
MEMBER_BAN_REMOVE = 23,
@@ -79,17 +79,17 @@ export enum AuditLogEvents {
// application commands
APPLICATION_COMMAND_PERMISSION_UPDATE = 121,
// automod
- POLICY_CREATE = 140,
+ POLICY_CREATE = 140,
POLICY_UPDATE = 141,
POLICY_DELETE = 142,
- MESSAGE_BLOCKED_BY_POLICIES = 143, // in fosscord, blocked messages are stealth-dropped
+ MESSAGE_BLOCKED_BY_POLICIES = 143, // in fosscord, blocked messages are stealth-dropped
// instance policies affecting the guild
GUILD_AFFECTED_BY_POLICIES = 216,
// message moves
IN_GUILD_MESSAGE_MOVE = 223,
CROSS_GUILD_MESSAGE_MOVE = 224,
// message routing
- ROUTE_CREATE = 225,
+ ROUTE_CREATE = 225,
ROUTE_UPDATE = 226,
}
diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts
index d532a39a..81cdbb6d 100644
--- a/src/util/entities/BackupCodes.ts
+++ b/src/util/entities/BackupCodes.ts
@@ -24,7 +24,7 @@ export function generateMfaBackupCodes(user_id: string) {
for (let i = 0; i < 10; i++) {
const code = BackupCode.create({
user: { id: user_id },
- code: crypto.randomBytes(4).toString("hex"), // 8 characters
+ code: crypto.randomBytes(4).toString("hex"), // 8 characters
consumed: false,
expired: false,
});
@@ -32,4 +32,4 @@ export function generateMfaBackupCodes(user_id: string) {
}
return backup_codes;
-}
\ No newline at end of file
+}
diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts
index d5a7c2bf..9942b60e 100644
--- a/src/util/entities/BaseClass.ts
+++ b/src/util/entities/BaseClass.ts
@@ -1,5 +1,12 @@
import "reflect-metadata";
-import { BaseEntity, BeforeInsert, BeforeUpdate, FindOptionsWhere, ObjectIdColumn, PrimaryColumn } from "typeorm";
+import {
+ BaseEntity,
+ BeforeInsert,
+ BeforeUpdate,
+ FindOptionsWhere,
+ ObjectIdColumn,
+ PrimaryColumn,
+} from "typeorm";
import { Snowflake } from "../util/Snowflake";
import "missing-native-js-functions";
import { getDatabase } from "..";
@@ -22,23 +29,40 @@ export class BaseClassWithoutId extends BaseEntity {
toJSON(): any {
return Object.fromEntries(
this.metadata!.columns // @ts-ignore
- .map((x) => [x.propertyName, this[x.propertyName]]) // @ts-ignore
- .concat(this.metadata.relations.map((x) => [x.propertyName, this[x.propertyName]]))
+ .map((x) => [x.propertyName, this[x.propertyName]])
+ .concat(
+ // @ts-ignore
+ this.metadata.relations.map((x) => [
+ x.propertyName,
+ // @ts-ignore
+ this[x.propertyName],
+ ]),
+ ),
);
}
- static increment<T extends BaseClass>(conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string) {
+ static increment<T extends BaseClass>(
+ conditions: FindOptionsWhere<T>,
+ propertyPath: string,
+ value: number | string,
+ ) {
const repository = this.getRepository();
return repository.increment(conditions, propertyPath, value);
}
- static decrement<T extends BaseClass>(conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string) {
+ static decrement<T extends BaseClass>(
+ conditions: FindOptionsWhere<T>,
+ propertyPath: string,
+ value: number | string,
+ ) {
const repository = this.getRepository();
return repository.decrement(conditions, propertyPath, value);
}
}
-export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") ? ObjectIdColumn : PrimaryColumn;
+export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb")
+ ? ObjectIdColumn
+ : PrimaryColumn;
export class BaseClass extends BaseClassWithoutId {
@PrimaryIdColumn()
diff --git a/src/util/entities/Categories.ts b/src/util/entities/Categories.ts
index 81fbc303..f12b237d 100644
--- a/src/util/entities/Categories.ts
+++ b/src/util/entities/Categories.ts
@@ -1,4 +1,4 @@
-import { PrimaryColumn, Column, Entity} from "typeorm";
+import { PrimaryColumn, Column, Entity } from "typeorm";
import { BaseClassWithoutId } from "./BaseClass";
// TODO: categories:
@@ -16,18 +16,18 @@ import { BaseClassWithoutId } from "./BaseClass";
// Also populate discord default categories
@Entity("categories")
-export class Categories extends BaseClassWithoutId { // Not using snowflake
-
- @PrimaryColumn()
- id: number;
+export class Categories extends BaseClassWithoutId {
+ // Not using snowflake
- @Column({ nullable: true })
- name: string;
+ @PrimaryColumn()
+ id: number;
- @Column({ type: "simple-json" })
- localizations: string;
+ @Column({ nullable: true })
+ name: string;
- @Column({ nullable: true })
- is_primary: boolean;
+ @Column({ type: "simple-json" })
+ localizations: string;
-}
\ No newline at end of file
+ @Column({ nullable: true })
+ is_primary: boolean;
+}
diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts
index 2200bfa3..14f36857 100644
--- a/src/util/entities/Channel.ts
+++ b/src/util/entities/Channel.ts
@@ -1,389 +1,457 @@
-import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
-import { BaseClass } from "./BaseClass";
-import { Guild } from "./Guild";
-import { PublicUserProjection, User } from "./User";
-import { HTTPError } from "lambert-server";
-import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters, ChannelTypes } from "../util";
-import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
-import { Recipient } from "./Recipient";
-import { Message } from "./Message";
-import { ReadState } from "./ReadState";
-import { Invite } from "./Invite";
-import { VoiceState } from "./VoiceState";
-import { Webhook } from "./Webhook";
-import { DmChannelDTO } from "../dtos";
-
-export enum ChannelType {
- GUILD_TEXT = 0, // a text channel within a guild
- DM = 1, // a direct message between users
- GUILD_VOICE = 2, // a voice channel within a guild
- GROUP_DM = 3, // a direct message between multiple users
- GUILD_CATEGORY = 4, // an organizational category that contains zero or more channels
- GUILD_NEWS = 5, // a channel that users can follow and crosspost into a guild or route
- GUILD_STORE = 6, // a channel in which game developers can sell their things
- ENCRYPTED = 7, // end-to-end encrypted channel
- ENCRYPTED_THREAD = 8, // end-to-end encrypted thread channel
- TRANSACTIONAL = 9, // event chain style transactional channel
- GUILD_NEWS_THREAD = 10, // a temporary sub-channel within a GUILD_NEWS channel
- GUILD_PUBLIC_THREAD = 11, // a temporary sub-channel within a GUILD_TEXT channel
- GUILD_PRIVATE_THREAD = 12, // a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission
- GUILD_STAGE_VOICE = 13, // a voice channel for hosting events with an audience
- DIRECTORY = 14, // guild directory listing channel
- GUILD_FORUM = 15, // forum composed of IM threads
- TICKET_TRACKER = 33, // ticket tracker, individual ticket items shall have type 12
- KANBAN = 34, // confluence like kanban board
- VOICELESS_WHITEBOARD = 35, // whiteboard but without voice (whiteboard + voice is the same as stage)
- CUSTOM_START = 64, // start custom channel types from here
- UNHANDLED = 255 // unhandled unowned pass-through channel type
-}
-
-@Entity("channels")
-export class Channel extends BaseClass {
- @Column()
- created_at: Date;
-
- @Column({ nullable: true })
- name?: string;
-
- @Column({ type: "text", nullable: true })
- icon?: string | null;
-
- @Column({ type: "int" })
- type: ChannelType;
-
- @OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, {
- cascade: true,
- orphanedRowAction: "delete",
- })
- recipients?: Recipient[];
-
- @Column({ nullable: true })
- last_message_id?: string;
-
- @Column({ nullable: true })
- @RelationId((channel: Channel) => channel.guild)
- guild_id?: string;
-
- @JoinColumn({ name: "guild_id" })
- @ManyToOne(() => Guild, {
- onDelete: "CASCADE",
- })
- guild: Guild;
-
- @Column({ nullable: true })
- @RelationId((channel: Channel) => channel.parent)
- parent_id: string;
-
- @JoinColumn({ name: "parent_id" })
- @ManyToOne(() => Channel)
- parent?: Channel;
-
- // for group DMs and owned custom channel types
- @Column({ nullable: true })
- @RelationId((channel: Channel) => channel.owner)
- owner_id?: string;
-
- @JoinColumn({ name: "owner_id" })
- @ManyToOne(() => User)
- owner: User;
-
- @Column({ nullable: true })
- last_pin_timestamp?: number;
-
- @Column({ nullable: true })
- default_auto_archive_duration?: number;
-
- @Column({ nullable: true })
- position?: number;
-
- @Column({ type: "simple-json", nullable: true })
- permission_overwrites?: ChannelPermissionOverwrite[];
-
- @Column({ nullable: true })
- video_quality_mode?: number;
-
- @Column({ nullable: true })
- bitrate?: number;
-
- @Column({ nullable: true })
- user_limit?: number;
-
- @Column()
- nsfw: boolean = false;
-
- @Column({ nullable: true })
- rate_limit_per_user?: number;
-
- @Column({ nullable: true })
- topic?: string;
-
- @OneToMany(() => Invite, (invite: Invite) => invite.channel, {
- cascade: true,
- orphanedRowAction: "delete",
- })
- invites?: Invite[];
-
- @Column({ nullable: true })
- retention_policy_id?: string;
-
- @OneToMany(() => Message, (message: Message) => message.channel, {
- cascade: true,
- orphanedRowAction: "delete",
- })
- messages?: Message[];
-
- @OneToMany(() => VoiceState, (voice_state: VoiceState) => voice_state.channel, {
- cascade: true,
- orphanedRowAction: "delete",
- })
- voice_states?: VoiceState[];
-
- @OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, {
- cascade: true,
- orphanedRowAction: "delete",
- })
- read_states?: ReadState[];
-
- @OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, {
- cascade: true,
- orphanedRowAction: "delete",
- })
- webhooks?: Webhook[];
-
- // TODO: DM channel
- static async createChannel(
- channel: Partial<Channel>,
- user_id: string = "0",
- opts?: {
- keepId?: boolean;
- skipExistsCheck?: boolean;
- skipPermissionCheck?: boolean;
- skipEventEmit?: boolean;
- skipNameChecks?: boolean;
- }
- ) {
- if (!opts?.skipPermissionCheck) {
- // Always check if user has permission first
- const permissions = await getPermission(user_id, channel.guild_id);
- permissions.hasThrow("MANAGE_CHANNELS");
- }
-
- if (!opts?.skipNameChecks) {
- const guild = await Guild.findOneOrFail({ where: { id: channel.guild_id } });
- if (!guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") && channel.name) {
- for (var character of InvisibleCharacters)
- if (channel.name.includes(character))
- throw new HTTPError("Channel name cannot include invalid characters", 403);
-
- // Categories skip these checks on discord.com
- if (channel.type !== ChannelType.GUILD_CATEGORY) {
- if (channel.name.includes(" "))
- throw new HTTPError("Channel name cannot include invalid characters", 403);
-
- if (channel.name.match(/\-\-+/g))
- throw new HTTPError("Channel name cannot include multiple adjacent dashes.", 403);
-
- if (channel.name.charAt(0) === "-" ||
- channel.name.charAt(channel.name.length - 1) === "-")
- throw new HTTPError("Channel name cannot start/end with dash.", 403);
- }
- else
- channel.name = channel.name.trim(); //category names are trimmed client side on discord.com
- }
-
- if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) {
- if (!channel.name)
- throw new HTTPError("Channel name cannot be empty.", 403);
- }
- }
-
- switch (channel.type) {
- case ChannelType.GUILD_TEXT:
- case ChannelType.GUILD_NEWS:
- case ChannelType.GUILD_VOICE:
- if (channel.parent_id && !opts?.skipExistsCheck) {
- const exists = await Channel.findOneOrFail({ where: { id: channel.parent_id } });
- if (!exists) throw new HTTPError("Parent id channel doesn't exist", 400);
- if (exists.guild_id !== channel.guild_id)
- throw new HTTPError("The category channel needs to be in the guild");
- }
- break;
- case ChannelType.GUILD_CATEGORY:
- case ChannelType.UNHANDLED:
- break;
- case ChannelType.DM:
- case ChannelType.GROUP_DM:
- throw new HTTPError("You can't create a dm channel in a guild");
- case ChannelType.GUILD_STORE:
- default:
- throw new HTTPError("Not yet supported");
- }
-
- if (!channel.permission_overwrites) channel.permission_overwrites = [];
- // TODO: eagerly auto generate position of all guild channels
-
- channel = {
- ...channel,
- ...(!opts?.keepId && { id: Snowflake.generate() }),
- created_at: new Date(),
- position: (channel.type === ChannelType.UNHANDLED ? 0 : channel.position) || 0,
- };
-
- await Promise.all([
- Channel.create(channel).save(),
- !opts?.skipEventEmit
- ? emitEvent({
- event: "CHANNEL_CREATE",
- data: channel,
- guild_id: channel.guild_id,
- } as ChannelCreateEvent)
- : Promise.resolve(),
- ]);
-
- return channel;
- }
-
- static async createDMChannel(recipients: string[], creator_user_id: string, name?: string) {
- recipients = recipients.unique().filter((x) => x !== creator_user_id);
- // TODO: check config for max number of recipients
- /** if you want to disallow note to self channels, uncomment the conditional below
-
- const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) });
- if (otherRecipientsUsers.length !== recipients.length) {
- throw new HTTPError("Recipient/s not found");
- }
- **/
-
- const type = recipients.length > 1 ? ChannelType.GROUP_DM : ChannelType.DM;
-
- let channel = null;
-
- const channelRecipients = [...recipients, creator_user_id];
-
- const userRecipients = await Recipient.find({
- where: { user_id: creator_user_id },
- relations: ["channel", "channel.recipients"],
- });
-
- for (let ur of userRecipients) {
- let re = ur.channel.recipients!.map((r) => r.user_id);
- if (re.length === channelRecipients.length) {
- if (containsAll(re, channelRecipients)) {
- if (channel == null) {
- channel = ur.channel;
- await ur.assign({ closed: false }).save();
- }
- }
- }
- }
-
- if (channel == null) {
- name = trimSpecial(name);
-
- channel = await Channel.create({
- name,
- type,
- owner_id: undefined,
- created_at: new Date(),
- last_message_id: undefined,
- recipients: channelRecipients.map(
- (x) =>
- Recipient.create({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })
- ),
- nsfw: false,
- }).save();
- }
-
- const channel_dto = await DmChannelDTO.from(channel);
-
- if (type === ChannelType.GROUP_DM) {
- for (let recipient of channel.recipients!) {
- await emitEvent({
- event: "CHANNEL_CREATE",
- data: channel_dto.excludedRecipients([recipient.user_id]),
- user_id: recipient.user_id,
- });
- }
- } else {
- await emitEvent({ event: "CHANNEL_CREATE", data: channel_dto, user_id: creator_user_id });
- }
-
- if (recipients.length === 1) return channel_dto;
- else return channel_dto.excludedRecipients([creator_user_id]);
- }
-
- static async removeRecipientFromChannel(channel: Channel, user_id: string) {
- await Recipient.delete({ channel_id: channel.id, user_id: user_id });
- channel.recipients = channel.recipients?.filter((r) => r.user_id !== user_id);
-
- if (channel.recipients?.length === 0) {
- await Channel.deleteChannel(channel);
- await emitEvent({
- event: "CHANNEL_DELETE",
- data: await DmChannelDTO.from(channel, [user_id]),
- user_id: user_id,
- });
- return;
- }
-
- await emitEvent({
- event: "CHANNEL_DELETE",
- data: await DmChannelDTO.from(channel, [user_id]),
- user_id: user_id,
- });
-
- //If the owner leave the server user is the new owner
- if (channel.owner_id === user_id) {
- channel.owner_id = "1"; // The channel is now owned by the server user
- await emitEvent({
- event: "CHANNEL_UPDATE",
- data: await DmChannelDTO.from(channel, [user_id]),
- channel_id: channel.id,
- });
- }
-
- await channel.save();
-
- await emitEvent({
- event: "CHANNEL_RECIPIENT_REMOVE",
- data: {
- channel_id: channel.id,
- user: await User.findOneOrFail({ where: { id: user_id }, select: PublicUserProjection }),
- },
- channel_id: channel.id,
- } as ChannelRecipientRemoveEvent);
- }
-
- static async deleteChannel(channel: Channel) {
- await Message.delete({ channel_id: channel.id }); //TODO we should also delete the attachments from the cdn but to do that we need to move cdn.ts in util
- //TODO before deleting the channel we should check and delete other relations
- await Channel.delete({ id: channel.id });
- }
-
- isDm() {
- return this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM;
- }
-
- // Does the channel support sending messages ( eg categories do not )
- isWritable() {
- const disallowedChannelTypes = [
- ChannelType.GUILD_CATEGORY,
- ChannelType.GUILD_STAGE_VOICE,
- ChannelType.VOICELESS_WHITEBOARD,
- ];
- return disallowedChannelTypes.indexOf(this.type) == -1;
- }
-}
-
-export interface ChannelPermissionOverwrite {
- allow: string;
- deny: string;
- id: string;
- type: ChannelPermissionOverwriteType;
-}
-
-export enum ChannelPermissionOverwriteType {
- role = 0,
- member = 1,
- group = 2,
-}
+import {
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToOne,
+ OneToMany,
+ RelationId,
+} from "typeorm";
+import { BaseClass } from "./BaseClass";
+import { Guild } from "./Guild";
+import { PublicUserProjection, User } from "./User";
+import { HTTPError } from "lambert-server";
+import {
+ containsAll,
+ emitEvent,
+ getPermission,
+ Snowflake,
+ trimSpecial,
+ InvisibleCharacters,
+ ChannelTypes,
+} from "../util";
+import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
+import { Recipient } from "./Recipient";
+import { Message } from "./Message";
+import { ReadState } from "./ReadState";
+import { Invite } from "./Invite";
+import { VoiceState } from "./VoiceState";
+import { Webhook } from "./Webhook";
+import { DmChannelDTO } from "../dtos";
+
+export enum ChannelType {
+ GUILD_TEXT = 0, // a text channel within a guild
+ DM = 1, // a direct message between users
+ GUILD_VOICE = 2, // a voice channel within a guild
+ GROUP_DM = 3, // a direct message between multiple users
+ GUILD_CATEGORY = 4, // an organizational category that contains zero or more channels
+ GUILD_NEWS = 5, // a channel that users can follow and crosspost into a guild or route
+ GUILD_STORE = 6, // a channel in which game developers can sell their things
+ ENCRYPTED = 7, // end-to-end encrypted channel
+ ENCRYPTED_THREAD = 8, // end-to-end encrypted thread channel
+ TRANSACTIONAL = 9, // event chain style transactional channel
+ GUILD_NEWS_THREAD = 10, // a temporary sub-channel within a GUILD_NEWS channel
+ GUILD_PUBLIC_THREAD = 11, // a temporary sub-channel within a GUILD_TEXT channel
+ GUILD_PRIVATE_THREAD = 12, // a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission
+ GUILD_STAGE_VOICE = 13, // a voice channel for hosting events with an audience
+ DIRECTORY = 14, // guild directory listing channel
+ GUILD_FORUM = 15, // forum composed of IM threads
+ TICKET_TRACKER = 33, // ticket tracker, individual ticket items shall have type 12
+ KANBAN = 34, // confluence like kanban board
+ VOICELESS_WHITEBOARD = 35, // whiteboard but without voice (whiteboard + voice is the same as stage)
+ CUSTOM_START = 64, // start custom channel types from here
+ UNHANDLED = 255, // unhandled unowned pass-through channel type
+}
+
+@Entity("channels")
+export class Channel extends BaseClass {
+ @Column()
+ created_at: Date;
+
+ @Column({ nullable: true })
+ name?: string;
+
+ @Column({ type: "text", nullable: true })
+ icon?: string | null;
+
+ @Column({ type: "int" })
+ type: ChannelType;
+
+ @OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, {
+ cascade: true,
+ orphanedRowAction: "delete",
+ })
+ recipients?: Recipient[];
+
+ @Column({ nullable: true })
+ last_message_id?: string;
+
+ @Column({ nullable: true })
+ @RelationId((channel: Channel) => channel.guild)
+ guild_id?: string;
+
+ @JoinColumn({ name: "guild_id" })
+ @ManyToOne(() => Guild, {
+ onDelete: "CASCADE",
+ })
+ guild: Guild;
+
+ @Column({ nullable: true })
+ @RelationId((channel: Channel) => channel.parent)
+ parent_id: string;
+
+ @JoinColumn({ name: "parent_id" })
+ @ManyToOne(() => Channel)
+ parent?: Channel;
+
+ // for group DMs and owned custom channel types
+ @Column({ nullable: true })
+ @RelationId((channel: Channel) => channel.owner)
+ owner_id?: string;
+
+ @JoinColumn({ name: "owner_id" })
+ @ManyToOne(() => User)
+ owner: User;
+
+ @Column({ nullable: true })
+ last_pin_timestamp?: number;
+
+ @Column({ nullable: true })
+ default_auto_archive_duration?: number;
+
+ @Column({ nullable: true })
+ position?: number;
+
+ @Column({ type: "simple-json", nullable: true })
+ permission_overwrites?: ChannelPermissionOverwrite[];
+
+ @Column({ nullable: true })
+ video_quality_mode?: number;
+
+ @Column({ nullable: true })
+ bitrate?: number;
+
+ @Column({ nullable: true })
+ user_limit?: number;
+
+ @Column()
+ nsfw: boolean = false;
+
+ @Column({ nullable: true })
+ rate_limit_per_user?: number;
+
+ @Column({ nullable: true })
+ topic?: string;
+
+ @OneToMany(() => Invite, (invite: Invite) => invite.channel, {
+ cascade: true,
+ orphanedRowAction: "delete",
+ })
+ invites?: Invite[];
+
+ @Column({ nullable: true })
+ retention_policy_id?: string;
+
+ @OneToMany(() => Message, (message: Message) => message.channel, {
+ cascade: true,
+ orphanedRowAction: "delete",
+ })
+ messages?: Message[];
+
+ @OneToMany(
+ () => VoiceState,
+ (voice_state: VoiceState) => voice_state.channel,
+ {
+ cascade: true,
+ orphanedRowAction: "delete",
+ },
+ )
+ voice_states?: VoiceState[];
+
+ @OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, {
+ cascade: true,
+ orphanedRowAction: "delete",
+ })
+ read_states?: ReadState[];
+
+ @OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, {
+ cascade: true,
+ orphanedRowAction: "delete",
+ })
+ webhooks?: Webhook[];
+
+ // TODO: DM channel
+ static async createChannel(
+ channel: Partial<Channel>,
+ user_id: string = "0",
+ opts?: {
+ keepId?: boolean;
+ skipExistsCheck?: boolean;
+ skipPermissionCheck?: boolean;
+ skipEventEmit?: boolean;
+ skipNameChecks?: boolean;
+ },
+ ) {
+ if (!opts?.skipPermissionCheck) {
+ // Always check if user has permission first
+ const permissions = await getPermission(user_id, channel.guild_id);
+ permissions.hasThrow("MANAGE_CHANNELS");
+ }
+
+ if (!opts?.skipNameChecks) {
+ const guild = await Guild.findOneOrFail({
+ where: { id: channel.guild_id },
+ });
+ if (
+ !guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") &&
+ channel.name
+ ) {
+ for (var character of InvisibleCharacters)
+ if (channel.name.includes(character))
+ throw new HTTPError(
+ "Channel name cannot include invalid characters",
+ 403,
+ );
+
+ // Categories skip these checks on discord.com
+ if (channel.type !== ChannelType.GUILD_CATEGORY) {
+ if (channel.name.includes(" "))
+ throw new HTTPError(
+ "Channel name cannot include invalid characters",
+ 403,
+ );
+
+ if (channel.name.match(/\-\-+/g))
+ throw new HTTPError(
+ "Channel name cannot include multiple adjacent dashes.",
+ 403,
+ );
+
+ if (
+ channel.name.charAt(0) === "-" ||
+ channel.name.charAt(channel.name.length - 1) === "-"
+ )
+ throw new HTTPError(
+ "Channel name cannot start/end with dash.",
+ 403,
+ );
+ } else channel.name = channel.name.trim(); //category names are trimmed client side on discord.com
+ }
+
+ if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) {
+ if (!channel.name)
+ throw new HTTPError("Channel name cannot be empty.", 403);
+ }
+ }
+
+ switch (channel.type) {
+ case ChannelType.GUILD_TEXT:
+ case ChannelType.GUILD_NEWS:
+ case ChannelType.GUILD_VOICE:
+ if (channel.parent_id && !opts?.skipExistsCheck) {
+ const exists = await Channel.findOneOrFail({
+ where: { id: channel.parent_id },
+ });
+ if (!exists)
+ throw new HTTPError(
+ "Parent id channel doesn't exist",
+ 400,
+ );
+ if (exists.guild_id !== channel.guild_id)
+ throw new HTTPError(
+ "The category channel needs to be in the guild",
+ );
+ }
+ break;
+ case ChannelType.GUILD_CATEGORY:
+ case ChannelType.UNHANDLED:
+ break;
+ case ChannelType.DM:
+ case ChannelType.GROUP_DM:
+ throw new HTTPError("You can't create a dm channel in a guild");
+ case ChannelType.GUILD_STORE:
+ default:
+ throw new HTTPError("Not yet supported");
+ }
+
+ if (!channel.permission_overwrites) channel.permission_overwrites = [];
+ // TODO: eagerly auto generate position of all guild channels
+
+ channel = {
+ ...channel,
+ ...(!opts?.keepId && { id: Snowflake.generate() }),
+ created_at: new Date(),
+ position:
+ (channel.type === ChannelType.UNHANDLED
+ ? 0
+ : channel.position) || 0,
+ };
+
+ await Promise.all([
+ Channel.create(channel).save(),
+ !opts?.skipEventEmit
+ ? emitEvent({
+ event: "CHANNEL_CREATE",
+ data: channel,
+ guild_id: channel.guild_id,
+ } as ChannelCreateEvent)
+ : Promise.resolve(),
+ ]);
+
+ return channel;
+ }
+
+ static async createDMChannel(
+ recipients: string[],
+ creator_user_id: string,
+ name?: string,
+ ) {
+ recipients = recipients.unique().filter((x) => x !== creator_user_id);
+ // TODO: check config for max number of recipients
+ /** if you want to disallow note to self channels, uncomment the conditional below
+
+ const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) });
+ if (otherRecipientsUsers.length !== recipients.length) {
+ throw new HTTPError("Recipient/s not found");
+ }
+ **/
+
+ const type =
+ recipients.length > 1 ? ChannelType.GROUP_DM : ChannelType.DM;
+
+ let channel = null;
+
+ const channelRecipients = [...recipients, creator_user_id];
+
+ const userRecipients = await Recipient.find({
+ where: { user_id: creator_user_id },
+ relations: ["channel", "channel.recipients"],
+ });
+
+ for (let ur of userRecipients) {
+ let re = ur.channel.recipients!.map((r) => r.user_id);
+ if (re.length === channelRecipients.length) {
+ if (containsAll(re, channelRecipients)) {
+ if (channel == null) {
+ channel = ur.channel;
+ await ur.assign({ closed: false }).save();
+ }
+ }
+ }
+ }
+
+ if (channel == null) {
+ name = trimSpecial(name);
+
+ channel = await Channel.create({
+ name,
+ type,
+ owner_id: undefined,
+ created_at: new Date(),
+ last_message_id: undefined,
+ recipients: channelRecipients.map((x) =>
+ Recipient.create({
+ user_id: x,
+ closed: !(
+ type === ChannelType.GROUP_DM ||
+ x === creator_user_id
+ ),
+ }),
+ ),
+ nsfw: false,
+ }).save();
+ }
+
+ const channel_dto = await DmChannelDTO.from(channel);
+
+ if (type === ChannelType.GROUP_DM) {
+ for (let recipient of channel.recipients!) {
+ await emitEvent({
+ event: "CHANNEL_CREATE",
+ data: channel_dto.excludedRecipients([recipient.user_id]),
+ user_id: recipient.user_id,
+ });
+ }
+ } else {
+ await emitEvent({
+ event: "CHANNEL_CREATE",
+ data: channel_dto,
+ user_id: creator_user_id,
+ });
+ }
+
+ if (recipients.length === 1) return channel_dto;
+ else return channel_dto.excludedRecipients([creator_user_id]);
+ }
+
+ static async removeRecipientFromChannel(channel: Channel, user_id: string) {
+ await Recipient.delete({ channel_id: channel.id, user_id: user_id });
+ channel.recipients = channel.recipients?.filter(
+ (r) => r.user_id !== user_id,
+ );
+
+ if (channel.recipients?.length === 0) {
+ await Channel.deleteChannel(channel);
+ await emitEvent({
+ event: "CHANNEL_DELETE",
+ data: await DmChannelDTO.from(channel, [user_id]),
+ user_id: user_id,
+ });
+ return;
+ }
+
+ await emitEvent({
+ event: "CHANNEL_DELETE",
+ data: await DmChannelDTO.from(channel, [user_id]),
+ user_id: user_id,
+ });
+
+ //If the owner leave the server user is the new owner
+ if (channel.owner_id === user_id) {
+ channel.owner_id = "1"; // The channel is now owned by the server user
+ await emitEvent({
+ event: "CHANNEL_UPDATE",
+ data: await DmChannelDTO.from(channel, [user_id]),
+ channel_id: channel.id,
+ });
+ }
+
+ await channel.save();
+
+ await emitEvent({
+ event: "CHANNEL_RECIPIENT_REMOVE",
+ data: {
+ channel_id: channel.id,
+ user: await User.findOneOrFail({
+ where: { id: user_id },
+ select: PublicUserProjection,
+ }),
+ },
+ channel_id: channel.id,
+ } as ChannelRecipientRemoveEvent);
+ }
+
+ static async deleteChannel(channel: Channel) {
+ await Message.delete({ channel_id: channel.id }); //TODO we should also delete the attachments from the cdn but to do that we need to move cdn.ts in util
+ //TODO before deleting the channel we should check and delete other relations
+ await Channel.delete({ id: channel.id });
+ }
+
+ isDm() {
+ return (
+ this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM
+ );
+ }
+
+ // Does the channel support sending messages ( eg categories do not )
+ isWritable() {
+ const disallowedChannelTypes = [
+ ChannelType.GUILD_CATEGORY,
+ ChannelType.GUILD_STAGE_VOICE,
+ ChannelType.VOICELESS_WHITEBOARD,
+ ];
+ return disallowedChannelTypes.indexOf(this.type) == -1;
+ }
+}
+
+export interface ChannelPermissionOverwrite {
+ allow: string;
+ deny: string;
+ id: string;
+ type: ChannelPermissionOverwriteType;
+}
+
+export enum ChannelPermissionOverwriteType {
+ role = 0,
+ member = 1,
+ group = 2,
+}
diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts
index c5afd307..2723ab67 100644
--- a/src/util/entities/ClientRelease.ts
+++ b/src/util/entities/ClientRelease.ts
@@ -1,4 +1,4 @@
-import { Column, Entity} from "typeorm";
+import { Column, Entity } from "typeorm";
import { BaseClass } from "./BaseClass";
@Entity("client_release")
diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts
index 9aabc1a8..cd7a6923 100644
--- a/src/util/entities/Config.ts
+++ b/src/util/entities/Config.ts
@@ -191,17 +191,17 @@ export interface ConfigValue {
allowTemplateCreation: Boolean;
allowDiscordTemplates: Boolean;
allowRaws: Boolean;
- },
+ };
client: {
useTestClient: Boolean;
releases: {
useLocalRelease: Boolean; //TODO
upstreamVersion: string;
};
- },
+ };
metrics: {
timeout: number;
- },
+ };
sentry: {
enabled: boolean;
endpoint: string;
@@ -230,7 +230,8 @@ export const DefaultConfigOptions: ConfigValue = {
},
general: {
instanceName: "Fosscord Instance",
- instanceDescription: "This is a Fosscord instance made in pre-release days",
+ instanceDescription:
+ "This is a Fosscord instance made in pre-release days",
frontPage: null,
tosPage: null,
correspondenceEmail: "noreply@localhost.local",
@@ -318,8 +319,9 @@ export const DefaultConfigOptions: ConfigValue = {
sitekey: null,
secret: null,
},
- ipdataApiKey: "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9",
- defaultRights: "30644591655936", // See util/scripts/rights.js
+ ipdataApiKey:
+ "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9",
+ defaultRights: "30644591655936", // See util/scripts/rights.js
},
login: {
requireCaptcha: false,
@@ -395,22 +397,23 @@ export const DefaultConfigOptions: ConfigValue = {
enabled: true,
allowTemplateCreation: true,
allowDiscordTemplates: true,
- allowRaws: false
+ allowRaws: false,
},
client: {
useTestClient: true,
releases: {
useLocalRelease: true,
- upstreamVersion: "0.0.264"
- }
+ upstreamVersion: "0.0.264",
+ },
},
metrics: {
- timeout: 30000
+ timeout: 30000,
},
sentry: {
enabled: false,
- endpoint: "https://05e8e3d005f34b7d97e920ae5870a5e5@sentry.thearcanebrony.net/6",
+ endpoint:
+ "https://05e8e3d005f34b7d97e920ae5870a5e5@sentry.thearcanebrony.net/6",
traceSampleRate: 1.0,
- environment: hostname()
- }
-};
\ No newline at end of file
+ environment: hostname(),
+ },
+};
diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts
index 09ae30ab..a893ff34 100644
--- a/src/util/entities/ConnectedAccount.ts
+++ b/src/util/entities/ConnectedAccount.ts
@@ -2,7 +2,8 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
import { BaseClass } from "./BaseClass";
import { User } from "./User";
-export interface PublicConnectedAccount extends Pick<ConnectedAccount, "name" | "type" | "verified"> {}
+export interface PublicConnectedAccount
+ extends Pick<ConnectedAccount, "name" | "type" | "verified"> {}
@Entity("connected_accounts")
export class ConnectedAccount extends BaseClass {
diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts
index a3615b7d..0aa640b5 100644
--- a/src/util/entities/Emoji.ts
+++ b/src/util/entities/Emoji.ts
@@ -40,7 +40,7 @@ export class Emoji extends BaseClass {
@Column({ type: "simple-array" })
roles: string[]; // roles this emoji is whitelisted to (new discord feature?)
-
+
@Column({ type: "simple-array", nullable: true })
groups: string[]; // user groups this emoji is whitelisted to (Fosscord extension)
}
diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts
index b597b90a..4c427b32 100644
--- a/src/util/entities/Encryption.ts
+++ b/src/util/entities/Encryption.ts
@@ -1,9 +1,23 @@
-import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
+import {
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToOne,
+ OneToMany,
+ RelationId,
+} from "typeorm";
import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild";
import { PublicUserProjection, User } from "./User";
import { HTTPError } from "lambert-server";
-import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters } from "../util";
+import {
+ containsAll,
+ emitEvent,
+ getPermission,
+ Snowflake,
+ trimSpecial,
+ InvisibleCharacters,
+} from "../util";
import { BitField, BitFieldResolvable, BitFlag } from "../util/BitField";
import { Recipient } from "./Recipient";
import { Message } from "./Message";
@@ -13,7 +27,6 @@ import { DmChannelDTO } from "../dtos";
@Entity("security_settings")
export class SecuritySettings extends BaseClass {
-
@Column({ nullable: true })
guild_id: string;
@@ -31,5 +44,4 @@ export class SecuritySettings extends BaseClass {
@Column({ nullable: true })
used_since_message: string;
-
}
diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts
index 2ce7c213..8854fec0 100644
--- a/src/util/entities/Guild.ts
+++ b/src/util/entities/Guild.ts
@@ -1,4 +1,13 @@
-import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm";
+import {
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToMany,
+ ManyToOne,
+ OneToMany,
+ OneToOne,
+ RelationId,
+} from "typeorm";
import { Config, handleFile, Snowflake } from "..";
import { Ban } from "./Ban";
import { BaseClass } from "./BaseClass";
@@ -86,7 +95,7 @@ export class Guild extends BaseClass {
//TODO: https://discord.com/developers/docs/resources/guild#guild-object-guild-features
@Column({ nullable: true })
- primary_category_id?: string; // TODO: this was number?
+ primary_category_id?: string; // TODO: this was number?
@Column({ nullable: true })
icon?: string;
@@ -269,7 +278,7 @@ export class Guild extends BaseClass {
@Column()
nsfw: boolean;
-
+
// TODO: nested guilds
@Column({ nullable: true })
parent?: string;
@@ -332,10 +341,13 @@ export class Guild extends BaseClass {
permissions: String("2251804225"),
position: 0,
icon: undefined,
- unicode_emoji: undefined
+ unicode_emoji: undefined,
}).save();
- if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general", nsfw: false }];
+ if (!body.channels || !body.channels.length)
+ body.channels = [
+ { id: "01", type: 0, name: "general", nsfw: false },
+ ];
const ids = new Map();
@@ -345,17 +357,23 @@ export class Guild extends BaseClass {
}
});
- for (const channel of body.channels?.sort((a, b) => (a.parent_id ? 1 : -1))) {
+ for (const channel of body.channels?.sort((a, b) =>
+ a.parent_id ? 1 : -1,
+ )) {
var id = ids.get(channel.id) || Snowflake.generate();
var parent_id = ids.get(channel.parent_id);
- await Channel.createChannel({ ...channel, guild_id, id, parent_id }, body.owner_id, {
- keepId: true,
- skipExistsCheck: true,
- skipPermissionCheck: true,
- skipEventEmit: true,
- });
+ await Channel.createChannel(
+ { ...channel, guild_id, id, parent_id },
+ body.owner_id,
+ {
+ keepId: true,
+ skipExistsCheck: true,
+ skipPermissionCheck: true,
+ skipEventEmit: true,
+ },
+ );
}
return guild;
diff --git a/src/util/entities/Invite.ts b/src/util/entities/Invite.ts
index 4f36f247..90dec92a 100644
--- a/src/util/entities/Invite.ts
+++ b/src/util/entities/Invite.ts
@@ -1,4 +1,11 @@
-import { Column, Entity, JoinColumn, ManyToOne, RelationId, PrimaryColumn } from "typeorm";
+import {
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToOne,
+ RelationId,
+ PrimaryColumn,
+} from "typeorm";
import { Member } from "./Member";
import { BaseClassWithoutId } from "./BaseClass";
import { Channel } from "./Channel";
@@ -76,7 +83,8 @@ export class Invite extends BaseClassWithoutId {
static async joinGuild(user_id: string, code: string) {
const invite = await Invite.findOneOrFail({ where: { code } });
- if (invite.uses++ >= invite.max_uses && invite.max_uses !== 0) await Invite.delete({ code });
+ if (invite.uses++ >= invite.max_uses && invite.max_uses !== 0)
+ await Invite.delete({ code });
else await invite.save();
await Member.addToGuild(user_id, invite.guild_id);
diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts
index 7d1346ba..f2762adc 100644
--- a/src/util/entities/Member.ts
+++ b/src/util/entities/Member.ts
@@ -22,7 +22,6 @@ import {
GuildMemberRemoveEvent,
GuildMemberUpdateEvent,
MessageCreateEvent,
-
} from "../interfaces";
import { HTTPError } from "lambert-server";
import { Role } from "./Role";
@@ -126,19 +125,34 @@ export class Member extends BaseClassWithoutId {
if (this.nick) {
this.nick = this.nick.split("\n").join("");
this.nick = this.nick.split("\t").join("");
- if (BannedWords.find(this.nick)) throw FieldErrors({ nick: { message: "Bad nickname", code: "INVALID_NICKNAME" } });
+ if (BannedWords.find(this.nick))
+ throw FieldErrors({
+ nick: { message: "Bad nickname", code: "INVALID_NICKNAME" },
+ });
}
}
static async IsInGuildOrFail(user_id: string, guild_id: string) {
- if (await Member.count({ where: { id: user_id, guild: { id: guild_id } } })) return true;
+ if (
+ await Member.count({
+ where: { id: user_id, guild: { id: guild_id } },
+ })
+ )
+ return true;
throw new HTTPError("You are not member of this guild", 403);
}
static async removeFromGuild(user_id: string, guild_id: string) {
- const guild = await Guild.findOneOrFail({ select: ["owner_id"], where: { id: guild_id } });
- if (guild.owner_id === user_id) throw new Error("The owner cannot be removed of the guild");
- const member = await Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user"] });
+ const guild = await Guild.findOneOrFail({
+ select: ["owner_id"],
+ where: { id: guild_id },
+ });
+ if (guild.owner_id === user_id)
+ throw new Error("The owner cannot be removed of the guild");
+ const member = await Member.findOneOrFail({
+ where: { id: user_id, guild_id },
+ relations: ["user"],
+ });
// use promise all to execute all promises at the same time -> save time
return Promise.all([
@@ -169,9 +183,12 @@ export class Member extends BaseClassWithoutId {
where: { id: user_id, guild_id },
relations: ["user", "roles"], // we don't want to load the role objects just the ids
//@ts-ignore
- select: ["index", "roles.id"], // TODO fix type
+ select: ["index", "roles.id"], // TODO fix type
+ }),
+ Role.findOneOrFail({
+ where: { id: role_id, guild_id },
+ select: ["id"],
}),
- Role.findOneOrFail({ where: { id: role_id, guild_id }, select: ["id"] }),
]);
member.roles.push(Role.create({ id: role_id }));
@@ -189,7 +206,11 @@ export class Member extends BaseClassWithoutId {
]);
}
- static async removeRole(user_id: string, guild_id: string, role_id: string) {
+ static async removeRole(
+ user_id: string,
+ guild_id: string,
+ role_id: string,
+ ) {
const [member] = await Promise.all([
Member.findOneOrFail({
where: { id: user_id, guild_id },
@@ -215,7 +236,11 @@ export class Member extends BaseClassWithoutId {
]);
}
- static async changeNickname(user_id: string, guild_id: string, nickname: string) {
+ static async changeNickname(
+ user_id: string,
+ guild_id: string,
+ nickname: string,
+ ) {
const member = await Member.findOneOrFail({
where: {
id: user_id,
@@ -249,7 +274,10 @@ export class Member extends BaseClassWithoutId {
const { maxGuilds } = Config.get().limits.user;
const guild_count = await Member.count({ where: { id: user_id } });
if (guild_count >= maxGuilds) {
- throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403);
+ throw new HTTPError(
+ `You are at the ${maxGuilds} server limit.`,
+ 403,
+ );
}
const guild = await Guild.findOneOrFail({
@@ -259,7 +287,11 @@ export class Member extends BaseClassWithoutId {
relations: [...PublicGuildRelations, "system_channel"],
});
- if (await Member.count({ where: { id: user.id, guild: { id: guild_id } } }))
+ if (
+ await Member.count({
+ where: { id: user.id, guild: { id: guild_id } },
+ })
+ )
throw new HTTPError("You are already a member of this guild", 400);
const member = {
@@ -268,7 +300,7 @@ export class Member extends BaseClassWithoutId {
nick: undefined,
roles: [guild_id], // @everyone role
joined_at: new Date(),
- premium_since: (new Date()).getTime(),
+ premium_since: new Date().getTime(),
deaf: false,
mute: false,
pending: false,
@@ -339,7 +371,11 @@ export class Member extends BaseClassWithoutId {
});
await Promise.all([
message.save(),
- emitEvent({ event: "MESSAGE_CREATE", channel_id: message.channel_id, data: message } as MessageCreateEvent)
+ emitEvent({
+ event: "MESSAGE_CREATE",
+ channel_id: message.channel_id,
+ data: message,
+ } as MessageCreateEvent),
]);
}
}
@@ -362,7 +398,7 @@ export interface UserGuildSettings {
channel_overrides: {
[channel_id: string]: ChannelOverride;
- } | null,
+ } | null;
message_notifications: number;
mobile_push: boolean;
mute_config: MuteConfig | null;
@@ -389,7 +425,7 @@ export const DefaultUserGuildSettings: UserGuildSettings = {
notify_highlights: 0,
suppress_everyone: false,
suppress_roles: false,
- version: 453, // ?
+ version: 453, // ?
guild_id: null,
};
diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts
index be790502..a52b4785 100644
--- a/src/util/entities/Message.ts
+++ b/src/util/entities/Message.ts
@@ -51,7 +51,7 @@ export enum MessageType {
SELF_COMMAND_SCRIPT = 43, // self command scripts
ENCRYPTION = 50,
CUSTOM_START = 63,
- UNHANDLED = 255
+ UNHANDLED = 255,
}
@Entity("messages")
@@ -115,7 +115,10 @@ export class Message extends BaseClass {
@ManyToOne(() => Application)
application?: Application;
- @Column({ nullable: true, type: process.env.PRODUCTION ? "longtext" : undefined })
+ @Column({
+ nullable: true,
+ type: process.env.PRODUCTION ? "longtext" : undefined,
+ })
content?: string;
@Column()
@@ -147,10 +150,14 @@ export class Message extends BaseClass {
@ManyToMany(() => Sticker, { cascade: true, onDelete: "CASCADE" })
sticker_items?: Sticker[];
- @OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, {
- cascade: true,
- orphanedRowAction: "delete",
- })
+ @OneToMany(
+ () => Attachment,
+ (attachment: Attachment) => attachment.message,
+ {
+ cascade: true,
+ orphanedRowAction: "delete",
+ },
+ )
attachments?: Attachment[];
@Column({ type: "simple-json" })
@@ -176,7 +183,7 @@ export class Message extends BaseClass {
@Column({ nullable: true })
flags?: string;
-
+
@Column({ type: "simple-json", nullable: true })
message_reference?: {
message_id: string;
@@ -204,7 +211,11 @@ export class Message extends BaseClass {
@BeforeInsert()
validate() {
if (this.content) {
- if (BannedWords.find(this.content)) throw new HTTPError("Message was blocked by automatic moderation", 200000);
+ if (BannedWords.find(this.content))
+ throw new HTTPError(
+ "Message was blocked by automatic moderation",
+ 200000,
+ );
}
}
}
diff --git a/src/util/entities/Migration.ts b/src/util/entities/Migration.ts
index 3f39ae72..f4e54eae 100644
--- a/src/util/entities/Migration.ts
+++ b/src/util/entities/Migration.ts
@@ -1,7 +1,14 @@
-import { Column, Entity, ObjectIdColumn, PrimaryGeneratedColumn } from "typeorm";
+import {
+ Column,
+ Entity,
+ ObjectIdColumn,
+ PrimaryGeneratedColumn,
+} from "typeorm";
import { BaseClassWithoutId } from ".";
-export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith("mongodb")
+export const PrimaryIdAutoGenerated = process.env.DATABASE?.startsWith(
+ "mongodb",
+)
? ObjectIdColumn
: PrimaryGeneratedColumn;
diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts
index 36017c5e..b3ac45ee 100644
--- a/src/util/entities/Note.ts
+++ b/src/util/entities/Note.ts
@@ -15,4 +15,4 @@ export class Note extends BaseClass {
@Column()
content: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts
index b915573b..53ed5589 100644
--- a/src/util/entities/ReadState.ts
+++ b/src/util/entities/ReadState.ts
@@ -1,4 +1,11 @@
-import { Column, Entity, Index, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import {
+ Column,
+ Entity,
+ Index,
+ JoinColumn,
+ ManyToOne,
+ RelationId,
+} from "typeorm";
import { BaseClass } from "./BaseClass";
import { Channel } from "./Channel";
import { Message } from "./Message";
@@ -33,8 +40,8 @@ export class ReadState extends BaseClass {
// fully read marker
@Column({ nullable: true })
- last_message_id: string;
-
+ last_message_id: string;
+
// public read receipt
@Column({ nullable: true })
public_ack: string;
diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts
index c3592c76..25b52757 100644
--- a/src/util/entities/Relationship.ts
+++ b/src/util/entities/Relationship.ts
@@ -1,4 +1,11 @@
-import { Column, Entity, Index, JoinColumn, ManyToOne, RelationId } from "typeorm";
+import {
+ Column,
+ Entity,
+ Index,
+ JoinColumn,
+ ManyToOne,
+ RelationId,
+} from "typeorm";
import { BaseClass } from "./BaseClass";
import { User } from "./User";
diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts
index ec8c69a2..04d74bac 100644
--- a/src/util/entities/StickerPack.ts
+++ b/src/util/entities/StickerPack.ts
@@ -1,4 +1,12 @@
-import { Column, Entity, JoinColumn, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm";
+import {
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToOne,
+ OneToMany,
+ OneToOne,
+ RelationId,
+} from "typeorm";
import { Sticker } from ".";
import { BaseClass } from "./BaseClass";
diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts
index 22140b7f..8f410bb4 100644
--- a/src/util/entities/Team.ts
+++ b/src/util/entities/Team.ts
@@ -1,4 +1,12 @@
-import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, RelationId } from "typeorm";
+import {
+ Column,
+ Entity,
+ JoinColumn,
+ ManyToMany,
+ ManyToOne,
+ OneToMany,
+ RelationId,
+} from "typeorm";
import { BaseClass } from "./BaseClass";
import { TeamMember } from "./TeamMember";
import { User } from "./User";
diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts
index b726e1e8..3f4a0422 100644
--- a/src/util/entities/TeamMember.ts
+++ b/src/util/entities/TeamMember.ts
@@ -20,9 +20,13 @@ export class TeamMember extends BaseClass {
team_id: string;
@JoinColumn({ name: "team_id" })
- @ManyToOne(() => require("./Team").Team, (team: import("./Team").Team) => team.members, {
- onDelete: "CASCADE",
- })
+ @ManyToOne(
+ () => require("./Team").Team,
+ (team: import("./Team").Team) => team.members,
+ {
+ onDelete: "CASCADE",
+ },
+ )
team: import("./Team").Team;
@Column({ nullable: true })
diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts
index 84a8a674..1389a424 100644
--- a/src/util/entities/User.ts
+++ b/src/util/entities/User.ts
@@ -1,9 +1,24 @@
-import { BeforeInsert, BeforeUpdate, Column, Entity, FindOneOptions, JoinColumn, OneToMany } from "typeorm";
+import {
+ BeforeInsert,
+ BeforeUpdate,
+ Column,
+ Entity,
+ FindOneOptions,
+ JoinColumn,
+ OneToMany,
+} from "typeorm";
import { BaseClass } from "./BaseClass";
import { BitField } from "../util/BitField";
import { Relationship } from "./Relationship";
import { ConnectedAccount } from "./ConnectedAccount";
-import { Config, FieldErrors, Snowflake, trimSpecial, BannedWords, adjustEmail } from "..";
+import {
+ Config,
+ FieldErrors,
+ Snowflake,
+ trimSpecial,
+ BannedWords,
+ adjustEmail,
+} from "..";
import { Member, Session } from ".";
export enum PublicUserEnum {
@@ -38,7 +53,7 @@ export enum PrivateUserEnum {
export type PrivateUserKeys = keyof typeof PrivateUserEnum | PublicUserKeys;
export const PublicUserProjection = Object.values(PublicUserEnum).filter(
- (x) => typeof x === "string"
+ (x) => typeof x === "string",
) as PublicUserKeys[];
export const PrivateUserProjection = [
...PublicUserProjection,
@@ -48,7 +63,7 @@ export const PrivateUserProjection = [
// Private user data that should never get sent to the client
export type PublicUser = Pick<User, PublicUserKeys>;
-export interface UserPublic extends Pick<User, PublicUserKeys> { }
+export interface UserPublic extends Pick<User, PublicUserKeys> {}
export interface UserPrivate extends Pick<User, PrivateUserKeys> {
locale: string;
@@ -144,17 +159,25 @@ export class User extends BaseClass {
sessions: Session[];
@JoinColumn({ name: "relationship_ids" })
- @OneToMany(() => Relationship, (relationship: Relationship) => relationship.from, {
- cascade: true,
- orphanedRowAction: "delete",
- })
+ @OneToMany(
+ () => Relationship,
+ (relationship: Relationship) => relationship.from,
+ {
+ cascade: true,
+ orphanedRowAction: "delete",
+ },
+ )
relationships: Relationship[];
@JoinColumn({ name: "connected_account_ids" })
- @OneToMany(() => ConnectedAccount, (account: ConnectedAccount) => account.user, {
- cascade: true,
- orphanedRowAction: "delete",
- })
+ @OneToMany(
+ () => ConnectedAccount,
+ (account: ConnectedAccount) => account.user,
+ {
+ cascade: true,
+ orphanedRowAction: "delete",
+ },
+ )
connected_accounts: ConnectedAccount[];
@Column({ type: "simple-json", select: false })
@@ -177,16 +200,43 @@ export class User extends BaseClass {
@BeforeInsert()
validate() {
this.email = adjustEmail(this.email);
- if (!this.email) throw FieldErrors({ email: { message: "Invalid email", code: "EMAIL_INVALID" } });
- if (!this.email.match(/([a-z\d.-]{3,})@([a-z\d.-]+).([a-z]{2,})/g)) throw FieldErrors({ email: { message: "Invalid email", code: "EMAIL_INVALID" } });
+ if (!this.email)
+ throw FieldErrors({
+ email: { message: "Invalid email", code: "EMAIL_INVALID" },
+ });
+ if (!this.email.match(/([a-z\d.-]{3,})@([a-z\d.-]+).([a-z]{2,})/g))
+ throw FieldErrors({
+ email: { message: "Invalid email", code: "EMAIL_INVALID" },
+ });
const discrim = Number(this.discriminator);
- if (this.discriminator.length > 4) throw FieldErrors({ email: { message: "Discriminator cannot be more than 4 digits.", code: "DISCRIMINATOR_INVALID" } });
- if (isNaN(discrim)) throw FieldErrors({ email: { message: "Discriminator must be a number.", code: "DISCRIMINATOR_INVALID" } });
- if (discrim <= 0 || discrim >= 10000) throw FieldErrors({ email: { message: "Discriminator must be a number.", code: "DISCRIMINATOR_INVALID" } });
+ if (this.discriminator.length > 4)
+ throw FieldErrors({
+ email: {
+ message: "Discriminator cannot be more than 4 digits.",
+ code: "DISCRIMINATOR_INVALID",
+ },
+ });
+ if (isNaN(discrim))
+ throw FieldErrors({
+ email: {
+ message: "Discriminator must be a number.",
+ code: "DISCRIMINATOR_INVALID",
+ },
+ });
+ if (discrim <= 0 || discrim >= 10000)
+ throw FieldErrors({
+ email: {
+ message: "Discriminator must be a number.",
+ code: "DISCRIMINATOR_INVALID",
+ },
+ });
this.discriminator = discrim.toString().padStart(4, "0");
- if (BannedWords.find(this.username)) throw FieldErrors({ username: { message: "Bad username", code: "INVALID_USERNAME" } });
+ if (BannedWords.find(this.username))
+ throw FieldErrors({
+ username: { message: "Bad username", code: "INVALID_USERNAME" },
+ });
}
toPublicUser() {
@@ -202,17 +252,25 @@ export class User extends BaseClass {
where: { id: user_id },
...opts,
//@ts-ignore
- select: [...PublicUserProjection, ...(opts?.select || [])], // TODO: fix
+ select: [...PublicUserProjection, ...(opts?.select || [])], // TODO: fix
});
}
- private static async generateDiscriminator(username: string): Promise<string | undefined> {
+ private static async generateDiscriminator(
+ username: string,
+ ): Promise<string | undefined> {
if (Config.get().register.incrementingDiscriminators) {
// discriminator will be incrementally generated
// First we need to figure out the currently highest discrimnator for the given username and then increment it
- const users = await User.find({ where: { username }, select: ["discriminator"] });
- const highestDiscriminator = Math.max(0, ...users.map((u) => Number(u.discriminator)));
+ const users = await User.find({
+ where: { username },
+ select: ["discriminator"],
+ });
+ const highestDiscriminator = Math.max(
+ 0,
+ ...users.map((u) => Number(u.discriminator)),
+ );
const discriminator = highestDiscriminator + 1;
if (discriminator >= 10000) {
@@ -226,8 +284,13 @@ export class User extends BaseClass {
// randomly generates a discriminator between 1 and 9999 and checks max five times if it already exists
// TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the database?
for (let tries = 0; tries < 5; tries++) {
- const discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0");
- const exists = await User.findOne({ where: { discriminator, username: username }, select: ["id"] });
+ const discriminator = Math.randomIntBetween(1, 9999)
+ .toString()
+ .padStart(4, "0");
+ const exists = await User.findOne({
+ where: { discriminator, username: username },
+ select: ["id"],
+ });
if (!exists) return discriminator;
}
@@ -265,7 +328,8 @@ export class User extends BaseClass {
// TODO: save date_of_birth
// appearently discord doesn't save the date of birth and just calculate if nsfw is allowed
// if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false
- const language = req.language === "en" ? "en-US" : req.language || "en-US";
+ const language =
+ req.language === "en" ? "en-US" : req.language || "en-US";
const user = User.create({
created_at: new Date(),
@@ -295,8 +359,8 @@ export class User extends BaseClass {
},
settings: { ...defaultSettings, locale: language },
purchased_flags: 5, // TODO: idk what the values for this are
- premium_usage_flags: 2, // TODO: idk what the values for this are
- extended_settings: "", // TODO: was {}
+ premium_usage_flags: 2, // TODO: idk what the values for this are
+ extended_settings: "", // TODO: was {}
fingerprints: [],
});
@@ -305,7 +369,7 @@ export class User extends BaseClass {
setImmediate(async () => {
if (Config.get().guild.autoJoin.enabled) {
for (const guild of Config.get().guild.autoJoin.guilds || []) {
- await Member.addToGuild(user.id, guild).catch((e) => { });
+ await Member.addToGuild(user.id, guild).catch((e) => {});
}
}
});
@@ -372,7 +436,7 @@ export interface UserSettings {
disable_games_tab: boolean;
enable_tts_command: boolean;
explicit_content_filter: number;
- friend_source_flags: { all: boolean; };
+ friend_source_flags: { all: boolean };
gateway_connected: boolean;
gif_auto_play: boolean;
// every top guild is displayed as a "folder"
diff --git a/src/util/entities/index.ts b/src/util/entities/index.ts
index 49793810..c439a4b7 100644
--- a/src/util/entities/index.ts
+++ b/src/util/entities/index.ts
@@ -29,4 +29,4 @@ export * from "./VoiceState";
export * from "./Webhook";
export * from "./ClientRelease";
export * from "./BackupCodes";
-export * from "./Note";
\ No newline at end of file
+export * from "./Note";
diff --git a/src/util/imports/OrmUtils.ts b/src/util/imports/OrmUtils.ts
index 68a1932c..26652db0 100644
--- a/src/util/imports/OrmUtils.ts
+++ b/src/util/imports/OrmUtils.ts
@@ -9,7 +9,12 @@ export class OrmUtils {
return !item.constructor || item.constructor === Object;
}
- private static mergeArrayKey(target: any, key: number, value: any, memo: Map<any, any>) {
+ private static mergeArrayKey(
+ target: any,
+ key: number,
+ value: any,
+ memo: Map<any, any>,
+ ) {
// Have we seen this before? Prevent infinite recursion.
if (memo.has(value)) {
target[key] = memo.get(value);
@@ -38,7 +43,12 @@ export class OrmUtils {
memo.delete(value);
}
- private static mergeObjectKey(target: any, key: string, value: any, memo: Map<any, any>) {
+ private static mergeObjectKey(
+ target: any,
+ key: string,
+ value: any,
+ memo: Map<any, any>,
+ ) {
// Have we seen this before? Prevent infinite recursion.
if (memo.has(value)) {
Object.assign(target, { [key]: memo.get(value) });
@@ -67,7 +77,11 @@ export class OrmUtils {
memo.delete(value);
}
- private static merge(target: any, source: any, memo: Map<any, any> = new Map()): any {
+ private static merge(
+ target: any,
+ source: any,
+ memo: Map<any, any> = new Map(),
+ ): any {
if (Array.isArray(target) && Array.isArray(source)) {
for (let key = 0; key < source.length; key++) {
this.mergeArrayKey(target, key, source[key], memo);
@@ -93,4 +107,4 @@ export class OrmUtils {
return target;
}
-}
\ No newline at end of file
+}
diff --git a/src/util/imports/index.ts b/src/util/imports/index.ts
index 5d9bfb5f..823151d9 100644
--- a/src/util/imports/index.ts
+++ b/src/util/imports/index.ts
@@ -1 +1 @@
-export * from "./OrmUtils";
\ No newline at end of file
+export * from "./OrmUtils";
diff --git a/src/util/index.ts b/src/util/index.ts
index 385070a3..3773c275 100644
--- a/src/util/index.ts
+++ b/src/util/index.ts
@@ -5,4 +5,4 @@ export * from "./interfaces/index";
export * from "./entities/index";
export * from "./dtos/index";
export * from "./schemas";
-export * from "./imports";
\ No newline at end of file
+export * from "./imports";
diff --git a/src/util/interfaces/Activity.ts b/src/util/interfaces/Activity.ts
index 9912e197..279ee40f 100644
--- a/src/util/interfaces/Activity.ts
+++ b/src/util/interfaces/Activity.ts
@@ -36,7 +36,8 @@ export interface Activity {
id?: string;
sync_id?: string;
- metadata?: { // spotify
+ metadata?: {
+ // spotify
context_uri?: string;
album_id: string;
artist_ids: string[];
diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts
index 59f995db..472fd572 100644
--- a/src/util/interfaces/Event.ts
+++ b/src/util/interfaces/Event.ts
@@ -75,7 +75,7 @@ export interface ReadyEventData {
number,
[[number, { e: number; s: number }[]]],
[number, [[number, [number, number]]]],
- { b: number; k: bigint[] }[]
+ { b: number; k: bigint[] }[],
][];
guild_join_requests?: any[]; // ? what is this? this is new
shard?: [number, number];
diff --git a/src/util/migrations/1633864260873-EmojiRoles.ts b/src/util/migrations/1633864260873-EmojiRoles.ts
index f0d709f2..31ced96b 100644
--- a/src/util/migrations/1633864260873-EmojiRoles.ts
+++ b/src/util/migrations/1633864260873-EmojiRoles.ts
@@ -4,10 +4,14 @@ export class EmojiRoles1633864260873 implements MigrationInterface {
name = "EmojiRoles1633864260873";
public async up(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`ALTER TABLE "emojis" ADD "roles" text NOT NULL DEFAULT ''`);
+ await queryRunner.query(
+ `ALTER TABLE "emojis" ADD "roles" text NOT NULL DEFAULT ''`,
+ );
}
public async down(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN column_name "roles"`);
+ await queryRunner.query(
+ `ALTER TABLE "emojis" DROP COLUMN column_name "roles"`,
+ );
}
}
diff --git a/src/util/migrations/1633864669243-EmojiUser.ts b/src/util/migrations/1633864669243-EmojiUser.ts
index 982405d7..9610216b 100644
--- a/src/util/migrations/1633864669243-EmojiUser.ts
+++ b/src/util/migrations/1633864669243-EmojiUser.ts
@@ -7,17 +7,21 @@ export class EmojiUser1633864669243 implements MigrationInterface {
await queryRunner.query(`ALTER TABLE "emojis" ADD "user_id" varchar`);
try {
await queryRunner.query(
- `ALTER TABLE "emojis" ADD CONSTRAINT FK_fa7ddd5f9a214e28ce596548421 FOREIGN KEY (user_id) REFERENCES users(id)`
+ `ALTER TABLE "emojis" ADD CONSTRAINT FK_fa7ddd5f9a214e28ce596548421 FOREIGN KEY (user_id) REFERENCES users(id)`,
);
} catch (error) {
console.error(
- "sqlite doesn't support altering foreign keys: https://stackoverflow.com/questions/1884818/how-do-i-add-a-foreign-key-to-an-existing-sqlite-table"
+ "sqlite doesn't support altering foreign keys: https://stackoverflow.com/questions/1884818/how-do-i-add-a-foreign-key-to-an-existing-sqlite-table",
);
}
}
public async down(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN column_name "user_id"`);
- await queryRunner.query(`ALTER TABLE "emojis" DROP CONSTRAINT FK_fa7ddd5f9a214e28ce596548421`);
+ await queryRunner.query(
+ `ALTER TABLE "emojis" DROP COLUMN column_name "user_id"`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "emojis" DROP CONSTRAINT FK_fa7ddd5f9a214e28ce596548421`,
+ );
}
}
diff --git a/src/util/migrations/1633881705509-VanityInvite.ts b/src/util/migrations/1633881705509-VanityInvite.ts
index 45485310..16072473 100644
--- a/src/util/migrations/1633881705509-VanityInvite.ts
+++ b/src/util/migrations/1633881705509-VanityInvite.ts
@@ -5,15 +5,21 @@ export class VanityInvite1633881705509 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
try {
- await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN vanity_url_code`);
- await queryRunner.query(`ALTER TABLE "emojis" DROP CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad`);
+ await queryRunner.query(
+ `ALTER TABLE "emojis" DROP COLUMN vanity_url_code`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "emojis" DROP CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad`,
+ );
} catch (error) {}
}
public async down(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`ALTER TABLE "emojis" ADD vanity_url_code varchar`);
await queryRunner.query(
- `ALTER TABLE "emojis" ADD CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad FOREIGN KEY ("vanity_url_code") REFERENCES "invites"("code") ON DELETE NO ACTION ON UPDATE NO ACTION`
+ `ALTER TABLE "emojis" ADD vanity_url_code varchar`,
+ );
+ await queryRunner.query(
+ `ALTER TABLE "emojis" ADD CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad FOREIGN KEY ("vanity_url_code") REFERENCES "invites"("code") ON DELETE NO ACTION ON UPDATE NO ACTION`,
);
}
}
diff --git a/src/util/migrations/1634308884591-Stickers.ts b/src/util/migrations/1634308884591-Stickers.ts
index fbc4649f..f7b83242 100644
--- a/src/util/migrations/1634308884591-Stickers.ts
+++ b/src/util/migrations/1634308884591-Stickers.ts
@@ -1,35 +1,64 @@
-import { MigrationInterface, QueryRunner, Table, TableColumn, TableForeignKey } from "typeorm";
+import {
+ MigrationInterface,
+ QueryRunner,
+ Table,
+ TableColumn,
+ TableForeignKey,
+} from "typeorm";
export class Stickers1634308884591 implements MigrationInterface {
name = "Stickers1634308884591";
public async up(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.dropForeignKey("read_states", "FK_6f255d873cfbfd7a93849b7ff74");
+ await queryRunner.dropForeignKey(
+ "read_states",
+ "FK_6f255d873cfbfd7a93849b7ff74",
+ );
await queryRunner.changeColumn(
"stickers",
"tags",
- new TableColumn({ name: "tags", type: "varchar", isNullable: true })
+ new TableColumn({
+ name: "tags",
+ type: "varchar",
+ isNullable: true,
+ }),
);
await queryRunner.changeColumn(
"stickers",
"pack_id",
- new TableColumn({ name: "pack_id", type: "varchar", isNullable: true })
+ new TableColumn({
+ name: "pack_id",
+ type: "varchar",
+ isNullable: true,
+ }),
+ );
+ await queryRunner.changeColumn(
+ "stickers",
+ "type",
+ new TableColumn({ name: "type", type: "integer" }),
);
- await queryRunner.changeColumn("stickers", "type", new TableColumn({ name: "type", type: "integer" }));
await queryRunner.changeColumn(
"stickers",
"format_type",
- new TableColumn({ name: "format_type", type: "integer" })
+ new TableColumn({ name: "format_type", type: "integer" }),
);
await queryRunner.changeColumn(
"stickers",
"available",
- new TableColumn({ name: "available", type: "boolean", isNullable: true })
+ new TableColumn({
+ name: "available",
+ type: "boolean",
+ isNullable: true,
+ }),
);
await queryRunner.changeColumn(
"stickers",
"user_id",
- new TableColumn({ name: "user_id", type: "boolean", isNullable: true })
+ new TableColumn({
+ name: "user_id",
+ type: "boolean",
+ isNullable: true,
+ }),
);
await queryRunner.createForeignKey(
"stickers",
@@ -39,17 +68,33 @@ export class Stickers1634308884591 implements MigrationInterface {
referencedColumnNames: ["id"],
referencedTableName: "users",
onDelete: "CASCADE",
- })
+ }),
);
await queryRunner.createTable(
new Table({
name: "sticker_packs",
columns: [
- new TableColumn({ name: "id", type: "varchar", isPrimary: true }),
+ new TableColumn({
+ name: "id",
+ type: "varchar",
+ isPrimary: true,
+ }),
new TableColumn({ name: "name", type: "varchar" }),
- new TableColumn({ name: "description", type: "varchar", isNullable: true }),
- new TableColumn({ name: "banner_asset_id", type: "varchar", isNullable: true }),
- new TableColumn({ name: "cover_sticker_id", type: "varchar", isNullable: true }),
+ new TableColumn({
+ name: "description",
+ type: "varchar",
+ isNullable: true,
+ }),
+ new TableColumn({
+ name: "banner_asset_id",
+ type: "varchar",
+ isNullable: true,
+ }),
+ new TableColumn({
+ name: "cover_sticker_id",
+ type: "varchar",
+ isNullable: true,
+ }),
],
foreignKeys: [
new TableForeignKey({
@@ -58,7 +103,7 @@ export class Stickers1634308884591 implements MigrationInterface {
referencedTableName: "stickers",
}),
],
- })
+ }),
);
}
diff --git a/src/util/migrations/1634424361103-Presence.ts b/src/util/migrations/1634424361103-Presence.ts
index 729955b8..a71cb253 100644
--- a/src/util/migrations/1634424361103-Presence.ts
+++ b/src/util/migrations/1634424361103-Presence.ts
@@ -4,7 +4,10 @@ export class Presence1634424361103 implements MigrationInterface {
name = "Presence1634424361103";
public async up(queryRunner: QueryRunner): Promise<void> {
- queryRunner.addColumn("sessions", new TableColumn({ name: "activites", type: "text" }));
+ queryRunner.addColumn(
+ "sessions",
+ new TableColumn({ name: "activites", type: "text" }),
+ );
}
public async down(queryRunner: QueryRunner): Promise<void> {}
diff --git a/src/util/migrations/1634426540271-MigrationTimestamp.ts b/src/util/migrations/1634426540271-MigrationTimestamp.ts
index 3208b25b..fb596906 100644
--- a/src/util/migrations/1634426540271-MigrationTimestamp.ts
+++ b/src/util/migrations/1634426540271-MigrationTimestamp.ts
@@ -7,7 +7,11 @@ export class MigrationTimestamp1634426540271 implements MigrationInterface {
await queryRunner.changeColumn(
"migrations",
"timestamp",
- new TableColumn({ name: "timestampe", type: "bigint", isNullable: false })
+ new TableColumn({
+ name: "timestampe",
+ type: "bigint",
+ isNullable: false,
+ }),
);
}
diff --git a/src/util/migrations/1660678870706-opencordFixes.ts b/src/util/migrations/1660678870706-opencordFixes.ts
index 1f10c212..53c561ce 100644
--- a/src/util/migrations/1660678870706-opencordFixes.ts
+++ b/src/util/migrations/1660678870706-opencordFixes.ts
@@ -1,53 +1,52 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class opencordFixes1660678870706 implements MigrationInterface {
- name = 'opencordFixes1660678870706'
+ name = "opencordFixes1660678870706";
- public async up(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`
+ public async up(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`
ALTER TABLE \`users\`
ADD \`purchased_flags\` int NOT NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`users\`
ADD \`premium_usage_flags\` int NOT NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`friend_discovery_flags\` int NOT NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`view_nsfw_guilds\` tinyint NOT NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`passwordless\` tinyint NOT NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NOT NULL
`);
- }
+ }
- public async down(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`
+ public async down(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`
ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`passwordless\`
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`view_nsfw_guilds\`
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`friend_discovery_flags\`
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`users\` DROP COLUMN \`premium_usage_flags\`
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`users\` DROP COLUMN \`purchased_flags\`
`);
- }
-
-}
\ No newline at end of file
+ }
+}
diff --git a/src/util/migrations/1660689892073-mobileFixes2.ts b/src/util/migrations/1660689892073-mobileFixes2.ts
index bd28694e..63e7e032 100644
--- a/src/util/migrations/1660689892073-mobileFixes2.ts
+++ b/src/util/migrations/1660689892073-mobileFixes2.ts
@@ -1,37 +1,36 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class mobileFixes21660689892073 implements MigrationInterface {
- name = 'mobileFixes21660689892073'
+ name = "mobileFixes21660689892073";
- public async up(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`
+ public async up(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`
ALTER TABLE \`user_settings\`
ADD \`banner_color\` varchar(255) NULL
`);
await queryRunner.query(`
UPDATE \`channels\` SET \`nsfw\` = 0 WHERE \`nsfw\` = NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
`);
await queryRunner.query(`
UPDATE \`guilds\` SET \`nsfw\` = 0 WHERE \`nsfw\` = NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
`);
- }
+ }
- public async down(queryRunner: QueryRunner): Promise<void> {
- await queryRunner.query(`
+ public async down(queryRunner: QueryRunner): Promise<void> {
+ await queryRunner.query(`
ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
`);
- await queryRunner.query(`
+ await queryRunner.query(`
ALTER TABLE \`user_settings\` DROP COLUMN \`banner_color\`
`);
- }
-
-}
\ No newline at end of file
+ }
+}
diff --git a/src/util/schemas/ActivitySchema.ts b/src/util/schemas/ActivitySchema.ts
index d316420e..5a3d205b 100644
--- a/src/util/schemas/ActivitySchema.ts
+++ b/src/util/schemas/ActivitySchema.ts
@@ -41,7 +41,8 @@ export const ActivitySchema = {
$id: String,
$sync_id: String,
- $metadata: { // spotify
+ $metadata: {
+ // spotify
$context_uri: String,
album_id: String,
artist_ids: [String],
@@ -57,4 +58,4 @@ export interface ActivitySchema {
status: Status;
activities?: Activity[];
since?: number; // unix time (in milliseconds) of when the client went idle, or null if the client is not idle
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/BackupCodesChallengeSchema.ts b/src/util/schemas/BackupCodesChallengeSchema.ts
index d6b519b7..8e2f0649 100644
--- a/src/util/schemas/BackupCodesChallengeSchema.ts
+++ b/src/util/schemas/BackupCodesChallengeSchema.ts
@@ -1,3 +1,3 @@
export interface BackupCodesChallengeSchema {
password: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/BanCreateSchema.ts b/src/util/schemas/BanCreateSchema.ts
index 876b2a89..834577dc 100644
--- a/src/util/schemas/BanCreateSchema.ts
+++ b/src/util/schemas/BanCreateSchema.ts
@@ -1,4 +1,4 @@
export interface BanCreateSchema {
delete_message_days?: string;
reason?: string;
-};
\ No newline at end of file
+}
diff --git a/src/util/schemas/BanModeratorSchema.ts b/src/util/schemas/BanModeratorSchema.ts
index 8efa2402..afb76433 100644
--- a/src/util/schemas/BanModeratorSchema.ts
+++ b/src/util/schemas/BanModeratorSchema.ts
@@ -4,4 +4,4 @@ export interface BanModeratorSchema {
guild_id: string;
executor_id: string;
reason?: string | undefined;
-};
\ No newline at end of file
+}
diff --git a/src/util/schemas/BanRegistrySchema.ts b/src/util/schemas/BanRegistrySchema.ts
index 8680d3db..501f94dc 100644
--- a/src/util/schemas/BanRegistrySchema.ts
+++ b/src/util/schemas/BanRegistrySchema.ts
@@ -5,4 +5,4 @@ export interface BanRegistrySchema {
executor_id: string;
ip?: string;
reason?: string | undefined;
-};
\ No newline at end of file
+}
diff --git a/src/util/schemas/BulkDeleteSchema.ts b/src/util/schemas/BulkDeleteSchema.ts
index 6a71e052..bfc4df65 100644
--- a/src/util/schemas/BulkDeleteSchema.ts
+++ b/src/util/schemas/BulkDeleteSchema.ts
@@ -1,3 +1,3 @@
export interface BulkDeleteSchema {
messages: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/ChannelModifySchema.ts b/src/util/schemas/ChannelModifySchema.ts
index 835ea2d7..9a07f983 100644
--- a/src/util/schemas/ChannelModifySchema.ts
+++ b/src/util/schemas/ChannelModifySchema.ts
@@ -27,4 +27,4 @@ export interface ChannelModifySchema {
flags?: number;
default_thread_rate_limit_per_user?: number;
video_quality_mode?: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/CodesVerificationSchema.ts b/src/util/schemas/CodesVerificationSchema.ts
index e8e2e7b4..73c371eb 100644
--- a/src/util/schemas/CodesVerificationSchema.ts
+++ b/src/util/schemas/CodesVerificationSchema.ts
@@ -2,4 +2,4 @@ export interface CodesVerificationSchema {
key: string;
nonce: string;
regenerate?: boolean;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/DmChannelCreateSchema.ts b/src/util/schemas/DmChannelCreateSchema.ts
index 04b8ff69..1b0fe86d 100644
--- a/src/util/schemas/DmChannelCreateSchema.ts
+++ b/src/util/schemas/DmChannelCreateSchema.ts
@@ -1,4 +1,4 @@
export interface DmChannelCreateSchema {
name?: string;
recipients: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/EmojiCreateSchema.ts b/src/util/schemas/EmojiCreateSchema.ts
index 8e2a2307..34084713 100644
--- a/src/util/schemas/EmojiCreateSchema.ts
+++ b/src/util/schemas/EmojiCreateSchema.ts
@@ -3,4 +3,4 @@ export interface EmojiCreateSchema {
image: string;
require_colons?: boolean | null;
roles?: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/EmojiModifySchema.ts b/src/util/schemas/EmojiModifySchema.ts
index cd5b7e3e..05d2d395 100644
--- a/src/util/schemas/EmojiModifySchema.ts
+++ b/src/util/schemas/EmojiModifySchema.ts
@@ -1,4 +1,4 @@
export interface EmojiModifySchema {
name?: string;
roles?: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/GuildCreateSchema.ts b/src/util/schemas/GuildCreateSchema.ts
index 9b5f7dc2..f3de7007 100644
--- a/src/util/schemas/GuildCreateSchema.ts
+++ b/src/util/schemas/GuildCreateSchema.ts
@@ -11,4 +11,4 @@ export interface GuildCreateSchema {
guild_template_code?: string;
system_channel_id?: string;
rules_channel_id?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/GuildTemplateCreateSchema.ts b/src/util/schemas/GuildTemplateCreateSchema.ts
index 7caefcb8..59db8428 100644
--- a/src/util/schemas/GuildTemplateCreateSchema.ts
+++ b/src/util/schemas/GuildTemplateCreateSchema.ts
@@ -1,4 +1,4 @@
export interface GuildTemplateCreateSchema {
name: string;
avatar?: string | null;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts b/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
index 0022da6e..e271b83e 100644
--- a/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
+++ b/src/util/schemas/GuildUpdateWelcomeScreenSchema.ts
@@ -7,4 +7,4 @@ export interface GuildUpdateWelcomeScreenSchema {
}[];
enabled?: boolean;
description?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/InviteCreateSchema.ts b/src/util/schemas/InviteCreateSchema.ts
index 83ae22dd..cac11147 100644
--- a/src/util/schemas/InviteCreateSchema.ts
+++ b/src/util/schemas/InviteCreateSchema.ts
@@ -8,4 +8,4 @@ export interface InviteCreateSchema {
unique?: boolean;
target_user?: string;
target_user_type?: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/LoginSchema.ts b/src/util/schemas/LoginSchema.ts
index 543d236c..dc889d94 100644
--- a/src/util/schemas/LoginSchema.ts
+++ b/src/util/schemas/LoginSchema.ts
@@ -5,4 +5,4 @@ export interface LoginSchema {
captcha_key?: string;
login_source?: string;
gift_code_sku_id?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MemberChangeSchema.ts b/src/util/schemas/MemberChangeSchema.ts
index 566d7e20..2367bef3 100644
--- a/src/util/schemas/MemberChangeSchema.ts
+++ b/src/util/schemas/MemberChangeSchema.ts
@@ -1,4 +1,4 @@
export interface MemberChangeSchema {
roles?: string[];
nick?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MemberNickChangeSchema.ts b/src/util/schemas/MemberNickChangeSchema.ts
index ed9fdb7b..d863038c 100644
--- a/src/util/schemas/MemberNickChangeSchema.ts
+++ b/src/util/schemas/MemberNickChangeSchema.ts
@@ -1,3 +1,3 @@
export interface MemberNickChangeSchema {
nick: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MessageAcknowledgeSchema.ts b/src/util/schemas/MessageAcknowledgeSchema.ts
index 1e7fb80d..194bb4b4 100644
--- a/src/util/schemas/MessageAcknowledgeSchema.ts
+++ b/src/util/schemas/MessageAcknowledgeSchema.ts
@@ -1,4 +1,4 @@
export interface MessageAcknowledgeSchema {
manual?: boolean;
mention_count?: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MessageCreateSchema.ts b/src/util/schemas/MessageCreateSchema.ts
index 9d77c485..bf3470bb 100644
--- a/src/util/schemas/MessageCreateSchema.ts
+++ b/src/util/schemas/MessageCreateSchema.ts
@@ -30,4 +30,4 @@ export interface MessageCreateSchema {
**/
attachments?: any[];
sticker_ids?: string[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/MfaCodesSchema.ts b/src/util/schemas/MfaCodesSchema.ts
index 226c43f1..ac05b9a4 100644
--- a/src/util/schemas/MfaCodesSchema.ts
+++ b/src/util/schemas/MfaCodesSchema.ts
@@ -1,4 +1,4 @@
export interface MfaCodesSchema {
password: string;
regenerate?: boolean;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/ModifyGuildStickerSchema.ts b/src/util/schemas/ModifyGuildStickerSchema.ts
index 06bf4ffe..159cc44f 100644
--- a/src/util/schemas/ModifyGuildStickerSchema.ts
+++ b/src/util/schemas/ModifyGuildStickerSchema.ts
@@ -12,4 +12,4 @@ export interface ModifyGuildStickerSchema {
* @maxLength 200
*/
tags: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/PruneSchema.ts b/src/util/schemas/PruneSchema.ts
index 60601d81..bea5e2b4 100644
--- a/src/util/schemas/PruneSchema.ts
+++ b/src/util/schemas/PruneSchema.ts
@@ -3,4 +3,4 @@ export interface PruneSchema {
* @min 0
*/
days: number;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/PurgeSchema.ts b/src/util/schemas/PurgeSchema.ts
index 8916be92..f5ab0a20 100644
--- a/src/util/schemas/PurgeSchema.ts
+++ b/src/util/schemas/PurgeSchema.ts
@@ -1,4 +1,4 @@
export interface PurgeSchema {
before: string;
after: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RegisterSchema.ts b/src/util/schemas/RegisterSchema.ts
index c0cc3805..865f55b3 100644
--- a/src/util/schemas/RegisterSchema.ts
+++ b/src/util/schemas/RegisterSchema.ts
@@ -24,4 +24,4 @@ export interface RegisterSchema {
captcha_key?: string;
promotional_email_opt_in?: boolean;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RelationshipPostSchema.ts b/src/util/schemas/RelationshipPostSchema.ts
index 3ff6eade..774c67f6 100644
--- a/src/util/schemas/RelationshipPostSchema.ts
+++ b/src/util/schemas/RelationshipPostSchema.ts
@@ -1,4 +1,4 @@
export interface RelationshipPostSchema {
discriminator: string;
username: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RelationshipPutSchema.ts b/src/util/schemas/RelationshipPutSchema.ts
index 455f854e..0a7f9720 100644
--- a/src/util/schemas/RelationshipPutSchema.ts
+++ b/src/util/schemas/RelationshipPutSchema.ts
@@ -2,4 +2,4 @@ import { RelationshipType } from "@fosscord/util";
export interface RelationshipPutSchema {
type?: RelationshipType;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/RoleModifySchema.ts b/src/util/schemas/RoleModifySchema.ts
index adb0c1a6..f3f4a20e 100644
--- a/src/util/schemas/RoleModifySchema.ts
+++ b/src/util/schemas/RoleModifySchema.ts
@@ -7,4 +7,4 @@ export interface RoleModifySchema {
position?: number;
icon?: string;
unicode_emoji?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/SelectProtocolSchema.ts b/src/util/schemas/SelectProtocolSchema.ts
index 92958e97..0ba0c23b 100644
--- a/src/util/schemas/SelectProtocolSchema.ts
+++ b/src/util/schemas/SelectProtocolSchema.ts
@@ -1,12 +1,12 @@
export interface SelectProtocolSchema {
protocol: "webrtc" | "udp";
data:
- | string
- | {
- address: string;
- port: number;
- mode: string;
- };
+ | string
+ | {
+ address: string;
+ port: number;
+ mode: string;
+ };
sdp?: string;
codecs?: {
name: "opus" | "VP8" | "VP9" | "H264";
@@ -16,4 +16,4 @@ export interface SelectProtocolSchema {
rtx_payload_type?: number | null;
}[];
rtc_connection_id?: string; // uuid
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TemplateCreateSchema.ts b/src/util/schemas/TemplateCreateSchema.ts
index 3f98f692..160934f5 100644
--- a/src/util/schemas/TemplateCreateSchema.ts
+++ b/src/util/schemas/TemplateCreateSchema.ts
@@ -1,4 +1,4 @@
export interface TemplateCreateSchema {
name: string;
description?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TemplateModifySchema.ts b/src/util/schemas/TemplateModifySchema.ts
index 3e6efb74..f9c9d14b 100644
--- a/src/util/schemas/TemplateModifySchema.ts
+++ b/src/util/schemas/TemplateModifySchema.ts
@@ -1,4 +1,4 @@
export interface TemplateModifySchema {
name: string;
description?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TotpDisableSchema.ts b/src/util/schemas/TotpDisableSchema.ts
index 05192bfa..51446e1c 100644
--- a/src/util/schemas/TotpDisableSchema.ts
+++ b/src/util/schemas/TotpDisableSchema.ts
@@ -1,3 +1,3 @@
export interface TotpDisableSchema {
code: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TotpEnableSchema.ts b/src/util/schemas/TotpEnableSchema.ts
index 7f6fb5a9..4e3551d9 100644
--- a/src/util/schemas/TotpEnableSchema.ts
+++ b/src/util/schemas/TotpEnableSchema.ts
@@ -2,4 +2,4 @@ export interface TotpEnableSchema {
password: string;
code?: string;
secret?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/TotpSchema.ts b/src/util/schemas/TotpSchema.ts
index 889cb443..941a92ec 100644
--- a/src/util/schemas/TotpSchema.ts
+++ b/src/util/schemas/TotpSchema.ts
@@ -1,6 +1,6 @@
export interface TotpSchema {
- code: string,
- ticket: string,
- gift_code_sku_id?: string | null,
- login_source?: string | null,
-}
\ No newline at end of file
+ code: string;
+ ticket: string;
+ gift_code_sku_id?: string | null;
+ login_source?: string | null;
+}
diff --git a/src/util/schemas/UserModifySchema.ts b/src/util/schemas/UserModifySchema.ts
index 34e0f135..5327e34b 100644
--- a/src/util/schemas/UserModifySchema.ts
+++ b/src/util/schemas/UserModifySchema.ts
@@ -16,4 +16,4 @@ export interface UserModifySchema {
code?: string;
email?: string;
discriminator?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/Validator.ts b/src/util/schemas/Validator.ts
index b71bf6a1..e85cdf7b 100644
--- a/src/util/schemas/Validator.ts
+++ b/src/util/schemas/Validator.ts
@@ -3,7 +3,14 @@ import addFormats from "ajv-formats";
import fs from "fs";
import path from "path";
-const SchemaPath = path.join(__dirname, "..", "..", "..", "assets", "schemas.json");
+const SchemaPath = path.join(
+ __dirname,
+ "..",
+ "..",
+ "..",
+ "assets",
+ "schemas.json",
+);
const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
export const ajv = new Ajv({
@@ -14,7 +21,7 @@ export const ajv = new Ajv({
coerceTypes: true,
messages: true,
strict: true,
- strictRequired: true
+ strictRequired: true,
});
addFormats(ajv);
@@ -41,7 +48,14 @@ export const normalizeBody = (body: any = {}) => {
} else {
for (const [key, value] of Object.entries(object)) {
if (value == null) {
- if (key === "icon" || key === "avatar" || key === "banner" || key === "splash" || key === "discovery_splash") continue;
+ if (
+ key === "icon" ||
+ key === "avatar" ||
+ key === "banner" ||
+ key === "splash" ||
+ key === "discovery_splash"
+ )
+ continue;
delete object[key];
} else if (typeof value === "object") {
normalizeObject(value);
@@ -51,4 +65,4 @@ export const normalizeBody = (body: any = {}) => {
};
normalizeObject(body);
return body;
-};
\ No newline at end of file
+};
diff --git a/src/util/schemas/VanityUrlSchema.ts b/src/util/schemas/VanityUrlSchema.ts
index 28bf7f2b..4dd9b9da 100644
--- a/src/util/schemas/VanityUrlSchema.ts
+++ b/src/util/schemas/VanityUrlSchema.ts
@@ -4,4 +4,4 @@ export interface VanityUrlSchema {
* @maxLength 20
*/
code?: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/VoiceIdentifySchema.ts b/src/util/schemas/VoiceIdentifySchema.ts
index d48de347..df023713 100644
--- a/src/util/schemas/VoiceIdentifySchema.ts
+++ b/src/util/schemas/VoiceIdentifySchema.ts
@@ -9,4 +9,4 @@ export interface VoiceIdentifySchema {
rid: string;
quality: number;
}[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/VoiceStateUpdateSchema.ts b/src/util/schemas/VoiceStateUpdateSchema.ts
index 5f805f4d..79e93b07 100644
--- a/src/util/schemas/VoiceStateUpdateSchema.ts
+++ b/src/util/schemas/VoiceStateUpdateSchema.ts
@@ -15,8 +15,8 @@ export const VoiceStateUpdateSchema = {
$channel_id: String,
self_mute: Boolean,
self_deaf: Boolean,
- $self_video: Boolean, //required in docs but bots don't always send it
+ $self_video: Boolean, //required in docs but bots don't always send it
$preferred_region: String,
$request_to_speak_timestamp: Date,
$suppress: Boolean,
-};
\ No newline at end of file
+};
diff --git a/src/util/schemas/VoiceVideoSchema.ts b/src/util/schemas/VoiceVideoSchema.ts
index 837ee1e7..0ba519e1 100644
--- a/src/util/schemas/VoiceVideoSchema.ts
+++ b/src/util/schemas/VoiceVideoSchema.ts
@@ -12,6 +12,6 @@ export interface VoiceVideoSchema {
rtx_ssrc: number;
max_bitrate: number;
max_framerate: number;
- max_resolution: { type: string; width: number; height: number; };
+ max_resolution: { type: string; width: number; height: number };
}[];
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/WebhookCreateSchema.ts b/src/util/schemas/WebhookCreateSchema.ts
index c32b642d..99f6a12f 100644
--- a/src/util/schemas/WebhookCreateSchema.ts
+++ b/src/util/schemas/WebhookCreateSchema.ts
@@ -5,4 +5,4 @@ export interface WebhookCreateSchema {
*/
name: string;
avatar: string;
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/WidgetModifySchema.ts b/src/util/schemas/WidgetModifySchema.ts
index 3c84b3a1..26d4504f 100644
--- a/src/util/schemas/WidgetModifySchema.ts
+++ b/src/util/schemas/WidgetModifySchema.ts
@@ -1,4 +1,4 @@
export interface WidgetModifySchema {
enabled: boolean; // whether the widget is enabled
channel_id: string; // the widget channel id
-}
\ No newline at end of file
+}
diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts
index f86552f3..ae80de71 100644
--- a/src/util/schemas/index.ts
+++ b/src/util/schemas/index.ts
@@ -38,4 +38,4 @@ export * from "./VoiceStateUpdateSchema";
export * from "./VoiceVideoSchema";
export * from "./IdentifySchema";
export * from "./ActivitySchema";
-export * from "./LazyRequestSchema";
\ No newline at end of file
+export * from "./LazyRequestSchema";
diff --git a/src/util/util/ApiError.ts b/src/util/util/ApiError.ts
index f1a9b4f6..0fce6882 100644
--- a/src/util/util/ApiError.ts
+++ b/src/util/util/ApiError.ts
@@ -3,23 +3,34 @@ export class ApiError extends Error {
readonly message: string,
public readonly code: number,
public readonly httpStatus: number = 400,
- public readonly defaultParams?: string[]
+ public readonly defaultParams?: string[],
) {
super(message);
}
withDefaultParams(): ApiError {
if (this.defaultParams)
- return new ApiError(applyParamsToString(this.message, this.defaultParams), this.code, this.httpStatus);
+ return new ApiError(
+ applyParamsToString(this.message, this.defaultParams),
+ this.code,
+ this.httpStatus,
+ );
return this;
}
withParams(...params: (string | number)[]): ApiError {
- return new ApiError(applyParamsToString(this.message, params), this.code, this.httpStatus);
+ return new ApiError(
+ applyParamsToString(this.message, params),
+ this.code,
+ this.httpStatus,
+ );
}
}
-export function applyParamsToString(s: string, params: (string | number)[]): string {
+export function applyParamsToString(
+ s: string,
+ params: (string | number)[],
+): string {
let newString = s;
params.forEach((a) => {
newString = newString.replace("{}", "" + a);
diff --git a/src/util/util/AutoUpdate.ts b/src/util/util/AutoUpdate.ts
index fd65ecf5..769d959f 100644
--- a/src/util/util/AutoUpdate.ts
+++ b/src/util/util/AutoUpdate.ts
@@ -1,6 +1,6 @@
import "missing-native-js-functions";
import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
+import ProxyAgent from "proxy-agent";
import readline from "readline";
import fs from "fs/promises";
import path from "path";
@@ -19,14 +19,17 @@ export function enableAutoUpdate(opts: {
}) {
if (!opts.checkInterval) return;
var interval = 1000 * 60 * 60 * 24;
- if (typeof opts.checkInterval === "number") opts.checkInterval = 1000 * interval;
+ if (typeof opts.checkInterval === "number")
+ opts.checkInterval = 1000 * interval;
const i = setInterval(async () => {
const currentVersion = await getCurrentVersion(opts.path);
const latestVersion = await getLatestVersion(opts.packageJsonLink);
if (currentVersion !== latestVersion) {
clearInterval(i);
- console.log(`[Auto Update] Current version (${currentVersion}) is out of date, updating ...`);
+ console.log(
+ `[Auto Update] Current version (${currentVersion}) is out of date, updating ...`,
+ );
await download(opts.downloadUrl, opts.path);
}
}, interval);
@@ -43,7 +46,7 @@ export function enableAutoUpdate(opts: {
} else {
console.log(`[Auto update] aborted`);
}
- }
+ },
);
}
});
@@ -65,7 +68,9 @@ async function download(url: string, dir: string) {
async function getCurrentVersion(dir: string) {
try {
- const content = await fs.readFile(path.join(dir, "package.json"), { encoding: "utf8" });
+ const content = await fs.readFile(path.join(dir, "package.json"), {
+ encoding: "utf8",
+ });
return JSON.parse(content).version;
} catch (error) {
throw new Error("[Auto update] couldn't get current version in " + dir);
@@ -76,7 +81,7 @@ async function getLatestVersion(url: string) {
try {
const agent = new ProxyAgent();
const response = await fetch(url, { agent });
- const content = await response.json() as any; // TODO: types
+ const content = (await response.json()) as any; // TODO: types
return content.version;
} catch (error) {
throw new Error("[Auto update] check failed for " + url);
diff --git a/src/util/util/BannedWords.ts b/src/util/util/BannedWords.ts
index 891a5980..74a82efe 100644
--- a/src/util/util/BannedWords.ts
+++ b/src/util/util/BannedWords.ts
@@ -6,7 +6,9 @@ var words: string[];
export const BannedWords = {
init: async function init() {
if (words) return words;
- const file = (await fs.readFile(path.join(process.cwd(), "bannedWords"))).toString();
+ const file = (
+ await fs.readFile(path.join(process.cwd(), "bannedWords"))
+ ).toString();
if (!file) {
words = [];
return [];
@@ -18,6 +20,6 @@ export const BannedWords = {
get: () => words,
find: (val: string) => {
- return words.some(x => val.indexOf(x) != -1);
- }
-};
\ No newline at end of file
+ return words.some((x) => val.indexOf(x) != -1);
+ },
+};
diff --git a/src/util/util/BitField.ts b/src/util/util/BitField.ts
index fb887e05..4e606660 100644
--- a/src/util/util/BitField.ts
+++ b/src/util/util/BitField.ts
@@ -3,7 +3,12 @@
// https://github.com/discordjs/discord.js/blob/master/src/util/BitField.js
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-export type BitFieldResolvable = number | BigInt | BitField | string | BitFieldResolvable[];
+export type BitFieldResolvable =
+ | number
+ | BigInt
+ | BitField
+ | string
+ | BitFieldResolvable[];
/**
* Data structure that makes it easy to interact with a bitfield.
@@ -91,7 +96,8 @@ export class BitField {
*/
serialize() {
const serialized: Record<string, boolean> = {};
- for (const [flag, bit] of Object.entries(BitField.FLAGS)) serialized[flag] = this.has(bit);
+ for (const [flag, bit] of Object.entries(BitField.FLAGS))
+ serialized[flag] = this.has(bit);
return serialized;
}
@@ -130,14 +136,21 @@ export class BitField {
static resolve(bit: BitFieldResolvable = BigInt(0)): bigint {
// @ts-ignore
const FLAGS = this.FLAGS || this.constructor?.FLAGS;
- if ((typeof bit === "number" || typeof bit === "bigint") && bit >= BigInt(0)) return BigInt(bit);
+ if (
+ (typeof bit === "number" || typeof bit === "bigint") &&
+ bit >= BigInt(0)
+ )
+ return BigInt(bit);
if (bit instanceof BitField) return bit.bitfield;
if (Array.isArray(bit)) {
// @ts-ignore
const resolve = this.constructor?.resolve || this.resolve;
- return bit.map((p) => resolve.call(this, p)).reduce((prev, p) => BigInt(prev) | BigInt(p), BigInt(0));
+ 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);
}
}
diff --git a/src/util/util/Categories.ts b/src/util/util/Categories.ts
index a3c69da7..cd706a8a 100644
--- a/src/util/util/Categories.ts
+++ b/src/util/util/Categories.ts
@@ -1 +1 @@
-//TODO: populate default discord categories + init, get and set methods
\ No newline at end of file
+//TODO: populate default discord categories + init, get and set methods
diff --git a/src/util/util/Config.ts b/src/util/util/Config.ts
index 31b8d97c..7fab7f90 100644
--- a/src/util/util/Config.ts
+++ b/src/util/util/Config.ts
@@ -1,5 +1,9 @@
import "missing-native-js-functions";
-import { ConfigValue, ConfigEntity, DefaultConfigOptions } from "../entities/Config";
+import {
+ ConfigValue,
+ ConfigEntity,
+ DefaultConfigOptions,
+} from "../entities/Config";
import path from "path";
import fs from "fs";
@@ -42,7 +46,11 @@ export const Config = {
function applyConfig(val: ConfigValue) {
async function apply(obj: any, key = ""): Promise<any> {
if (typeof obj === "object" && obj !== null)
- return Promise.all(Object.keys(obj).map((k) => apply(obj[k], key ? `${key}_${k}` : k)));
+ return Promise.all(
+ Object.keys(obj).map((k) =>
+ apply(obj[k], key ? `${key}_${k}` : k),
+ ),
+ );
let pair = pairs.find((x) => x.key === key);
if (!pair) pair = new ConfigEntity();
@@ -67,7 +75,8 @@ function pairsToConfig(pairs: ConfigEntity[]) {
let i = 0;
for (const key of keys) {
- if (!isNaN(Number(key)) && !prevObj[prev]?.length) prevObj[prev] = obj = [];
+ if (!isNaN(Number(key)) && !prevObj[prev]?.length)
+ prevObj[prev] = obj = [];
if (i++ === keys.length - 1) obj[key] = p.value;
else if (!obj[key]) obj[key] = {};
diff --git a/src/util/util/Constants.ts b/src/util/util/Constants.ts
index 81a7165d..7c5b7dcb 100644
--- a/src/util/util/Constants.ts
+++ b/src/util/util/Constants.ts
@@ -77,9 +77,9 @@ export const VoiceOPCodes = {
RESUME: 7,
HELLO: 8,
RESUMED: 9,
- CLIENT_CONNECT: 12, // incorrect, op 12 is probably used for video
- CLIENT_DISCONNECT: 13, // incorrect
- VERSION: 16, //not documented
+ CLIENT_CONNECT: 12, // incorrect, op 12 is probably used for video
+ CLIENT_DISCONNECT: 13, // incorrect
+ VERSION: 16, //not documented
};
export const Events = {
@@ -160,7 +160,13 @@ export const ShardEvents = {
* sidebar for more information.</warn>
* @typedef {string} PartialType
*/
-export const PartialTypes = keyMirror(["USER", "CHANNEL", "GUILD_MEMBER", "MESSAGE", "REACTION"]);
+export const PartialTypes = keyMirror([
+ "USER",
+ "CHANNEL",
+ "GUILD_MEMBER",
+ "MESSAGE",
+ "REACTION",
+]);
/**
* The type of a websocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
@@ -291,7 +297,7 @@ export const MessageTypes = [
* @typedef {string} SystemMessageType
*/
export const SystemMessageTypes = MessageTypes.filter(
- (type: string | null) => type && type !== "DEFAULT" && type !== "REPLY"
+ (type: string | null) => type && type !== "DEFAULT" && type !== "REPLY",
);
/**
@@ -305,7 +311,14 @@ export const SystemMessageTypes = MessageTypes.filter(
* * COMPETING
* @typedef {string} ActivityType
*/
-export const ActivityTypes = ["PLAYING", "STREAMING", "LISTENING", "WATCHING", "CUSTOM_STATUS", "COMPETING"];
+export const ActivityTypes = [
+ "PLAYING",
+ "STREAMING",
+ "LISTENING",
+ "WATCHING",
+ "CUSTOM_STATUS",
+ "COMPETING",
+];
export const ChannelTypes = {
TEXT: 0,
@@ -361,7 +374,11 @@ export const Colors = {
* * ALL_MEMBERS
* @typedef {string} ExplicitContentFilterLevel
*/
-export const ExplicitContentFilterLevels = ["DISABLED", "MEMBERS_WITHOUT_ROLES", "ALL_MEMBERS"];
+export const ExplicitContentFilterLevels = [
+ "DISABLED",
+ "MEMBERS_WITHOUT_ROLES",
+ "ALL_MEMBERS",
+];
/**
* The value set for the verification levels for a guild:
@@ -372,7 +389,13 @@ export const ExplicitContentFilterLevels = ["DISABLED", "MEMBERS_WITHOUT_ROLES",
* * VERY_HIGH
* @typedef {string} VerificationLevel
*/
-export const VerificationLevels = ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"];
+export const VerificationLevels = [
+ "NONE",
+ "LOW",
+ "MEDIUM",
+ "HIGH",
+ "VERY_HIGH",
+];
/**
* An error encountered while performing an API request. Here are the potential errors:
@@ -517,7 +540,10 @@ export const VerificationLevels = ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"]
*/
export const DiscordApiErrors = {
//https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes
- GENERAL_ERROR: new ApiError("General error (such as a malformed request body, amongst other things)", 0),
+ GENERAL_ERROR: new ApiError(
+ "General error (such as a malformed request body, amongst other things)",
+ 0,
+ ),
UNKNOWN_ACCOUNT: new ApiError("Unknown account", 10001),
UNKNOWN_APPLICATION: new ApiError("Unknown application", 10002),
UNKNOWN_CHANNEL: new ApiError("Unknown channel", 10003),
@@ -542,185 +568,410 @@ export const DiscordApiErrors = {
UNKNOWN_BUILD: new ApiError("Unknown build", 10030),
UNKNOWN_LOBBY: new ApiError("Unknown lobby", 10031),
UNKNOWN_BRANCH: new ApiError("Unknown branch", 10032),
- UNKNOWN_STORE_DIRECTORY_LAYOUT: new ApiError("Unknown store directory layout", 10033),
+ UNKNOWN_STORE_DIRECTORY_LAYOUT: new ApiError(
+ "Unknown store directory layout",
+ 10033,
+ ),
UNKNOWN_REDISTRIBUTABLE: new ApiError("Unknown redistributable", 10036),
UNKNOWN_GIFT_CODE: new ApiError("Unknown gift code", 10038),
UNKNOWN_STREAM: new ApiError("Unknown stream", 10049),
- UNKNOWN_PREMIUM_SERVER_SUBSCRIBE_COOLDOWN: new ApiError("Unknown premium server subscribe cooldown", 10050),
+ UNKNOWN_PREMIUM_SERVER_SUBSCRIBE_COOLDOWN: new ApiError(
+ "Unknown premium server subscribe cooldown",
+ 10050,
+ ),
UNKNOWN_GUILD_TEMPLATE: new ApiError("Unknown guild template", 10057),
- UNKNOWN_DISCOVERABLE_SERVER_CATEGORY: new ApiError("Unknown discoverable server category", 10059),
+ UNKNOWN_DISCOVERABLE_SERVER_CATEGORY: new ApiError(
+ "Unknown discoverable server category",
+ 10059,
+ ),
UNKNOWN_STICKER: new ApiError("Unknown sticker", 10060),
UNKNOWN_INTERACTION: new ApiError("Unknown interaction", 10062),
- UNKNOWN_APPLICATION_COMMAND: new ApiError("Unknown application command", 10063),
- UNKNOWN_APPLICATION_COMMAND_PERMISSIONS: new ApiError("Unknown application command permissions", 10066),
+ UNKNOWN_APPLICATION_COMMAND: new ApiError(
+ "Unknown application command",
+ 10063,
+ ),
+ UNKNOWN_APPLICATION_COMMAND_PERMISSIONS: new ApiError(
+ "Unknown application command permissions",
+ 10066,
+ ),
UNKNOWN_STAGE_INSTANCE: new ApiError("Unknown Stage Instance", 10067),
- UNKNOWN_GUILD_MEMBER_VERIFICATION_FORM: new ApiError("Unknown Guild Member Verification Form", 10068),
- UNKNOWN_GUILD_WELCOME_SCREEN: new ApiError("Unknown Guild Welcome Screen", 10069),
- UNKNOWN_GUILD_SCHEDULED_EVENT: new ApiError("Unknown Guild Scheduled Event", 10070),
- UNKNOWN_GUILD_SCHEDULED_EVENT_USER: new ApiError("Unknown Guild Scheduled Event User", 10071),
- BOT_PROHIBITED_ENDPOINT: new ApiError("Bots cannot use this endpoint", 20001),
+ UNKNOWN_GUILD_MEMBER_VERIFICATION_FORM: new ApiError(
+ "Unknown Guild Member Verification Form",
+ 10068,
+ ),
+ UNKNOWN_GUILD_WELCOME_SCREEN: new ApiError(
+ "Unknown Guild Welcome Screen",
+ 10069,
+ ),
+ UNKNOWN_GUILD_SCHEDULED_EVENT: new ApiError(
+ "Unknown Guild Scheduled Event",
+ 10070,
+ ),
+ UNKNOWN_GUILD_SCHEDULED_EVENT_USER: new ApiError(
+ "Unknown Guild Scheduled Event User",
+ 10071,
+ ),
+ BOT_PROHIBITED_ENDPOINT: new ApiError(
+ "Bots cannot use this endpoint",
+ 20001,
+ ),
BOT_ONLY_ENDPOINT: new ApiError("Only bots can use this endpoint", 20002),
EXPLICIT_CONTENT_CANNOT_BE_SENT_TO_RECIPIENT: new ApiError(
"Explicit content cannot be sent to the desired recipient(s)",
- 20009
+ 20009,
),
ACTION_NOT_AUTHORIZED_ON_APPLICATION: new ApiError(
"You are not authorized to perform this action on this application",
- 20012
+ 20012,
+ ),
+ SLOWMODE_RATE_LIMIT: new ApiError(
+ "This action cannot be performed due to slowmode rate limit",
+ 20016,
+ ),
+ ONLY_OWNER: new ApiError(
+ "Only the owner of this account can perform this action",
+ 20018,
+ ),
+ ANNOUNCEMENT_RATE_LIMITS: new ApiError(
+ "This message cannot be edited due to announcement rate limits",
+ 20022,
+ ),
+ CHANNEL_WRITE_RATELIMIT: new ApiError(
+ "The channel you are writing has hit the write rate limit",
+ 20028,
),
- SLOWMODE_RATE_LIMIT: new ApiError("This action cannot be performed due to slowmode rate limit", 20016),
- ONLY_OWNER: new ApiError("Only the owner of this account can perform this action", 20018),
- ANNOUNCEMENT_RATE_LIMITS: new ApiError("This message cannot be edited due to announcement rate limits", 20022),
- CHANNEL_WRITE_RATELIMIT: new ApiError("The channel you are writing has hit the write rate limit", 20028),
WORDS_NOT_ALLOWED: new ApiError(
"Your Stage topic, server name, server description, or channel names contain words that are not allowed",
- 20031
- ),
- GUILD_PREMIUM_LEVEL_TOO_LOW: new ApiError("Guild premium subscription level too low", 20035),
- MAXIMUM_GUILDS: new ApiError("Maximum number of guilds reached ({})", 30001, undefined, ["100"]),
- MAXIMUM_FRIENDS: new ApiError("Maximum number of friends reached ({})", 30002, undefined, ["1000"]),
- MAXIMUM_PINS: new ApiError("Maximum number of pins reached for the channel ({})", 30003, undefined, ["50"]),
- MAXIMUM_NUMBER_OF_RECIPIENTS_REACHED: new ApiError("Maximum number of recipients reached ({})", 30004, undefined, [
- "10",
- ]),
- MAXIMUM_ROLES: new ApiError("Maximum number of guild roles reached ({})", 30005, undefined, ["250"]),
- MAXIMUM_WEBHOOKS: new ApiError("Maximum number of webhooks reached ({})", 30007, undefined, ["10"]),
- MAXIMUM_NUMBER_OF_EMOJIS_REACHED: new ApiError("Maximum number of emojis reached", 30008),
- MAXIMUM_REACTIONS: new ApiError("Maximum number of reactions reached ({})", 30010, undefined, ["20"]),
- MAXIMUM_CHANNELS: new ApiError("Maximum number of guild channels reached ({})", 30013, undefined, ["500"]),
- MAXIMUM_ATTACHMENTS: new ApiError("Maximum number of attachments in a message reached ({})", 30015, undefined, [
- "10",
- ]),
- MAXIMUM_INVITES: new ApiError("Maximum number of invites reached ({})", 30016, undefined, ["1000"]),
- MAXIMUM_ANIMATED_EMOJIS: new ApiError("Maximum number of animated emojis reached", 30018),
- MAXIMUM_SERVER_MEMBERS: new ApiError("Maximum number of server members reached", 30019),
+ 20031,
+ ),
+ GUILD_PREMIUM_LEVEL_TOO_LOW: new ApiError(
+ "Guild premium subscription level too low",
+ 20035,
+ ),
+ MAXIMUM_GUILDS: new ApiError(
+ "Maximum number of guilds reached ({})",
+ 30001,
+ undefined,
+ ["100"],
+ ),
+ MAXIMUM_FRIENDS: new ApiError(
+ "Maximum number of friends reached ({})",
+ 30002,
+ undefined,
+ ["1000"],
+ ),
+ MAXIMUM_PINS: new ApiError(
+ "Maximum number of pins reached for the channel ({})",
+ 30003,
+ undefined,
+ ["50"],
+ ),
+ MAXIMUM_NUMBER_OF_RECIPIENTS_REACHED: new ApiError(
+ "Maximum number of recipients reached ({})",
+ 30004,
+ undefined,
+ ["10"],
+ ),
+ MAXIMUM_ROLES: new ApiError(
+ "Maximum number of guild roles reached ({})",
+ 30005,
+ undefined,
+ ["250"],
+ ),
+ MAXIMUM_WEBHOOKS: new ApiError(
+ "Maximum number of webhooks reached ({})",
+ 30007,
+ undefined,
+ ["10"],
+ ),
+ MAXIMUM_NUMBER_OF_EMOJIS_REACHED: new ApiError(
+ "Maximum number of emojis reached",
+ 30008,
+ ),
+ MAXIMUM_REACTIONS: new ApiError(
+ "Maximum number of reactions reached ({})",
+ 30010,
+ undefined,
+ ["20"],
+ ),
+ MAXIMUM_CHANNELS: new ApiError(
+ "Maximum number of guild channels reached ({})",
+ 30013,
+ undefined,
+ ["500"],
+ ),
+ MAXIMUM_ATTACHMENTS: new ApiError(
+ "Maximum number of attachments in a message reached ({})",
+ 30015,
+ undefined,
+ ["10"],
+ ),
+ MAXIMUM_INVITES: new ApiError(
+ "Maximum number of invites reached ({})",
+ 30016,
+ undefined,
+ ["1000"],
+ ),
+ MAXIMUM_ANIMATED_EMOJIS: new ApiError(
+ "Maximum number of animated emojis reached",
+ 30018,
+ ),
+ MAXIMUM_SERVER_MEMBERS: new ApiError(
+ "Maximum number of server members reached",
+ 30019,
+ ),
MAXIMUM_SERVER_CATEGORIES: new ApiError(
"Maximum number of server categories has been reached ({})",
30030,
undefined,
- ["5"]
+ ["5"],
+ ),
+ GUILD_ALREADY_HAS_TEMPLATE: new ApiError(
+ "Guild already has a template",
+ 30031,
+ ),
+ MAXIMUM_THREAD_PARTICIPANTS: new ApiError(
+ "Max number of thread participants has been reached",
+ 30033,
),
- GUILD_ALREADY_HAS_TEMPLATE: new ApiError("Guild already has a template", 30031),
- MAXIMUM_THREAD_PARTICIPANTS: new ApiError("Max number of thread participants has been reached", 30033),
MAXIMUM_BANS_FOR_NON_GUILD_MEMBERS: new ApiError(
"Maximum number of bans for non-guild members have been exceeded",
- 30035
+ 30035,
+ ),
+ MAXIMUM_BANS_FETCHES: new ApiError(
+ "Maximum number of bans fetches has been reached",
+ 30037,
),
- MAXIMUM_BANS_FETCHES: new ApiError("Maximum number of bans fetches has been reached", 30037),
MAXIMUM_STICKERS: new ApiError("Maximum number of stickers reached", 30039),
- MAXIMUM_PRUNE_REQUESTS: new ApiError("Maximum number of prune requests has been reached. Try again later", 30040),
- UNAUTHORIZED: new ApiError("Unauthorized. Provide a valid token and try again", 40001),
+ MAXIMUM_PRUNE_REQUESTS: new ApiError(
+ "Maximum number of prune requests has been reached. Try again later",
+ 30040,
+ ),
+ UNAUTHORIZED: new ApiError(
+ "Unauthorized. Provide a valid token and try again",
+ 40001,
+ ),
ACCOUNT_VERIFICATION_REQUIRED: new ApiError(
"You need to verify your account in order to perform this action",
- 40002
+ 40002,
+ ),
+ OPENING_DIRECT_MESSAGES_TOO_FAST: new ApiError(
+ "You are opening direct messages too fast",
+ 40003,
+ ),
+ REQUEST_ENTITY_TOO_LARGE: new ApiError(
+ "Request entity too large. Try sending something smaller in size",
+ 40005,
+ ),
+ FEATURE_TEMPORARILY_DISABLED: new ApiError(
+ "This feature has been temporarily disabled server-side",
+ 40006,
),
- OPENING_DIRECT_MESSAGES_TOO_FAST: new ApiError("You are opening direct messages too fast", 40003),
- REQUEST_ENTITY_TOO_LARGE: new ApiError("Request entity too large. Try sending something smaller in size", 40005),
- FEATURE_TEMPORARILY_DISABLED: new ApiError("This feature has been temporarily disabled server-side", 40006),
USER_BANNED: new ApiError("The user is banned from this guild", 40007),
- TARGET_USER_IS_NOT_CONNECTED_TO_VOICE: new ApiError("Target user is not connected to voice", 40032),
- ALREADY_CROSSPOSTED: new ApiError("This message has already been crossposted", 40033),
- APPLICATION_COMMAND_ALREADY_EXISTS: new ApiError("An application command with that name already exists", 40041),
+ TARGET_USER_IS_NOT_CONNECTED_TO_VOICE: new ApiError(
+ "Target user is not connected to voice",
+ 40032,
+ ),
+ ALREADY_CROSSPOSTED: new ApiError(
+ "This message has already been crossposted",
+ 40033,
+ ),
+ APPLICATION_COMMAND_ALREADY_EXISTS: new ApiError(
+ "An application command with that name already exists",
+ 40041,
+ ),
MISSING_ACCESS: new ApiError("Missing access", 50001),
INVALID_ACCOUNT_TYPE: new ApiError("Invalid account type", 50002),
- CANNOT_EXECUTE_ON_DM: new ApiError("Cannot execute action on a DM channel", 50003),
+ CANNOT_EXECUTE_ON_DM: new ApiError(
+ "Cannot execute action on a DM channel",
+ 50003,
+ ),
EMBED_DISABLED: new ApiError("Guild widget disabled", 50004),
- CANNOT_EDIT_MESSAGE_BY_OTHER: new ApiError("Cannot edit a message authored by another user", 50005),
- CANNOT_SEND_EMPTY_MESSAGE: new ApiError("Cannot send an empty message", 50006),
- CANNOT_MESSAGE_USER: new ApiError("Cannot send messages to this user", 50007),
- CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL: new ApiError("Cannot send messages in a voice channel", 50008),
+ CANNOT_EDIT_MESSAGE_BY_OTHER: new ApiError(
+ "Cannot edit a message authored by another user",
+ 50005,
+ ),
+ CANNOT_SEND_EMPTY_MESSAGE: new ApiError(
+ "Cannot send an empty message",
+ 50006,
+ ),
+ CANNOT_MESSAGE_USER: new ApiError(
+ "Cannot send messages to this user",
+ 50007,
+ ),
+ CANNOT_SEND_MESSAGES_IN_VOICE_CHANNEL: new ApiError(
+ "Cannot send messages in a voice channel",
+ 50008,
+ ),
CHANNEL_VERIFICATION_LEVEL_TOO_HIGH: new ApiError(
"Channel verification level is too high for you to gain access",
- 50009
+ 50009,
+ ),
+ OAUTH2_APPLICATION_BOT_ABSENT: new ApiError(
+ "OAuth2 application does not have a bot",
+ 50010,
+ ),
+ MAXIMUM_OAUTH2_APPLICATIONS: new ApiError(
+ "OAuth2 application limit reached",
+ 50011,
),
- OAUTH2_APPLICATION_BOT_ABSENT: new ApiError("OAuth2 application does not have a bot", 50010),
- MAXIMUM_OAUTH2_APPLICATIONS: new ApiError("OAuth2 application limit reached", 50011),
INVALID_OAUTH_STATE: new ApiError("Invalid OAuth2 state", 50012),
- MISSING_PERMISSIONS: new ApiError("You lack permissions to perform that action ({})", 50013, undefined, [""]),
- INVALID_AUTHENTICATION_TOKEN: new ApiError("Invalid authentication token provided", 50014),
+ MISSING_PERMISSIONS: new ApiError(
+ "You lack permissions to perform that action ({})",
+ 50013,
+ undefined,
+ [""],
+ ),
+ INVALID_AUTHENTICATION_TOKEN: new ApiError(
+ "Invalid authentication token provided",
+ 50014,
+ ),
NOTE_TOO_LONG: new ApiError("Note was too long", 50015),
INVALID_BULK_DELETE_QUANTITY: new ApiError(
"Provided too few or too many messages to delete. Must provide at least {} and fewer than {} messages to delete",
50016,
undefined,
- ["2", "100"]
+ ["2", "100"],
),
CANNOT_PIN_MESSAGE_IN_OTHER_CHANNEL: new ApiError(
"A message can only be pinned to the channel it was sent in",
- 50019
- ),
- INVALID_OR_TAKEN_INVITE_CODE: new ApiError("Invite code was either invalid or taken", 50020),
- CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: new ApiError("Cannot execute action on a system message", 50021),
- CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE: new ApiError("Cannot execute action on this channel type", 50024),
- INVALID_OAUTH_TOKEN: new ApiError("Invalid OAuth2 access token provided", 50025),
- MISSING_REQUIRED_OAUTH2_SCOPE: new ApiError("Missing required OAuth2 scope", 50026),
- INVALID_WEBHOOK_TOKEN_PROVIDED: new ApiError("Invalid webhook token provided", 50027),
+ 50019,
+ ),
+ INVALID_OR_TAKEN_INVITE_CODE: new ApiError(
+ "Invite code was either invalid or taken",
+ 50020,
+ ),
+ CANNOT_EXECUTE_ON_SYSTEM_MESSAGE: new ApiError(
+ "Cannot execute action on a system message",
+ 50021,
+ ),
+ CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE: new ApiError(
+ "Cannot execute action on this channel type",
+ 50024,
+ ),
+ INVALID_OAUTH_TOKEN: new ApiError(
+ "Invalid OAuth2 access token provided",
+ 50025,
+ ),
+ MISSING_REQUIRED_OAUTH2_SCOPE: new ApiError(
+ "Missing required OAuth2 scope",
+ 50026,
+ ),
+ INVALID_WEBHOOK_TOKEN_PROVIDED: new ApiError(
+ "Invalid webhook token provided",
+ 50027,
+ ),
INVALID_ROLE: new ApiError("Invalid role", 50028),
INVALID_RECIPIENT: new ApiError("Invalid Recipient(s)", 50033),
- BULK_DELETE_MESSAGE_TOO_OLD: new ApiError("A message provided was too old to bulk delete", 50034),
+ BULK_DELETE_MESSAGE_TOO_OLD: new ApiError(
+ "A message provided was too old to bulk delete",
+ 50034,
+ ),
INVALID_FORM_BODY: new ApiError(
"Invalid form body (returned for both application/json and multipart/form-data bodies), or invalid Content-Type provided",
- 50035
+ 50035,
),
INVITE_ACCEPTED_TO_GUILD_NOT_CONTAINING_BOT: new ApiError(
"An invite was accepted to a guild the application's bot is not in",
- 50036
+ 50036,
),
INVALID_API_VERSION: new ApiError("Invalid API version provided", 50041),
- FILE_EXCEEDS_MAXIMUM_SIZE: new ApiError("File uploaded exceeds the maximum size", 50045),
+ FILE_EXCEEDS_MAXIMUM_SIZE: new ApiError(
+ "File uploaded exceeds the maximum size",
+ 50045,
+ ),
INVALID_FILE_UPLOADED: new ApiError("Invalid file uploaded", 50046),
- CANNOT_SELF_REDEEM_GIFT: new ApiError("Cannot self-redeem this gift", 50054),
- PAYMENT_SOURCE_REQUIRED: new ApiError("Payment source required to redeem gift", 50070),
+ CANNOT_SELF_REDEEM_GIFT: new ApiError(
+ "Cannot self-redeem this gift",
+ 50054,
+ ),
+ PAYMENT_SOURCE_REQUIRED: new ApiError(
+ "Payment source required to redeem gift",
+ 50070,
+ ),
CANNOT_DELETE_COMMUNITY_REQUIRED_CHANNEL: new ApiError(
"Cannot delete a channel required for Community guilds",
- 50074
+ 50074,
),
INVALID_STICKER_SENT: new ApiError("Invalid sticker sent", 50081),
CANNOT_EDIT_ARCHIVED_THREAD: new ApiError(
"Tried to perform an operation on an archived thread, such as editing a message or adding a user to the thread",
- 50083
+ 50083,
+ ),
+ INVALID_THREAD_NOTIFICATION_SETTINGS: new ApiError(
+ "Invalid thread notification settings",
+ 50084,
),
- INVALID_THREAD_NOTIFICATION_SETTINGS: new ApiError("Invalid thread notification settings", 50084),
BEFORE_EARLIER_THAN_THREAD_CREATION_DATE: new ApiError(
"before value is earlier than the thread creation date",
- 50085
+ 50085,
+ ),
+ SERVER_NOT_AVAILABLE_IN_YOUR_LOCATION: new ApiError(
+ "This server is not available in your location",
+ 50095,
),
- SERVER_NOT_AVAILABLE_IN_YOUR_LOCATION: new ApiError("This server is not available in your location", 50095),
SERVER_NEEDS_MONETIZATION_ENABLED: new ApiError(
"This server needs monetization enabled in order to perform this action",
- 50097
+ 50097,
+ ),
+ TWO_FACTOR_REQUIRED: new ApiError(
+ "Two factor is required for this operation",
+ 60003,
+ ),
+ NO_USERS_WITH_DISCORDTAG_EXIST: new ApiError(
+ "No users with DiscordTag exist",
+ 80004,
),
- TWO_FACTOR_REQUIRED: new ApiError("Two factor is required for this operation", 60003),
- NO_USERS_WITH_DISCORDTAG_EXIST: new ApiError("No users with DiscordTag exist", 80004),
REACTION_BLOCKED: new ApiError("Reaction was blocked", 90001),
- RESOURCE_OVERLOADED: new ApiError("API resource is currently overloaded. Try again a little later", 130000),
+ RESOURCE_OVERLOADED: new ApiError(
+ "API resource is currently overloaded. Try again a little later",
+ 130000,
+ ),
STAGE_ALREADY_OPEN: new ApiError("The Stage is already open", 150006),
- THREAD_ALREADY_CREATED_FOR_THIS_MESSAGE: new ApiError("A thread has already been created for this message", 160004),
+ THREAD_ALREADY_CREATED_FOR_THIS_MESSAGE: new ApiError(
+ "A thread has already been created for this message",
+ 160004,
+ ),
THREAD_IS_LOCKED: new ApiError("Thread is locked", 160005),
- MAXIMUM_NUMBER_OF_ACTIVE_THREADS: new ApiError("Maximum number of active threads reached", 160006),
+ MAXIMUM_NUMBER_OF_ACTIVE_THREADS: new ApiError(
+ "Maximum number of active threads reached",
+ 160006,
+ ),
MAXIMUM_NUMBER_OF_ACTIVE_ANNOUNCEMENT_THREADS: new ApiError(
"Maximum number of active announcement threads reached",
- 160007
+ 160007,
+ ),
+ INVALID_JSON_FOR_UPLOADED_LOTTIE_FILE: new ApiError(
+ "Invalid JSON for uploaded Lottie file",
+ 170001,
),
- INVALID_JSON_FOR_UPLOADED_LOTTIE_FILE: new ApiError("Invalid JSON for uploaded Lottie file", 170001),
LOTTIES_CANNOT_CONTAIN_RASTERIZED_IMAGES: new ApiError(
"Uploaded Lotties cannot contain rasterized images such as PNG or JPEG",
- 170002
+ 170002,
+ ),
+ STICKER_MAXIMUM_FRAMERATE: new ApiError(
+ "Sticker maximum framerate exceeded",
+ 170003,
+ ),
+ STICKER_MAXIMUM_FRAME_COUNT: new ApiError(
+ "Sticker frame count exceeds maximum of {} frames",
+ 170004,
+ undefined,
+ ["1000"],
+ ),
+ LOTTIE_ANIMATION_MAXIMUM_DIMENSIONS: new ApiError(
+ "Lottie animation maximum dimensions exceeded",
+ 170005,
),
- STICKER_MAXIMUM_FRAMERATE: new ApiError("Sticker maximum framerate exceeded", 170003),
- STICKER_MAXIMUM_FRAME_COUNT: new ApiError("Sticker frame count exceeds maximum of {} frames", 170004, undefined, [
- "1000",
- ]),
- LOTTIE_ANIMATION_MAXIMUM_DIMENSIONS: new ApiError("Lottie animation maximum dimensions exceeded", 170005),
STICKER_FRAME_RATE_TOO_SMALL_OR_TOO_LARGE: new ApiError(
"Sticker frame rate is either too small or too large",
- 170006
+ 170006,
),
STICKER_ANIMATION_DURATION_MAXIMUM: new ApiError(
"Sticker animation duration exceeds maximum of {} seconds",
170007,
undefined,
- ["5"]
+ ["5"],
),
//Other errors
@@ -731,26 +982,92 @@ export const DiscordApiErrors = {
* An error encountered while performing an API request (Fosscord only). Here are the potential errors:
*/
export const FosscordApiErrors = {
- MANUALLY_TRIGGERED_ERROR: new ApiError("This is an artificial error", 1, 500),
- PREMIUM_DISABLED_FOR_GUILD: new ApiError("This guild cannot be boosted", 25001),
- NO_FURTHER_PREMIUM: new ApiError("This guild does not receive further boosts", 25002),
- GUILD_PREMIUM_DISABLED_FOR_YOU: new ApiError("This guild cannot be boosted by you", 25003, 403),
+ MANUALLY_TRIGGERED_ERROR: new ApiError(
+ "This is an artificial error",
+ 1,
+ 500,
+ ),
+ PREMIUM_DISABLED_FOR_GUILD: new ApiError(
+ "This guild cannot be boosted",
+ 25001,
+ ),
+ NO_FURTHER_PREMIUM: new ApiError(
+ "This guild does not receive further boosts",
+ 25002,
+ ),
+ GUILD_PREMIUM_DISABLED_FOR_YOU: new ApiError(
+ "This guild cannot be boosted by you",
+ 25003,
+ 403,
+ ),
CANNOT_FRIEND_SELF: new ApiError("Cannot friend oneself", 25009),
- USER_SPECIFIC_INVITE_WRONG_RECIPIENT: new ApiError("This invite is not meant for you", 25010),
+ USER_SPECIFIC_INVITE_WRONG_RECIPIENT: new ApiError(
+ "This invite is not meant for you",
+ 25010,
+ ),
USER_SPECIFIC_INVITE_FAILED: new ApiError("Failed to invite user", 25011),
- CANNOT_MODIFY_USER_GROUP: new ApiError("This user cannot manipulate this group", 25050, 403),
- CANNOT_REMOVE_SELF_FROM_GROUP: new ApiError("This user cannot remove oneself from user group", 25051),
- CANNOT_BAN_OPERATOR: new ApiError("Non-OPERATOR cannot ban OPERATOR from instance", 25052),
- CANNOT_LEAVE_GUILD: new ApiError("You are not allowed to leave guilds that you joined by yourself", 25059, 403),
- EDITS_DISABLED: new ApiError("You are not allowed to edit your own messages", 25060, 403),
- DELETE_MESSAGE_DISABLED: new ApiError("You are not allowed to delete your own messages", 25061, 403),
- FEATURE_PERMANENTLY_DISABLED: new ApiError("This feature has been disabled server-side", 45006, 501),
- MISSING_RIGHTS: new ApiError("You lack rights to perform that action ({})", 50013, undefined, [""]),
- CANNOT_REPLACE_BY_BACKFILL: new ApiError("Cannot backfill to message ID that already exists", 55002, 409),
- CANNOT_BACKFILL_TO_THE_FUTURE: new ApiError("You cannot backfill messages in the future", 55003),
- CANNOT_GRANT_PERMISSIONS_EXCEEDING_RIGHTS: new ApiError("You cannot grant permissions exceeding your own rights", 50050),
- ROUTES_LOOPING: new ApiError("Loops in the route definition ({})", 50060, undefined, [""]),
- CANNOT_REMOVE_ROUTE: new ApiError("Cannot remove message route while it is in effect and being used", 50061),
+ CANNOT_MODIFY_USER_GROUP: new ApiError(
+ "This user cannot manipulate this group",
+ 25050,
+ 403,
+ ),
+ CANNOT_REMOVE_SELF_FROM_GROUP: new ApiError(
+ "This user cannot remove oneself from user group",
+ 25051,
+ ),
+ CANNOT_BAN_OPERATOR: new ApiError(
+ "Non-OPERATOR cannot ban OPERATOR from instance",
+ 25052,
+ ),
+ CANNOT_LEAVE_GUILD: new ApiError(
+ "You are not allowed to leave guilds that you joined by yourself",
+ 25059,
+ 403,
+ ),
+ EDITS_DISABLED: new ApiError(
+ "You are not allowed to edit your own messages",
+ 25060,
+ 403,
+ ),
+ DELETE_MESSAGE_DISABLED: new ApiError(
+ "You are not allowed to delete your own messages",
+ 25061,
+ 403,
+ ),
+ FEATURE_PERMANENTLY_DISABLED: new ApiError(
+ "This feature has been disabled server-side",
+ 45006,
+ 501,
+ ),
+ MISSING_RIGHTS: new ApiError(
+ "You lack rights to perform that action ({})",
+ 50013,
+ undefined,
+ [""],
+ ),
+ CANNOT_REPLACE_BY_BACKFILL: new ApiError(
+ "Cannot backfill to message ID that already exists",
+ 55002,
+ 409,
+ ),
+ CANNOT_BACKFILL_TO_THE_FUTURE: new ApiError(
+ "You cannot backfill messages in the future",
+ 55003,
+ ),
+ CANNOT_GRANT_PERMISSIONS_EXCEEDING_RIGHTS: new ApiError(
+ "You cannot grant permissions exceeding your own rights",
+ 50050,
+ ),
+ ROUTES_LOOPING: new ApiError(
+ "Loops in the route definition ({})",
+ 50060,
+ undefined,
+ [""],
+ ),
+ CANNOT_REMOVE_ROUTE: new ApiError(
+ "Cannot remove message route while it is in effect and being used",
+ 50061,
+ ),
};
/**
@@ -769,11 +1086,7 @@ export const DefaultMessageNotifications = ["ALL", "MENTIONS", "MUTED"];
* * INSERTED (Fosscord extension)
* @typedef {string} MembershipStates
*/
-export const MembershipStates = [
- "INSERTED",
- "INVITED",
- "ACCEPTED",
-];
+export const MembershipStates = ["INSERTED", "INVITED", "ACCEPTED"];
/**
* The value set for a webhook's type:
@@ -782,15 +1095,10 @@ export const MembershipStates = [
* * Custom (Fosscord extension)
* @typedef {string} WebhookTypes
*/
-export const WebhookTypes = [
- "Custom",
- "Incoming",
- "Channel Follower",
-];
+export const WebhookTypes = ["Custom", "Incoming", "Channel Follower"];
function keyMirror(arr: string[]) {
let tmp = Object.create(null);
for (const value of arr) tmp[value] = value;
return tmp;
}
-
diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts
index ddbea57d..e96be6c4 100644
--- a/src/util/util/Database.ts
+++ b/src/util/util/Database.ts
@@ -9,7 +9,8 @@ import { yellow, green, red } from "picocolors";
// We want to generate all id's with Snowflakes that's why we have our own BaseEntity class
var dbConnection: DataSource | undefined;
-let dbConnectionString = process.env.DATABASE || path.join(process.cwd(), "database.db");
+let dbConnectionString =
+ process.env.DATABASE || path.join(process.cwd(), "database.db");
export function getDatabase(): DataSource | null {
// if (!dbConnection) throw new Error("Tried to get database before it was initialised");
@@ -20,18 +21,24 @@ export function getDatabase(): DataSource | null {
export async function initDatabase(): Promise<DataSource> {
if (dbConnection) return dbConnection;
- const type = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") : "sqlite";
+ const type = dbConnectionString.includes("://")
+ ? dbConnectionString.split(":")[0]?.replace("+srv", "")
+ : "sqlite";
const isSqlite = type.includes("sqlite");
console.log(`[Database] ${yellow(`connecting to ${type} db`)}`);
if (isSqlite) {
- console.log(`[Database] ${red(`You are running sqlite! Please keep in mind that we recommend setting up a dedicated database!`)}`);
+ console.log(
+ `[Database] ${red(
+ `You are running sqlite! Please keep in mind that we recommend setting up a dedicated database!`,
+ )}`,
+ );
}
const dataSource = new DataSource({
//@ts-ignore
type,
- charset: 'utf8mb4',
+ charset: "utf8mb4",
url: isSqlite ? undefined : dbConnectionString,
database: isSqlite ? dbConnectionString : undefined,
entities: ["dist/util/entities/*.js"],
diff --git a/src/util/util/Email.ts b/src/util/util/Email.ts
index 6885da33..c98ccff0 100644
--- a/src/util/util/Email.ts
+++ b/src/util/util/Email.ts
@@ -15,7 +15,7 @@ export function adjustEmail(email?: string): string | undefined {
// replace .dots and +alternatives -> Gmail Dot Trick https://support.google.com/mail/answer/7436150 and https://generator.email/blog/gmail-generator
let v = user.replace(/[.]|(\+.*)/g, "") + "@gmail.com";
}
-
+
if (domain === "google.com") {
// replace .dots and +alternatives -> Google Staff GMail Dot Trick
let v = user.replace(/[.]|(\+.*)/g, "") + "@google.com";
diff --git a/src/util/util/Event.ts b/src/util/util/Event.ts
index 20a638a0..c81de951 100644
--- a/src/util/util/Event.ts
+++ b/src/util/util/Event.ts
@@ -5,15 +5,27 @@ import { EVENT, Event } from "../interfaces";
export const events = new EventEmitter();
export async function emitEvent(payload: Omit<Event, "created_at">) {
- const id = (payload.channel_id || payload.user_id || payload.guild_id) as string;
+ const id = (payload.channel_id ||
+ payload.user_id ||
+ payload.guild_id) as string;
if (!id) return console.error("event doesn't contain any id", payload);
if (RabbitMQ.connection) {
- const data = typeof payload.data === "object" ? JSON.stringify(payload.data) : payload.data; // use rabbitmq for event transmission
- await RabbitMQ.channel?.assertExchange(id, "fanout", { durable: false });
+ const data =
+ typeof payload.data === "object"
+ ? JSON.stringify(payload.data)
+ : payload.data; // use rabbitmq for event transmission
+ await RabbitMQ.channel?.assertExchange(id, "fanout", {
+ durable: false,
+ });
// assertQueue isn't needed, because a queue will automatically created if it doesn't exist
- const successful = RabbitMQ.channel?.publish(id, "", Buffer.from(`${data}`), { type: payload.event });
+ const successful = RabbitMQ.channel?.publish(
+ id,
+ "",
+ Buffer.from(`${data}`),
+ { type: payload.event },
+ );
if (!successful) throw new Error("failed to send event");
} else if (process.env.EVENT_TRANSMISSION === "process") {
process.send?.({ type: "event", event: payload, id } as ProcessEvent);
@@ -48,10 +60,19 @@ export interface ProcessEvent {
id: string;
}
-export async function listenEvent(event: string, callback: (event: EventOpts) => any, opts?: ListenEventOpts) {
+export async function listenEvent(
+ event: string,
+ callback: (event: EventOpts) => any,
+ opts?: ListenEventOpts,
+) {
if (RabbitMQ.connection) {
- // @ts-ignore
- return rabbitListen(opts?.channel || RabbitMQ.channel, event, callback, { acknowledge: opts?.acknowledge });
+ return rabbitListen(
+ // @ts-ignore
+ opts?.channel || RabbitMQ.channel,
+ event,
+ callback,
+ { acknowledge: opts?.acknowledge },
+ );
} else if (process.env.EVENT_TRANSMISSION === "process") {
const cancel = () => {
process.removeListener("message", listener);
@@ -59,7 +80,9 @@ export async function listenEvent(event: string, callback: (event: EventOpts) =>
};
const listener = (msg: ProcessEvent) => {
- msg.type === "event" && msg.id === event && callback({ ...msg.event, cancel });
+ msg.type === "event" &&
+ msg.id === event &&
+ callback({ ...msg.event, cancel });
};
//@ts-ignore apparently theres no function addListener with this signature
@@ -84,10 +107,13 @@ async function rabbitListen(
channel: Channel,
id: string,
callback: (event: EventOpts) => any,
- opts?: { acknowledge?: boolean }
+ opts?: { acknowledge?: boolean },
) {
await channel.assertExchange(id, "fanout", { durable: false });
- const q = await channel.assertQueue("", { exclusive: true, autoDelete: true });
+ const q = await channel.assertQueue("", {
+ exclusive: true,
+ autoDelete: true,
+ });
const cancel = () => {
channel.cancel(q.queue);
@@ -116,7 +142,7 @@ async function rabbitListen(
},
{
noAck: !opts?.acknowledge,
- }
+ },
);
return cancel;
diff --git a/src/util/util/FieldError.ts b/src/util/util/FieldError.ts
index 406b33e8..24818fed 100644
--- a/src/util/util/FieldError.ts
+++ b/src/util/util/FieldError.ts
@@ -1,6 +1,8 @@
import "missing-native-js-functions";
-export function FieldErrors(fields: Record<string, { code?: string; message: string }>) {
+export function FieldErrors(
+ fields: Record<string, { code?: string; message: string }>,
+) {
return new FieldError(
50035,
"Invalid Form Body",
@@ -11,7 +13,7 @@ export function FieldErrors(fields: Record<string, { code?: string; message: str
code: code || "BASE_TYPE_INVALID",
},
],
- }))
+ })),
);
}
@@ -19,7 +21,11 @@ export function FieldErrors(fields: Record<string, { code?: string; message: str
// Ensure you use the proper content type (image/jpeg, image/png, image/gif) that matches the image data being provided.
export class FieldError extends Error {
- constructor(public code: string | number, public message: string, public errors?: any) {
+ constructor(
+ public code: string | number,
+ public message: string,
+ public errors?: any,
+ ) {
super(message);
}
}
diff --git a/src/util/util/Intents.ts b/src/util/util/Intents.ts
index 1e840b76..b9f4d65a 100644
--- a/src/util/util/Intents.ts
+++ b/src/util/util/Intents.ts
@@ -22,13 +22,12 @@ export class Intents extends BitField {
GUILD_POLICY_EXECUTION: BigInt(1) << BigInt(21), // guild policy execution
LIVE_MESSAGE_COMPOSITION: BigInt(1) << BigInt(32), // allow composing messages using the gateway
GUILD_ROUTES: BigInt(1) << BigInt(41), // message routes affecting the guild
- DIRECT_MESSAGES_THREADS: BigInt(1) << BigInt(42), // direct message threads
+ DIRECT_MESSAGES_THREADS: BigInt(1) << BigInt(42), // direct message threads
JUMBO_EVENTS: BigInt(1) << BigInt(43), // jumbo events (size limits to be defined later)
LOBBIES: BigInt(1) << BigInt(44), // lobbies
- INSTANCE_ROUTES: BigInt(1) << BigInt(60), // all message route changes
+ INSTANCE_ROUTES: BigInt(1) << BigInt(60), // all message route changes
INSTANCE_GUILD_CHANGES: BigInt(1) << BigInt(61), // all guild create, guild object patch, split, merge and delete events
INSTANCE_POLICY_UPDATES: BigInt(1) << BigInt(62), // all instance policy updates
- INSTANCE_USER_UPDATES: BigInt(1) << BigInt(63) // all instance user updates
+ INSTANCE_USER_UPDATES: BigInt(1) << BigInt(63), // all instance user updates
};
}
-
diff --git a/src/util/util/InvisibleCharacters.ts b/src/util/util/InvisibleCharacters.ts
index a48cfab0..da295d68 100644
--- a/src/util/util/InvisibleCharacters.ts
+++ b/src/util/util/InvisibleCharacters.ts
@@ -1,56 +1,56 @@
-// List from https://invisible-characters.com/
-export const InvisibleCharacters = [
- '\u{9}', //Tab
- //'\u{20}', //Space //categories can have spaces in them
- '\u{ad}', //Soft hyphen
- '\u{34f}', //Combining grapheme joiner
- '\u{61c}', //Arabic letter mark
- '\u{115f}', //Hangul choseong filler
- '\u{1160}', //Hangul jungseong filler
- '\u{17b4}', //Khmer vowel inherent AQ
- '\u{17b5}', //Khmer vowel inherent AA
- '\u{180e}', //Mongolian vowel separator
- '\u{2000}', //En quad
- '\u{2001}', //Em quad
- '\u{2002}', //En space
- '\u{2003}', //Em space
- '\u{2004}', //Three-per-em space
- '\u{2005}', //Four-per-em space
- '\u{2006}', //Six-per-em space
- '\u{2007}', //Figure space
- '\u{2008}', //Punctuation space
- '\u{2009}', //Thin space
- '\u{200a}', //Hair space
- '\u{200b}', //Zero width space
- '\u{200c}', //Zero width non-joiner
- '\u{200d}', //Zero width joiner
- '\u{200e}', //Left-to-right mark
- '\u{200f}', //Right-to-left mark
- '\u{202f}', //Narrow no-break space
- '\u{205f}', //Medium mathematical space
- '\u{2060}', //Word joiner
- '\u{2061}', //Function application
- '\u{2062}', //Invisible times
- '\u{2063}', //Invisible separator
- '\u{2064}', //Invisible plus
- '\u{206a}', //Inhibit symmetric swapping
- '\u{206b}', //Activate symmetric swapping
- '\u{206c}', //Inhibit arabic form shaping
- '\u{206d}', //Activate arabic form shaping
- '\u{206e}', //National digit shapes
- '\u{206f}', //Nominal digit shapes
- '\u{3000}', //Ideographic space
- '\u{2800}', //Braille pattern blank
- '\u{3164}', //Hangul filler
- '\u{feff}', //Zero width no-break space
- '\u{ffa0}', //Haldwidth hangul filler
- '\u{1d159}', //Musical symbol null notehead
- '\u{1d173}', //Musical symbol begin beam
- '\u{1d174}', //Musical symbol end beam
- '\u{1d175}', //Musical symbol begin tie
- '\u{1d176}', //Musical symbol end tie
- '\u{1d177}', //Musical symbol begin slur
- '\u{1d178}', //Musical symbol end slur
- '\u{1d179}', //Musical symbol begin phrase
- '\u{1d17a}' //Musical symbol end phrase
-];
\ No newline at end of file
+// List from https://invisible-characters.com/
+export const InvisibleCharacters = [
+ "\u{9}", //Tab
+ //'\u{20}', //Space //categories can have spaces in them
+ "\u{ad}", //Soft hyphen
+ "\u{34f}", //Combining grapheme joiner
+ "\u{61c}", //Arabic letter mark
+ "\u{115f}", //Hangul choseong filler
+ "\u{1160}", //Hangul jungseong filler
+ "\u{17b4}", //Khmer vowel inherent AQ
+ "\u{17b5}", //Khmer vowel inherent AA
+ "\u{180e}", //Mongolian vowel separator
+ "\u{2000}", //En quad
+ "\u{2001}", //Em quad
+ "\u{2002}", //En space
+ "\u{2003}", //Em space
+ "\u{2004}", //Three-per-em space
+ "\u{2005}", //Four-per-em space
+ "\u{2006}", //Six-per-em space
+ "\u{2007}", //Figure space
+ "\u{2008}", //Punctuation space
+ "\u{2009}", //Thin space
+ "\u{200a}", //Hair space
+ "\u{200b}", //Zero width space
+ "\u{200c}", //Zero width non-joiner
+ "\u{200d}", //Zero width joiner
+ "\u{200e}", //Left-to-right mark
+ "\u{200f}", //Right-to-left mark
+ "\u{202f}", //Narrow no-break space
+ "\u{205f}", //Medium mathematical space
+ "\u{2060}", //Word joiner
+ "\u{2061}", //Function application
+ "\u{2062}", //Invisible times
+ "\u{2063}", //Invisible separator
+ "\u{2064}", //Invisible plus
+ "\u{206a}", //Inhibit symmetric swapping
+ "\u{206b}", //Activate symmetric swapping
+ "\u{206c}", //Inhibit arabic form shaping
+ "\u{206d}", //Activate arabic form shaping
+ "\u{206e}", //National digit shapes
+ "\u{206f}", //Nominal digit shapes
+ "\u{3000}", //Ideographic space
+ "\u{2800}", //Braille pattern blank
+ "\u{3164}", //Hangul filler
+ "\u{feff}", //Zero width no-break space
+ "\u{ffa0}", //Haldwidth hangul filler
+ "\u{1d159}", //Musical symbol null notehead
+ "\u{1d173}", //Musical symbol begin beam
+ "\u{1d174}", //Musical symbol end beam
+ "\u{1d175}", //Musical symbol begin tie
+ "\u{1d176}", //Musical symbol end tie
+ "\u{1d177}", //Musical symbol begin slur
+ "\u{1d178}", //Musical symbol end slur
+ "\u{1d179}", //Musical symbol begin phrase
+ "\u{1d17a}", //Musical symbol end phrase
+];
diff --git a/src/util/util/Permissions.ts b/src/util/util/Permissions.ts
index a432af76..0c12487e 100644
--- a/src/util/util/Permissions.ts
+++ b/src/util/util/Permissions.ts
@@ -1,6 +1,12 @@
// https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js
// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
-import { Channel, ChannelPermissionOverwrite, Guild, Member, Role } from "../entities";
+import {
+ Channel,
+ ChannelPermissionOverwrite,
+ Guild,
+ Member,
+ Role,
+} from "../entities";
import { BitField } from "./BitField";
import "missing-native-js-functions";
import { BitFieldResolvable, BitFlag } from "./BitField";
@@ -13,7 +19,12 @@ try {
HTTPError = Error;
}
-export type PermissionResolvable = bigint | number | Permissions | PermissionResolvable[] | PermissionString;
+export type PermissionResolvable =
+ | bigint
+ | number
+ | Permissions
+ | PermissionResolvable[]
+ | PermissionString;
type PermissionString = keyof typeof Permissions.FLAGS;
@@ -80,14 +91,20 @@ export class Permissions extends BitField {
};
any(permission: PermissionResolvable, checkAdmin = true) {
- return (checkAdmin && super.any(Permissions.FLAGS.ADMINISTRATOR)) || super.any(permission);
+ return (
+ (checkAdmin && super.any(Permissions.FLAGS.ADMINISTRATOR)) ||
+ super.any(permission)
+ );
}
/**
* Checks whether the bitfield has a permission, or multiple permissions.
*/
has(permission: PermissionResolvable, checkAdmin = true) {
- return (checkAdmin && super.has(Permissions.FLAGS.ADMINISTRATOR)) || super.has(permission);
+ return (
+ (checkAdmin && super.has(Permissions.FLAGS.ADMINISTRATOR)) ||
+ super.has(permission)
+ );
}
/**
@@ -96,28 +113,39 @@ export class Permissions extends BitField {
hasThrow(permission: PermissionResolvable) {
if (this.has(permission) && this.has("VIEW_CHANNEL")) return true;
// @ts-ignore
- throw new HTTPError(`You are missing the following permissions ${permission}`, 403);
+ throw new HTTPError(
+ `You are missing the following permissions ${permission}`,
+ 403,
+ );
}
overwriteChannel(overwrites: ChannelPermissionOverwrite[]) {
if (!overwrites) return this;
if (!this.cache) throw new Error("permission chache not available");
overwrites = overwrites.filter((x) => {
- if (x.type === 0 && this.cache.roles?.some((r) => r.id === x.id)) return true;
+ if (x.type === 0 && this.cache.roles?.some((r) => r.id === x.id))
+ return true;
if (x.type === 1 && x.id == this.cache.user_id) return true;
return false;
});
- return new Permissions(Permissions.channelPermission(overwrites, this.bitfield));
+ return new Permissions(
+ Permissions.channelPermission(overwrites, this.bitfield),
+ );
}
- static channelPermission(overwrites: ChannelPermissionOverwrite[], init?: bigint) {
+ static channelPermission(
+ overwrites: ChannelPermissionOverwrite[],
+ init?: bigint,
+ ) {
// TODO: do not deny any permissions if admin
return overwrites.reduce((permission, overwrite) => {
// apply disallowed permission
// * permission: current calculated permission (e.g. 010)
// * deny contains all denied permissions (e.g. 011)
// * allow contains all explicitly allowed permisions (e.g. 100)
- return (permission & ~BigInt(overwrite.deny)) | BigInt(overwrite.allow);
+ return (
+ (permission & ~BigInt(overwrite.deny)) | BigInt(overwrite.allow)
+ );
// ~ operator inverts deny (e.g. 011 -> 100)
// & operator only allows 1 for both ~deny and permission (e.g. 010 & 100 -> 000)
// | operators adds both together (e.g. 000 + 100 -> 100)
@@ -126,7 +154,10 @@ export class Permissions extends BitField {
static rolePermission(roles: Role[]) {
// adds all permissions of all roles together (Bit OR)
- return roles.reduce((permission, role) => permission | BigInt(role.permissions), BigInt(0));
+ return roles.reduce(
+ (permission, role) => permission | BigInt(role.permissions),
+ BigInt(0),
+ );
}
static finalPermission({
@@ -157,7 +188,8 @@ export class Permissions extends BitField {
}
if (channel?.recipient_ids) {
- if (channel?.owner_id === user.id) return new Permissions("ADMINISTRATOR");
+ if (channel?.owner_id === user.id)
+ return new Permissions("ADMINISTRATOR");
if (channel.recipient_ids.includes(user.id)) {
// Default dm permissions
return new Permissions([
@@ -183,7 +215,10 @@ export class Permissions extends BitField {
}
}
-const ALL_PERMISSIONS = Object.values(Permissions.FLAGS).reduce((total, val) => total | val, BigInt(0));
+const ALL_PERMISSIONS = Object.values(Permissions.FLAGS).reduce(
+ (total, val) => total | val,
+ BigInt(0),
+);
export type PermissionCache = {
channel?: Channel | undefined;
@@ -204,7 +239,7 @@ export async function getPermission(
channel_relations?: string[];
member_select?: (keyof Member)[];
member_relations?: string[];
- } = {}
+ } = {},
) {
if (!user_id) throw new HTTPError("User not found");
var channel: Channel | undefined;
@@ -239,16 +274,17 @@ export async function getPermission(
],
relations: opts.guild_relations,
});
- if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR);
+ if (guild.owner_id === user_id)
+ return new Permissions(Permissions.FLAGS.ADMINISTRATOR);
member = await Member.findOneOrFail({
where: { guild_id, id: user_id },
relations: ["roles", ...(opts.member_relations || [])],
// select: [
- // "id", // TODO: Bug in typeorm? adding these selects breaks the query.
- // "roles",
- // @ts-ignore
- // ...(opts.member_select || []),
+ // "id", // TODO: Bug in typeorm? adding these selects breaks the query.
+ // "roles",
+ // @ts-ignore
+ // ...(opts.member_select || []),
// ],
});
}
diff --git a/src/util/util/RabbitMQ.ts b/src/util/util/RabbitMQ.ts
index 0f5eb6aa..1bfb3f5c 100644
--- a/src/util/util/RabbitMQ.ts
+++ b/src/util/util/RabbitMQ.ts
@@ -1,7 +1,11 @@
import amqp, { Connection, Channel } from "amqplib";
// 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,
channel: null,
init: async function () {
diff --git a/src/util/util/Rights.ts b/src/util/util/Rights.ts
index b28c75b7..659353a6 100644
--- a/src/util/util/Rights.ts
+++ b/src/util/util/Rights.ts
@@ -11,7 +11,12 @@ try {
HTTPError = Error;
}
-export type RightResolvable = bigint | number | Rights | RightResolvable[] | RightString;
+export type RightResolvable =
+ | bigint
+ | number
+ | Rights
+ | RightResolvable[]
+ | RightString;
type RightString = keyof typeof Rights.FLAGS;
// TODO: just like roles for members, users should have privilidges which combine multiple rights into one and make it easy to assign
@@ -60,7 +65,7 @@ export class Rights extends BitField {
CREDITABLE: BitFlag(32), // can receive money from monetisation related features
KICK_BAN_MEMBERS: BitFlag(33),
// can kick or ban guild or group DM members in the guilds/groups that they have KICK_MEMBERS, or BAN_MEMBERS
- SELF_LEAVE_GROUPS: BitFlag(34),
+ SELF_LEAVE_GROUPS: BitFlag(34),
// can leave the guilds or group DMs that they joined on their own (one can always leave a guild or group DMs they have been force-added)
PRESENCE: BitFlag(35),
// inverts the presence confidentiality default (OPERATOR's presence is not routed by default, others' are) for a given user
@@ -72,31 +77,44 @@ export class Rights extends BitField {
RESPOND_TO_INTERACTIONS: BitFlag(41), // can respond to interactions
SEND_BACKDATED_EVENTS: BitFlag(42), // can send backdated events
USE_MASS_INVITES: BitFlag(43), // added per @xnacly's request — can accept mass invites
- ACCEPT_INVITES: BitFlag(44) // added per @xnacly's request — can accept user-specific invites and DM requests
+ ACCEPT_INVITES: BitFlag(44), // added per @xnacly's request — can accept user-specific invites and DM requests
};
any(permission: RightResolvable, checkOperator = true) {
- return (checkOperator && super.any(Rights.FLAGS.OPERATOR)) || super.any(permission);
+ return (
+ (checkOperator && super.any(Rights.FLAGS.OPERATOR)) ||
+ super.any(permission)
+ );
}
has(permission: RightResolvable, checkOperator = true) {
- return (checkOperator && super.has(Rights.FLAGS.OPERATOR)) || super.has(permission);
+ return (
+ (checkOperator && super.has(Rights.FLAGS.OPERATOR)) ||
+ super.has(permission)
+ );
}
hasThrow(permission: RightResolvable) {
if (this.has(permission)) return true;
// @ts-ignore
- throw new HTTPError(`You are missing the following rights ${permission}`, 403);
+ throw new HTTPError(
+ `You are missing the following rights ${permission}`,
+ 403,
+ );
}
-
}
-const ALL_RIGHTS = Object.values(Rights.FLAGS).reduce((total, val) => total | val, BigInt(0));
+const ALL_RIGHTS = Object.values(Rights.FLAGS).reduce(
+ (total, val) => total | val,
+ BigInt(0),
+);
-export async function getRights( user_id: string
+export async function getRights(
+ user_id: string,
/**, opts: {
in_behalf?: (keyof User)[];
- } = {} **/) {
+ } = {} **/
+) {
let user = await User.findOneOrFail({ where: { id: user_id } });
return new Rights(user.rights);
-}
+}
diff --git a/src/util/util/Snowflake.ts b/src/util/util/Snowflake.ts
index 134d526e..69effb2e 100644
--- a/src/util/util/Snowflake.ts
+++ b/src/util/util/Snowflake.ts
@@ -17,7 +17,9 @@ export class Snowflake {
static workerId = BigInt((cluster.worker?.id || 0) % 31); // max 31
constructor() {
- throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
+ throw new Error(
+ `The ${this.constructor.name} class may not be instantiated.`,
+ );
}
/**
@@ -83,14 +85,15 @@ export class Snowflake {
return dec;
}
- static generateWorkerProcess() { // worker process - returns a number
+ static generateWorkerProcess() {
+ // worker process - returns a number
var time = BigInt(Date.now() - Snowflake.EPOCH) << BigInt(22);
var worker = Snowflake.workerId << 17n;
var process = Snowflake.processId << 12n;
var increment = Snowflake.INCREMENT++;
return BigInt(time | worker | process | increment);
}
-
+
static generate() {
return Snowflake.generateWorkerProcess().toString();
}
@@ -111,7 +114,9 @@ export class Snowflake {
* @returns {DeconstructedSnowflake} Deconstructed snowflake
*/
static deconstruct(snowflake) {
- const BINARY = Snowflake.idToBinary(snowflake).toString(2).padStart(64, "0");
+ const BINARY = Snowflake.idToBinary(snowflake)
+ .toString(2)
+ .padStart(64, "0");
const res = {
timestamp: parseInt(BINARY.substring(0, 42), 2) + Snowflake.EPOCH,
workerID: parseInt(BINARY.substring(42, 47), 2),
diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
index 5ba3e1ec..19e64f47 100644
--- a/src/util/util/Token.ts
+++ b/src/util/util/Token.ts
@@ -17,11 +17,14 @@ export function checkToken(token: string, jwtSecret: string): Promise<any> {
const user = await User.findOne({
where: { id: decoded.id },
- select: ["data", "bot", "disabled", "deleted", "rights"]
+ select: ["data", "bot", "disabled", "deleted", "rights"],
});
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
- if (decoded.iat * 1000 < new Date(user.data.valid_tokens_since).setSeconds(0, 0))
+ if (
+ decoded.iat * 1000 <
+ new Date(user.data.valid_tokens_since).setSeconds(0, 0)
+ )
return rej("Invalid Token");
if (user.disabled) return rej("User disabled");
if (user.deleted) return rej("User not found");
@@ -45,7 +48,7 @@ export async function generateToken(id: string) {
(err, token) => {
if (err) return rej(err);
return res(token);
- }
+ },
);
});
}
diff --git a/src/util/util/TraverseDirectory.ts b/src/util/util/TraverseDirectory.ts
index 3d0d6279..3f5b0385 100644
--- a/src/util/util/TraverseDirectory.ts
+++ b/src/util/util/TraverseDirectory.ts
@@ -1,13 +1,14 @@
import { Server, traverseDirectory } from "lambert-server";
//if we're using ts-node, use ts files instead of js
-const extension = Symbol.for("ts-node.register.instance") in process ? "ts" : "js"
+const extension =
+ Symbol.for("ts-node.register.instance") in process ? "ts" : "js";
-const DEFAULT_FILTER = new RegExp("^([^\.].*)(?<!\.d)\.(" + extension + ")$");
+const DEFAULT_FILTER = new RegExp("^([^.].*)(?<!.d).(" + extension + ")$");
export function registerRoutes(server: Server, root: string) {
return traverseDirectory(
{ dirname: root, recursive: true, filter: DEFAULT_FILTER },
- server.registerRoute.bind(server, root)
+ server.registerRoute.bind(server, root),
);
}
diff --git a/src/util/util/cdn.ts b/src/util/util/cdn.ts
index 812a4e1d..6b2c8424 100644
--- a/src/util/util/cdn.ts
+++ b/src/util/util/cdn.ts
@@ -4,7 +4,10 @@ import fetch from "node-fetch";
import { Attachment } from "../entities";
import { Config } from "./Config";
-export async function uploadFile(path: string, file?: Express.Multer.File): Promise<Attachment> {
+export async function uploadFile(
+ path: string,
+ file?: Express.Multer.File,
+): Promise<Attachment> {
if (!file?.buffer) throw new HTTPError("Missing file in body");
const form = new FormData();
@@ -13,28 +16,38 @@ export async function uploadFile(path: string, file?: Express.Multer.File): Prom
filename: file.originalname,
});
- const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
- headers: {
- signature: Config.get().security.requestSignature,
- ...form.getHeaders(),
+ const response = await fetch(
+ `${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`,
+ {
+ headers: {
+ signature: Config.get().security.requestSignature,
+ ...form.getHeaders(),
+ },
+ method: "POST",
+ body: form,
},
- method: "POST",
- body: form,
- });
- const result = await response.json() as Attachment;
+ );
+ const result = (await response.json()) as Attachment;
if (response.status !== 200) throw result;
return result;
}
-export async function handleFile(path: string, body?: string): Promise<string | undefined> {
+export async function handleFile(
+ path: string,
+ body?: string,
+): Promise<string | undefined> {
if (!body || !body.startsWith("data:")) return undefined;
try {
const mimetype = body.split(":")[1].split(";")[0];
const buffer = Buffer.from(body.split(",")[1], "base64");
// @ts-ignore
- const { id } = await uploadFile(path, { buffer, mimetype, originalname: "banner" });
+ const { id } = await uploadFile(path, {
+ buffer,
+ mimetype,
+ originalname: "banner",
+ });
return id;
} catch (error) {
console.error(error);
@@ -43,12 +56,15 @@ export async function handleFile(path: string, body?: string): Promise<string |
}
export async function deleteFile(path: string) {
- const response = await fetch(`${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`, {
- headers: {
- signature: Config.get().security.requestSignature,
+ const response = await fetch(
+ `${Config.get().cdn.endpointPrivate || "http://localhost:3003"}${path}`,
+ {
+ headers: {
+ signature: Config.get().security.requestSignature,
+ },
+ method: "DELETE",
},
- method: "DELETE",
- });
+ );
const result = await response.json();
if (response.status !== 200) throw result;
diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index b2bd6489..aa38e472 100644
--- a/src/util/util/index.ts
+++ b/src/util/util/index.ts
@@ -20,4 +20,4 @@ export * from "./String";
export * from "./Array";
export * from "./TraverseDirectory";
export * from "./InvisibleCharacters";
-export * from "./BannedWords";
\ No newline at end of file
+export * from "./BannedWords";
|