summary refs log tree commit diff
path: root/gateway/src/opcodes/LazyRequest.ts
blob: b1d553b9d892def59bdb45a27c7568de6e07451c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// @ts-nocheck WIP
import {
	db,
	getPermission,
	MemberModel,
	MongooseCache,
	PublicUserProjection,
	RoleModel,
	toObject,
} from "@fosscord/server-util";
import { LazyRequest } from "../schema/LazyRequest";
import { OPCODES, Payload } from "../util/Constants";
import { Send } from "../util/Send";
import WebSocket from "../util/WebSocket";
import { check } from "./instanceOf";

// TODO: check permission and only show roles/members that have access to this channel
// TODO: config: if want to list all members (even those who are offline) sorted by role, or just those who are online

export async function onLazyRequest(this: WebSocket, { d }: Payload) {
	// TODO: check data
	check.call(this, LazyRequest, d);
	const { guild_id, typing, channels, activities } = d as LazyRequest;

	const permissions = await getPermission(this.user_id, guild_id);
	permissions.hasThrow("VIEW_CHANNEL");

	// MongoDB query to retrieve all hoisted roles and join them with the members and users collection
	const roles = toObject(
		await db
			.collection("roles")
			.aggregate([
				{
					$match: {
						guild_id,
						// hoist: true // TODO: also match @everyone role
					},
				},
				{ $sort: { position: 1 } },
				{
					$lookup: {
						from: "members",
						let: { id: "$id" },
						pipeline: [
							{ $match: { $expr: { $in: ["$$id", "$roles"] } } },
							{ $limit: 100 },
							{
								$lookup: {
									from: "users",
									let: { user_id: "$id" },
									pipeline: [
										{ $match: { $expr: { $eq: ["$id", "$$user_id"] } } },
										{ $project: PublicUserProjection },
									],
									as: "user",
								},
							},
							{
								$unwind: "$user",
							},
						],
						as: "members",
					},
				},
			])
			.toArray()
	);

	const groups = roles.map((x) => ({ id: x.id === guild_id ? "online" : x.id, count: x.members.length }));
	const member_count = roles.reduce((a, b) => b.members.length + a, 0);
	const items = [];

	for (const role of roles) {
		items.push({
			group: {
				count: role.members.length,
				id: role.id === guild_id ? "online" : role.name,
			},
		});
		for (const member of role.members) {
			member.roles.remove(guild_id);
			items.push({ member });
		}
	}

	return Send(this, {
		op: OPCODES.Dispatch,
		s: this.sequence++,
		t: "GUILD_MEMBER_LIST_UPDATE",
		d: {
			ops: [
				{
					range: [0, 99],
					op: "SYNC",
					items,
				},
			],
			online_count: member_count, // TODO count online count
			member_count,
			id: "everyone",
			guild_id,
			groups,
		},
	});
}