Added ILLEGAL_CHANNEL_NAMES
and NULL_CHANNEL_NAMES
guild feature flags
This commit is contained in:
parent
f9ff5b35f3
commit
35c7489f72
@ -1,332 +1,350 @@
|
|||||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
|
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
|
||||||
import { BaseClass } from "./BaseClass";
|
import { BaseClass } from "./BaseClass";
|
||||||
import { Guild } from "./Guild";
|
import { Guild } from "./Guild";
|
||||||
import { PublicUserProjection, User } from "./User";
|
import { PublicUserProjection, User } from "./User";
|
||||||
import { HTTPError } from "lambert-server";
|
import { HTTPError } from "lambert-server";
|
||||||
import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial } from "../util";
|
import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters } from "../util";
|
||||||
import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
|
import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces";
|
||||||
import { Recipient } from "./Recipient";
|
import { Recipient } from "./Recipient";
|
||||||
import { Message } from "./Message";
|
import { Message } from "./Message";
|
||||||
import { ReadState } from "./ReadState";
|
import { ReadState } from "./ReadState";
|
||||||
import { Invite } from "./Invite";
|
import { Invite } from "./Invite";
|
||||||
import { VoiceState } from "./VoiceState";
|
import { VoiceState } from "./VoiceState";
|
||||||
import { Webhook } from "./Webhook";
|
import { Webhook } from "./Webhook";
|
||||||
import { DmChannelDTO } from "../dtos";
|
import { DmChannelDTO } from "../dtos";
|
||||||
|
|
||||||
export enum ChannelType {
|
export enum ChannelType {
|
||||||
GUILD_TEXT = 0, // a text channel within a server
|
GUILD_TEXT = 0, // a text channel within a server
|
||||||
DM = 1, // a direct message between users
|
DM = 1, // a direct message between users
|
||||||
GUILD_VOICE = 2, // a voice channel within a server
|
GUILD_VOICE = 2, // a voice channel within a server
|
||||||
GROUP_DM = 3, // a direct message between multiple users
|
GROUP_DM = 3, // a direct message between multiple users
|
||||||
GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels
|
GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels
|
||||||
GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server
|
GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server
|
||||||
GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord
|
GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord
|
||||||
// TODO: what are channel types between 7-9?
|
// TODO: what are channel types between 7-9?
|
||||||
GUILD_NEWS_THREAD = 10, // a temporary sub-channel within a GUILD_NEWS 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_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_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
|
GUILD_STAGE_VOICE = 13, // a voice channel for hosting events with an audience
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity("channels")
|
@Entity("channels")
|
||||||
export class Channel extends BaseClass {
|
export class Channel extends BaseClass {
|
||||||
@Column()
|
@Column()
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
||||||
@Column({ type: "text", nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
icon?: string | null;
|
icon?: string | null;
|
||||||
|
|
||||||
@Column({ type: "int" })
|
@Column({ type: "int" })
|
||||||
type: ChannelType;
|
type: ChannelType;
|
||||||
|
|
||||||
@OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, {
|
@OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
orphanedRowAction: "delete",
|
orphanedRowAction: "delete",
|
||||||
})
|
})
|
||||||
recipients?: Recipient[];
|
recipients?: Recipient[];
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
last_message_id: string;
|
last_message_id: string;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
@RelationId((channel: Channel) => channel.guild)
|
@RelationId((channel: Channel) => channel.guild)
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
|
|
||||||
@JoinColumn({ name: "guild_id" })
|
@JoinColumn({ name: "guild_id" })
|
||||||
@ManyToOne(() => Guild, {
|
@ManyToOne(() => Guild, {
|
||||||
onDelete: "CASCADE",
|
onDelete: "CASCADE",
|
||||||
})
|
})
|
||||||
guild: Guild;
|
guild: Guild;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
@RelationId((channel: Channel) => channel.parent)
|
@RelationId((channel: Channel) => channel.parent)
|
||||||
parent_id: string;
|
parent_id: string;
|
||||||
|
|
||||||
@JoinColumn({ name: "parent_id" })
|
@JoinColumn({ name: "parent_id" })
|
||||||
@ManyToOne(() => Channel)
|
@ManyToOne(() => Channel)
|
||||||
parent?: Channel;
|
parent?: Channel;
|
||||||
|
|
||||||
// only for group dms
|
// only for group dms
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
@RelationId((channel: Channel) => channel.owner)
|
@RelationId((channel: Channel) => channel.owner)
|
||||||
owner_id: string;
|
owner_id: string;
|
||||||
|
|
||||||
@JoinColumn({ name: "owner_id" })
|
@JoinColumn({ name: "owner_id" })
|
||||||
@ManyToOne(() => User)
|
@ManyToOne(() => User)
|
||||||
owner: User;
|
owner: User;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
last_pin_timestamp?: number;
|
last_pin_timestamp?: number;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
default_auto_archive_duration?: number;
|
default_auto_archive_duration?: number;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
position?: number;
|
position?: number;
|
||||||
|
|
||||||
@Column({ type: "simple-json", nullable: true })
|
@Column({ type: "simple-json", nullable: true })
|
||||||
permission_overwrites?: ChannelPermissionOverwrite[];
|
permission_overwrites?: ChannelPermissionOverwrite[];
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
video_quality_mode?: number;
|
video_quality_mode?: number;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
bitrate?: number;
|
bitrate?: number;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
user_limit?: number;
|
user_limit?: number;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
nsfw?: boolean;
|
nsfw?: boolean;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
rate_limit_per_user?: number;
|
rate_limit_per_user?: number;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
topic?: string;
|
topic?: string;
|
||||||
|
|
||||||
@OneToMany(() => Invite, (invite: Invite) => invite.channel, {
|
@OneToMany(() => Invite, (invite: Invite) => invite.channel, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
orphanedRowAction: "delete",
|
orphanedRowAction: "delete",
|
||||||
})
|
})
|
||||||
invites?: Invite[];
|
invites?: Invite[];
|
||||||
|
|
||||||
@OneToMany(() => Message, (message: Message) => message.channel, {
|
@OneToMany(() => Message, (message: Message) => message.channel, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
orphanedRowAction: "delete",
|
orphanedRowAction: "delete",
|
||||||
})
|
})
|
||||||
messages?: Message[];
|
messages?: Message[];
|
||||||
|
|
||||||
@OneToMany(() => VoiceState, (voice_state: VoiceState) => voice_state.channel, {
|
@OneToMany(() => VoiceState, (voice_state: VoiceState) => voice_state.channel, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
orphanedRowAction: "delete",
|
orphanedRowAction: "delete",
|
||||||
})
|
})
|
||||||
voice_states?: VoiceState[];
|
voice_states?: VoiceState[];
|
||||||
|
|
||||||
@OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, {
|
@OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
orphanedRowAction: "delete",
|
orphanedRowAction: "delete",
|
||||||
})
|
})
|
||||||
read_states?: ReadState[];
|
read_states?: ReadState[];
|
||||||
|
|
||||||
@OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, {
|
@OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
orphanedRowAction: "delete",
|
orphanedRowAction: "delete",
|
||||||
})
|
})
|
||||||
webhooks?: Webhook[];
|
webhooks?: Webhook[];
|
||||||
|
|
||||||
// TODO: DM channel
|
// TODO: DM channel
|
||||||
static async createChannel(
|
static async createChannel(
|
||||||
channel: Partial<Channel>,
|
channel: Partial<Channel>,
|
||||||
user_id: string = "0",
|
user_id: string = "0",
|
||||||
opts?: {
|
opts?: {
|
||||||
keepId?: boolean;
|
keepId?: boolean;
|
||||||
skipExistsCheck?: boolean;
|
skipExistsCheck?: boolean;
|
||||||
skipPermissionCheck?: boolean;
|
skipPermissionCheck?: boolean;
|
||||||
skipEventEmit?: boolean;
|
skipEventEmit?: boolean;
|
||||||
}
|
skipNameChecks?: boolean;
|
||||||
) {
|
}
|
||||||
if (!opts?.skipPermissionCheck) {
|
) {
|
||||||
// Always check if user has permission first
|
if (!opts?.skipPermissionCheck) {
|
||||||
const permissions = await getPermission(user_id, channel.guild_id);
|
// Always check if user has permission first
|
||||||
permissions.hasThrow("MANAGE_CHANNELS");
|
const permissions = await getPermission(user_id, channel.guild_id);
|
||||||
}
|
permissions.hasThrow("MANAGE_CHANNELS");
|
||||||
|
}
|
||||||
switch (channel.type) {
|
|
||||||
case ChannelType.GUILD_TEXT:
|
if (!opts?.skipNameChecks) {
|
||||||
case ChannelType.GUILD_VOICE:
|
const guild = await Guild.findOneOrFail({ id: channel.guild_id });
|
||||||
if (channel.parent_id && !opts?.skipExistsCheck) {
|
if (!guild.features.includes("ILLEGAL_CHANNEL_NAMES") && channel.name) {
|
||||||
const exists = await Channel.findOneOrFail({ id: channel.parent_id });
|
for (var character of InvisibleCharacters)
|
||||||
if (!exists) throw new HTTPError("Parent id channel doesn't exist", 400);
|
channel.name = channel.name.split(character).join("-");
|
||||||
if (exists.guild_id !== channel.guild_id)
|
|
||||||
throw new HTTPError("The category channel needs to be in the guild");
|
channel.name = channel.name.split(/\-+/g).join("-"); //replace multiple occurances with just one
|
||||||
}
|
channel.name = channel.name.split("-").filter(Boolean).join("-"); //trim '-' character
|
||||||
break;
|
}
|
||||||
case ChannelType.GUILD_CATEGORY:
|
|
||||||
break;
|
if (!guild.features.includes("NULL_CHANNEL_NAMES")) {
|
||||||
case ChannelType.DM:
|
if (channel.name) channel.name = channel.name.trim();
|
||||||
case ChannelType.GROUP_DM:
|
|
||||||
throw new HTTPError("You can't create a dm channel in a guild");
|
if (!channel.name) throw new HTTPError("Channel name cannot be empty.");
|
||||||
// TODO: check if guild is community server
|
}
|
||||||
case ChannelType.GUILD_STORE:
|
}
|
||||||
case ChannelType.GUILD_NEWS:
|
|
||||||
default:
|
switch (channel.type) {
|
||||||
throw new HTTPError("Not yet supported");
|
case ChannelType.GUILD_TEXT:
|
||||||
}
|
case ChannelType.GUILD_VOICE:
|
||||||
|
if (channel.parent_id && !opts?.skipExistsCheck) {
|
||||||
if (!channel.permission_overwrites) channel.permission_overwrites = [];
|
const exists = await Channel.findOneOrFail({ id: channel.parent_id });
|
||||||
// TODO: auto generate position
|
if (!exists) throw new HTTPError("Parent id channel doesn't exist", 400);
|
||||||
|
if (exists.guild_id !== channel.guild_id)
|
||||||
channel = {
|
throw new HTTPError("The category channel needs to be in the guild");
|
||||||
...channel,
|
}
|
||||||
...(!opts?.keepId && { id: Snowflake.generate() }),
|
break;
|
||||||
created_at: new Date(),
|
case ChannelType.GUILD_CATEGORY:
|
||||||
position: channel.position || 0,
|
break;
|
||||||
};
|
case ChannelType.DM:
|
||||||
|
case ChannelType.GROUP_DM:
|
||||||
await Promise.all([
|
throw new HTTPError("You can't create a dm channel in a guild");
|
||||||
new Channel(channel).save(),
|
// TODO: check if guild is community server
|
||||||
!opts?.skipEventEmit
|
case ChannelType.GUILD_STORE:
|
||||||
? emitEvent({
|
case ChannelType.GUILD_NEWS:
|
||||||
event: "CHANNEL_CREATE",
|
default:
|
||||||
data: channel,
|
throw new HTTPError("Not yet supported");
|
||||||
guild_id: channel.guild_id,
|
}
|
||||||
} as ChannelCreateEvent)
|
|
||||||
: Promise.resolve(),
|
if (!channel.permission_overwrites) channel.permission_overwrites = [];
|
||||||
]);
|
// TODO: auto generate position
|
||||||
|
|
||||||
return channel;
|
channel = {
|
||||||
}
|
...channel,
|
||||||
|
...(!opts?.keepId && { id: Snowflake.generate() }),
|
||||||
static async createDMChannel(recipients: string[], creator_user_id: string, name?: string) {
|
created_at: new Date(),
|
||||||
recipients = recipients.unique().filter((x) => x !== creator_user_id);
|
position: channel.position || 0,
|
||||||
const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) });
|
};
|
||||||
|
|
||||||
// TODO: check config for max number of recipients
|
await Promise.all([
|
||||||
if (otherRecipientsUsers.length !== recipients.length) {
|
new Channel(channel).save(),
|
||||||
throw new HTTPError("Recipient/s not found");
|
!opts?.skipEventEmit
|
||||||
}
|
? emitEvent({
|
||||||
|
event: "CHANNEL_CREATE",
|
||||||
const type = recipients.length === 1 ? ChannelType.DM : ChannelType.GROUP_DM;
|
data: channel,
|
||||||
|
guild_id: channel.guild_id,
|
||||||
let channel = null;
|
} as ChannelCreateEvent)
|
||||||
|
: Promise.resolve(),
|
||||||
const channelRecipients = [...recipients, creator_user_id];
|
]);
|
||||||
|
|
||||||
const userRecipients = await Recipient.find({
|
return channel;
|
||||||
where: { user_id: creator_user_id },
|
}
|
||||||
relations: ["channel", "channel.recipients"],
|
|
||||||
});
|
static async createDMChannel(recipients: string[], creator_user_id: string, name?: string) {
|
||||||
|
recipients = recipients.unique().filter((x) => x !== creator_user_id);
|
||||||
for (let ur of userRecipients) {
|
const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) });
|
||||||
let re = ur.channel.recipients!.map((r) => r.user_id);
|
|
||||||
if (re.length === channelRecipients.length) {
|
// TODO: check config for max number of recipients
|
||||||
if (containsAll(re, channelRecipients)) {
|
if (otherRecipientsUsers.length !== recipients.length) {
|
||||||
if (channel == null) {
|
throw new HTTPError("Recipient/s not found");
|
||||||
channel = ur.channel;
|
}
|
||||||
await ur.assign({ closed: false }).save();
|
|
||||||
}
|
const type = recipients.length === 1 ? ChannelType.DM : ChannelType.GROUP_DM;
|
||||||
}
|
|
||||||
}
|
let channel = null;
|
||||||
}
|
|
||||||
|
const channelRecipients = [...recipients, creator_user_id];
|
||||||
if (channel == null) {
|
|
||||||
name = trimSpecial(name);
|
const userRecipients = await Recipient.find({
|
||||||
|
where: { user_id: creator_user_id },
|
||||||
channel = await new Channel({
|
relations: ["channel", "channel.recipients"],
|
||||||
name,
|
});
|
||||||
type,
|
|
||||||
owner_id: type === ChannelType.DM ? undefined : creator_user_id,
|
for (let ur of userRecipients) {
|
||||||
created_at: new Date(),
|
let re = ur.channel.recipients!.map((r) => r.user_id);
|
||||||
last_message_id: null,
|
if (re.length === channelRecipients.length) {
|
||||||
recipients: channelRecipients.map(
|
if (containsAll(re, channelRecipients)) {
|
||||||
(x) =>
|
if (channel == null) {
|
||||||
new Recipient({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })
|
channel = ur.channel;
|
||||||
),
|
await ur.assign({ closed: false }).save();
|
||||||
}).save();
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const channel_dto = await DmChannelDTO.from(channel);
|
}
|
||||||
|
|
||||||
if (type === ChannelType.GROUP_DM) {
|
if (channel == null) {
|
||||||
for (let recipient of channel.recipients!) {
|
name = trimSpecial(name);
|
||||||
await emitEvent({
|
|
||||||
event: "CHANNEL_CREATE",
|
channel = await new Channel({
|
||||||
data: channel_dto.excludedRecipients([recipient.user_id]),
|
name,
|
||||||
user_id: recipient.user_id,
|
type,
|
||||||
});
|
owner_id: type === ChannelType.DM ? undefined : creator_user_id,
|
||||||
}
|
created_at: new Date(),
|
||||||
} else {
|
last_message_id: null,
|
||||||
await emitEvent({ event: "CHANNEL_CREATE", data: channel_dto, user_id: creator_user_id });
|
recipients: channelRecipients.map(
|
||||||
}
|
(x) =>
|
||||||
|
new Recipient({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })
|
||||||
return channel_dto.excludedRecipients([creator_user_id]);
|
),
|
||||||
}
|
}).save();
|
||||||
|
}
|
||||||
static async removeRecipientFromChannel(channel: Channel, user_id: string) {
|
|
||||||
await Recipient.delete({ channel_id: channel.id, user_id: user_id });
|
const channel_dto = await DmChannelDTO.from(channel);
|
||||||
channel.recipients = channel.recipients?.filter((r) => r.user_id !== user_id);
|
|
||||||
|
if (type === ChannelType.GROUP_DM) {
|
||||||
if (channel.recipients?.length === 0) {
|
for (let recipient of channel.recipients!) {
|
||||||
await Channel.deleteChannel(channel);
|
await emitEvent({
|
||||||
await emitEvent({
|
event: "CHANNEL_CREATE",
|
||||||
event: "CHANNEL_DELETE",
|
data: channel_dto.excludedRecipients([recipient.user_id]),
|
||||||
data: await DmChannelDTO.from(channel, [user_id]),
|
user_id: recipient.user_id,
|
||||||
user_id: user_id,
|
});
|
||||||
});
|
}
|
||||||
return;
|
} else {
|
||||||
}
|
await emitEvent({ event: "CHANNEL_CREATE", data: channel_dto, user_id: creator_user_id });
|
||||||
|
}
|
||||||
await emitEvent({
|
|
||||||
event: "CHANNEL_DELETE",
|
return channel_dto.excludedRecipients([creator_user_id]);
|
||||||
data: await DmChannelDTO.from(channel, [user_id]),
|
}
|
||||||
user_id: user_id,
|
|
||||||
});
|
static async removeRecipientFromChannel(channel: Channel, user_id: string) {
|
||||||
|
await Recipient.delete({ channel_id: channel.id, user_id: user_id });
|
||||||
//If the owner leave we make the first recipient in the list the new owner
|
channel.recipients = channel.recipients?.filter((r) => r.user_id !== user_id);
|
||||||
if (channel.owner_id === user_id) {
|
|
||||||
channel.owner_id = channel.recipients!.find((r) => r.user_id !== user_id)!.user_id; //Is there a criteria to choose the new owner?
|
if (channel.recipients?.length === 0) {
|
||||||
await emitEvent({
|
await Channel.deleteChannel(channel);
|
||||||
event: "CHANNEL_UPDATE",
|
await emitEvent({
|
||||||
data: await DmChannelDTO.from(channel, [user_id]),
|
event: "CHANNEL_DELETE",
|
||||||
channel_id: channel.id,
|
data: await DmChannelDTO.from(channel, [user_id]),
|
||||||
});
|
user_id: user_id,
|
||||||
}
|
});
|
||||||
|
return;
|
||||||
await channel.save();
|
}
|
||||||
|
|
||||||
await emitEvent({
|
await emitEvent({
|
||||||
event: "CHANNEL_RECIPIENT_REMOVE",
|
event: "CHANNEL_DELETE",
|
||||||
data: {
|
data: await DmChannelDTO.from(channel, [user_id]),
|
||||||
channel_id: channel.id,
|
user_id: user_id,
|
||||||
user: await User.findOneOrFail({ where: { id: user_id }, select: PublicUserProjection }),
|
});
|
||||||
},
|
|
||||||
channel_id: channel.id,
|
//If the owner leave we make the first recipient in the list the new owner
|
||||||
} as ChannelRecipientRemoveEvent);
|
if (channel.owner_id === user_id) {
|
||||||
}
|
channel.owner_id = channel.recipients!.find((r) => r.user_id !== user_id)!.user_id; //Is there a criteria to choose the new owner?
|
||||||
|
await emitEvent({
|
||||||
static async deleteChannel(channel: Channel) {
|
event: "CHANNEL_UPDATE",
|
||||||
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
|
data: await DmChannelDTO.from(channel, [user_id]),
|
||||||
//TODO before deleting the channel we should check and delete other relations
|
channel_id: channel.id,
|
||||||
await Channel.delete({ id: channel.id });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isDm() {
|
await channel.save();
|
||||||
return this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM;
|
|
||||||
}
|
await emitEvent({
|
||||||
}
|
event: "CHANNEL_RECIPIENT_REMOVE",
|
||||||
|
data: {
|
||||||
export interface ChannelPermissionOverwrite {
|
channel_id: channel.id,
|
||||||
allow: string;
|
user: await User.findOneOrFail({ where: { id: user_id }, select: PublicUserProjection }),
|
||||||
deny: string;
|
},
|
||||||
id: string;
|
channel_id: channel.id,
|
||||||
type: ChannelPermissionOverwriteType;
|
} as ChannelRecipientRemoveEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ChannelPermissionOverwriteType {
|
static async deleteChannel(channel: Channel) {
|
||||||
role = 0,
|
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
|
||||||
member = 1,
|
//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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChannelPermissionOverwrite {
|
||||||
|
allow: string;
|
||||||
|
deny: string;
|
||||||
|
id: string;
|
||||||
|
type: ChannelPermissionOverwriteType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ChannelPermissionOverwriteType {
|
||||||
|
role = 0,
|
||||||
|
member = 1,
|
||||||
|
}
|
||||||
|
55
util/src/util/InvisibleCharacters.ts
Normal file
55
util/src/util/InvisibleCharacters.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
export const InvisibleCharacters = [
|
||||||
|
"\t",
|
||||||
|
" ",
|
||||||
|
"",
|
||||||
|
"͏",
|
||||||
|
"",
|
||||||
|
"ᅟ",
|
||||||
|
"ᅠ",
|
||||||
|
"឴",
|
||||||
|
"឵",
|
||||||
|
"",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
" ",
|
||||||
|
"⠀",
|
||||||
|
"ㅤ",
|
||||||
|
"",
|
||||||
|
"ᅠ",
|
||||||
|
"𝅙",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
@ -18,3 +18,4 @@ export * from "./Snowflake";
|
|||||||
export * from "./String";
|
export * from "./String";
|
||||||
export * from "./Array";
|
export * from "./Array";
|
||||||
export * from "./TraverseDirectory";
|
export * from "./TraverseDirectory";
|
||||||
|
export * from "./InvisibleCharacters";
|
Loading…
x
Reference in New Issue
Block a user