Skip to content

Commit

Permalink
refactor channel positions in guild
Browse files Browse the repository at this point in the history
  • Loading branch information
MaddyUnderStars committed Oct 4, 2023
1 parent 551d2bf commit 7795f1b
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 71 deletions.
84 changes: 56 additions & 28 deletions src/api/routes/guilds/#guild_id/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import {
ChannelModifySchema,
ChannelReorderSchema,
ChannelUpdateEvent,
Guild,
emitEvent,
} from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
const router = Router();

router.get(
Expand Down Expand Up @@ -96,44 +96,72 @@ router.patch(
const { guild_id } = req.params;
const body = req.body as ChannelReorderSchema;

await Promise.all([
body.map(async (x) => {
if (x.position == null && !x.parent_id)
throw new HTTPError(
`You need to at least specify position or parent_id`,
400,
);
const guild = await Guild.findOneOrFail({
where: { id: guild_id },
select: { channelOrdering: true },
});

// The channels not listed for this query
const notMentioned = guild.channelOrdering.filter(
(x) => !body.find((c) => c.id == x),
);

const opts: Partial<Channel> = {};
if (x.position != null) opts.position = x.position;

if (x.parent_id) {
opts.parent_id = x.parent_id;
const parent_channel = await Channel.findOneOrFail({
where: { id: x.parent_id, guild_id },
select: ["permission_overwrites"],
});
if (x.lock_permissions) {
opts.permission_overwrites =
parent_channel.permission_overwrites;
}
}

await Channel.update({ guild_id, id: x.id }, opts);
const withParents = body.filter((x) => x.parent_id != undefined);
const withPositions = body.filter((x) => x.position != undefined);

await Promise.all(
withPositions.map(async (opt) => {
const channel = await Channel.findOneOrFail({
where: { guild_id, id: x.id },
where: { id: opt.id },
});

channel.position = opt.position as number;
notMentioned.splice(opt.position as number, 0, channel.id);

await emitEvent({
event: "CHANNEL_UPDATE",
data: channel,
channel_id: x.id,
channel_id: channel.id,
guild_id,
} as ChannelUpdateEvent);
}),
]);
);

// have to do the parents after the positions
await Promise.all(
withParents.map(async (opt) => {
const [channel, parent] = await Promise.all([
Channel.findOneOrFail({
where: { id: opt.id },
}),
Channel.findOneOrFail({
where: { id: opt.parent_id as string },
select: { permission_overwrites: true },
}),
]);

if (opt.lock_permissions)
await Channel.update(
{ id: channel.id },
{ permission_overwrites: parent.permission_overwrites },
);

const parentPos = notMentioned.indexOf(parent.id);
notMentioned.splice(parentPos + 1, 0, channel.id);
channel.position = (parentPos + 1) as number;

await emitEvent({
event: "CHANNEL_UPDATE",
data: channel,
channel_id: channel.id,
guild_id,
} as ChannelUpdateEvent);
}),
);

await Guild.update({ id: guild_id }, { channelOrdering: notMentioned });

res.sendStatus(204);
return res.sendStatus(204);
},
);

Expand Down
16 changes: 4 additions & 12 deletions src/api/routes/guilds/#guild_id/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,6 @@ router.patch(
guild.assign(body);

if (body.public_updates_channel_id == "1") {
// move all channels up 1
await Channel.createQueryBuilder("channels")
.where({ guild: { id: guild_id } })
.update({ position: () => "position + 1" })
.execute();

// create an updates channel for them
const channel = await Channel.createChannel(
{
Expand All @@ -188,6 +182,8 @@ router.patch(
{ skipPermissionCheck: true },
);

await Guild.insertChannelInOrder(guild.id, channel.id, 0, guild);

guild.public_updates_channel_id = channel.id;
} else if (body.public_updates_channel_id != undefined) {
// ensure channel exists in this guild
Expand All @@ -198,12 +194,6 @@ router.patch(
}

if (body.rules_channel_id == "1") {
// move all channels up 1
await Channel.createQueryBuilder("channels")
.where({ guild: { id: guild_id } })
.update({ position: () => "position + 1" })
.execute();

// create a rules for them
const channel = await Channel.createChannel(
{
Expand All @@ -225,6 +215,8 @@ router.patch(
{ skipPermissionCheck: true },
);

await Guild.insertChannelInOrder(guild.id, channel.id, 0, guild);

guild.rules_channel_id = channel.id;
} else if (body.rules_channel_id != undefined) {
// ensure channel exists in this guild
Expand Down
7 changes: 1 addition & 6 deletions src/api/routes/guilds/#guild_id/widget.json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,7 @@ router.get(
// Fetch voice channels, and the @everyone permissions object
const channels: { id: string; name: string; position: number }[] = [];

(
await Channel.find({
where: { guild_id: guild_id, type: 2 },
order: { position: "ASC" },
})
).filter((doc) => {
(await Channel.getOrderedChannels(guild.id, guild)).filter((doc) => {
// Only return channels where @everyone has the CONNECT permission
if (
doc.permission_overwrites === undefined ||
Expand Down
40 changes: 27 additions & 13 deletions src/gateway/opcodes/Identify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
UserSettings,
checkToken,
emitEvent,
getDatabase,
} from "@spacebar/util";
import { check } from "./instanceOf";

Expand Down Expand Up @@ -167,7 +168,12 @@ export async function onIdentify(this: WebSocket, data: Payload) {
// guild channels, emoji, roles, stickers
// but we do want almost everything from guild.
// How do you do that without just enumerating the guild props?
guild: true,
guild: Object.fromEntries(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
getDatabase()!
.getMetadata(Guild)
.columns.map((x) => [x.propertyName, true]),
),
},
relations: [
"guild",
Expand Down Expand Up @@ -253,18 +259,26 @@ export async function onIdentify(this: WebSocket, data: Payload) {
const guilds: GuildOrUnavailable[] = members.map((member) => {
// filter guild channels we don't have permission to view
// TODO: check if this causes issues when the user is granted other roles?
member.guild.channels = member.guild.channels.filter((channel) => {
const perms = Permissions.finalPermission({
user: {
id: member.id,
roles: member.roles.map((x) => x.id),
},
guild: member.guild,
channel,
});

return perms.has("VIEW_CHANNEL");
});
member.guild.channels = member.guild.channels
.filter((channel) => {
const perms = Permissions.finalPermission({
user: {
id: member.id,
roles: member.roles.map((x) => x.id),
},
guild: member.guild,
channel,
});

return perms.has("VIEW_CHANNEL");
})
.map((channel) => {
channel.position = member.guild.channelOrdering.indexOf(
channel.id,
);
return channel;
})
.sort((a, b) => a.position - b.position);

if (user.bot) {
pending_guilds.push(member.guild);
Expand Down
62 changes: 52 additions & 10 deletions src/util/entities/Channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,6 @@ export class Channel extends BaseClass {
@Column({ nullable: true })
default_auto_archive_duration?: number;

@Column({ nullable: true })
position?: number;

@Column({ type: "simple-json", nullable: true })
permission_overwrites?: ChannelPermissionOverwrite[];

Expand Down Expand Up @@ -193,6 +190,9 @@ export class Channel extends BaseClass {
@Column()
default_thread_rate_limit_per_user: number = 0;

/** Must be calculated Channel.calculatePosition */
position: number;

// TODO: DM channel
static async createChannel(
channel: Partial<Channel>,
Expand All @@ -211,10 +211,16 @@ export class Channel extends BaseClass {
permissions.hasThrow("MANAGE_CHANNELS");
}

const guild = await Guild.findOneOrFail({
where: { id: channel.guild_id },
select: {
features: !opts?.skipNameChecks,
channelOrdering: true,
id: true,
},
});

if (!opts?.skipNameChecks) {
const guild = await Guild.findOneOrFail({
where: { id: channel.guild_id },
});
if (
!guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") &&
channel.name
Expand Down Expand Up @@ -293,14 +299,15 @@ export class Channel extends BaseClass {
if (!channel.permission_overwrites) channel.permission_overwrites = [];
// TODO: eagerly auto generate position of all guild channels

const position =
(channel.type === ChannelType.UNHANDLED ? 0 : channel.position) ||
0;

channel = {
...channel,
...(!opts?.keepId && { id: Snowflake.generate() }),
created_at: new Date(),
position:
(channel.type === ChannelType.UNHANDLED
? 0
: channel.position) || 0,
position,
};

const ret = Channel.create(channel);
Expand All @@ -314,6 +321,7 @@ export class Channel extends BaseClass {
guild_id: channel.guild_id,
} as ChannelCreateEvent)
: Promise.resolve(),
Guild.insertChannelInOrder(guild.id, ret.id, position, guild),
]);

return ret;
Expand Down Expand Up @@ -456,6 +464,40 @@ export class Channel extends BaseClass {
await Channel.delete({ id: channel.id });
}

static async calculatePosition(
channel_id: string,
guild_id: string,
guild?: Guild,
) {
if (!guild)
guild = await Guild.findOneOrFail({
where: { id: guild_id },
select: { channelOrdering: true },
});

return guild.channelOrdering.findIndex((id) => channel_id == id);
}

static async getOrderedChannels(guild_id: string, guild?: Guild) {
if (!guild)
guild = await Guild.findOneOrFail({
where: { id: guild_id },
select: { channelOrdering: true },
});

const channels = await Promise.all(
guild.channelOrdering.map((id) =>
Channel.findOneOrFail({ where: { id } }),
),
);

return channels.reduce((r, v) => {
v.position = (guild as Guild).channelOrdering.indexOf(v.id);
r[v.position] = v;
return r;
}, [] as Array<Channel>);
}

isDm() {
return (
this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM
Expand Down
Loading

0 comments on commit 7795f1b

Please sign in to comment.