Merge pull request #1159 from DEVTomatoCake/feat/request-guild-members

This commit is contained in:
Madeline 2024-08-14 14:03:56 +10:00 committed by GitHub
commit 4b02fa6ade
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 5028 additions and 43 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -50,7 +50,7 @@ export async function Close(this: WebSocket, code: number, reason: Buffer) {
} as SessionsReplace); } as SessionsReplace);
const session = sessions.first() || { const session = sessions.first() || {
activities: [], activities: [],
client_info: {}, client_status: {},
status: "offline", status: "offline",
}; };
@ -68,7 +68,7 @@ export async function Close(this: WebSocket, code: number, reason: Buffer) {
data: { data: {
user: userOrId, user: userOrId,
activities: session.activities, activities: session.activities,
client_status: session?.client_info, client_status: session?.client_status,
status: session.status, status: session.status,
}, },
} as PresenceUpdateEvent); } as PresenceUpdateEvent);

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -122,8 +122,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
session_id: this.session_id, session_id: this.session_id,
status: identify.presence?.status || "online", status: identify.presence?.status || "online",
client_info: { client_info: {
client: identify.properties?.$device, client: identify.properties?.device || identify.properties?.$device,
os: identify.properties?.os, os: identify.properties?.os || identify.properties?.$os,
version: 0, version: 0,
}, },
activities: identify.presence?.activities, // TODO: validation activities: identify.presence?.activities, // TODO: validation
@ -372,7 +372,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
data: { data: {
user: user.toPublicUser(), user: user.toPublicUser(),
activities: session.activities, activities: session.activities,
client_status: session.client_info, client_status: session.client_status,
status: session.status, status: session.status,
}, },
} as PresenceUpdateEvent), } as PresenceUpdateEvent),

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -248,7 +248,7 @@ export async function onLazyRequest(this: WebSocket, { d }: Payload) {
d: { d: {
user: user, user: user,
activities: session?.activities || [], activities: session?.activities || [],
client_status: session?.client_info, client_status: session?.client_status,
status: session?.status || "offline", status: session?.status || "offline",
} as Presence, } as Presence,
}); });

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -35,14 +35,19 @@ export async function onPresenceUpdate(this: WebSocket, { d }: Payload) {
{ status: presence.status, activities: presence.activities }, { status: presence.status, activities: presence.activities },
); );
const session = await Session.findOneOrFail({
select: ["client_status"],
where: { session_id: this.session_id },
});
await emitEvent({ await emitEvent({
event: "PRESENCE_UPDATE", event: "PRESENCE_UPDATE",
user_id: this.user_id, user_id: this.user_id,
data: { data: {
user: await User.getPublicUser(this.user_id), user: await User.getPublicUser(this.user_id),
activities: presence.activities,
client_status: {}, // TODO:
status: presence.status, status: presence.status,
activities: presence.activities,
client_status: session.client_status,
}, },
} as PresenceUpdateEvent); } as PresenceUpdateEvent);
} }

View File

@ -1,23 +1,124 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { WebSocket } from "@spacebar/gateway"; import {
getPermission,
GuildMembersChunkEvent,
Member,
Presence,
RequestGuildMembersSchema,
Session,
} from "@spacebar/util";
import { WebSocket, Payload, OPCODES, Send } from "@spacebar/gateway";
import { check } from "./instanceOf";
import { FindManyOptions, In, Like } from "typeorm";
export function onRequestGuildMembers(this: WebSocket) { export async function onRequestGuildMembers(this: WebSocket, { d }: Payload) {
// return this.close(CLOSECODES.Unknown_error); // TODO: check data
check.call(this, RequestGuildMembersSchema, d);
const { guild_id, query, presences, nonce } =
d as RequestGuildMembersSchema;
let { limit, user_ids } = d as RequestGuildMembersSchema;
if ("query" in d && (!limit || Number.isNaN(limit)))
throw new Error('"query" requires "limit" to be set');
if ("query" in d && user_ids)
throw new Error('"query" and "user_ids" are mutually exclusive');
if (user_ids && !Array.isArray(user_ids)) user_ids = [user_ids];
user_ids = user_ids as string[] | undefined;
// TODO: Configurable limit?
if ((query || (user_ids && user_ids.length > 0)) && (!limit || limit > 100))
limit = 100;
const permissions = await getPermission(this.user_id, guild_id);
permissions.hasThrow("VIEW_CHANNEL");
const whereQuery: FindManyOptions["where"] = {};
if (query) {
whereQuery.user = {
username: Like(query + "%"),
};
} else if (user_ids && user_ids.length > 0) {
whereQuery.id = In(user_ids);
}
const memberFind: FindManyOptions = {
where: {
...whereQuery,
guild_id,
},
relations: ["users", "roles"],
};
if (limit) memberFind.take = Math.abs(Number(limit || 100));
const members = await Member.find(memberFind);
const baseData = {
guild_id,
nonce,
};
const chunkCount = Math.ceil(members.length / 1000);
let notFound: string[] = [];
if (user_ids && user_ids.length > 0)
notFound = user_ids.filter(
(id) => !members.some((member) => member.id == id),
);
const chunks: GuildMembersChunkEvent["data"][] = [];
while (members.length > 0) {
const chunk: Member[] = members.splice(0, 1000);
const presenceList: Presence[] = [];
if (presences) {
for await (const member of chunk) {
const session = await Session.findOne({
where: { user_id: member.id },
});
if (session)
presenceList.push({
user: member.user.toPublicUser(),
status: session.status,
activities: session.activities,
client_status: session.client_status,
});
}
}
chunks.push({
...baseData,
members: chunk.map((member) => member.toPublicMember()),
presences: presences ? presenceList : undefined,
chunk_index: chunks.length,
chunk_count: chunkCount,
});
}
if (notFound.length > 0) chunks[0].not_found = notFound;
chunks.forEach((chunk) => {
Send(this, {
op: OPCODES.Dispatch,
s: this.sequence++,
t: "GUILD_MEMBERS_CHUNK",
d: chunk,
});
});
} }

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -19,7 +19,7 @@
import { User } from "./User"; import { User } from "./User";
import { BaseClass } from "./BaseClass"; import { BaseClass } from "./BaseClass";
import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm";
import { Status } from "../interfaces/Status"; import { ClientStatus, Status } from "../interfaces/Status";
import { Activity } from "../interfaces/Activity"; import { Activity } from "../interfaces/Activity";
//TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them
@ -43,7 +43,6 @@ export class Session extends BaseClass {
@Column({ type: "simple-json", nullable: true }) @Column({ type: "simple-json", nullable: true })
activities: Activity[]; activities: Activity[];
// TODO client_status
@Column({ type: "simple-json", select: false }) @Column({ type: "simple-json", select: false })
client_info: { client_info: {
client: string; client: string;
@ -51,6 +50,9 @@ export class Session extends BaseClass {
version: number; version: number;
}; };
@Column({ type: "simple-json" })
client_status: ClientStatus;
@Column({ nullable: false, type: "varchar" }) @Column({ nullable: false, type: "varchar" })
status: Status; //TODO enum status: Status; //TODO enum
} }

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -280,8 +280,8 @@ export interface GuildMembersChunkEvent extends Event {
members: PublicMember[]; members: PublicMember[];
chunk_index: number; chunk_index: number;
chunk_count: number; chunk_count: number;
not_found: string[]; not_found?: string[];
presences: Presence[]; presences?: Presence[];
nonce?: string; nonce?: string;
}; };
} }

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -21,5 +21,6 @@ export type Status = "idle" | "dnd" | "online" | "offline" | "invisible";
export interface ClientStatus { export interface ClientStatus {
desktop?: string; // e.g. Windows/Linux/Mac desktop?: string; // e.g. Windows/Linux/Mac
mobile?: string; // e.g. iOS/Android mobile?: string; // e.g. iOS/Android
web?: string; // e.g. browser, bot account web?: string; // e.g. browser, bot account, unknown
embedded?: string; // e.g. embedded
} }

View File

@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class client_status1723347738541 implements MigrationInterface {
name = "client_status1723347738541";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
"ALTER TABLE `sessions` ADD `client_status` text NULL AFTER `client_info`",
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
"ALTER TABLE `sessions` DROP COLUMN `client_status`",
);
}
}

View File

@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class client_status1723347738541 implements MigrationInterface {
name = "client_status1723347738541";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
"ALTER TABLE `sessions` ADD `client_status` text NULL AFTER `client_info`",
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
"ALTER TABLE `sessions` DROP COLUMN `client_status`",
);
}
}

View File

@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class client_status1723347738541 implements MigrationInterface {
name = "client_status1723347738541";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
"ALTER TABLE sessions ADD client_status text NULL",
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
"ALTER TABLE sessions DROP COLUMN client_status",
);
}
}

View File

@ -0,0 +1,35 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export interface RequestGuildMembersSchema {
guild_id: string;
query?: string;
limit?: number;
presences?: boolean;
user_ids?: string | string[];
nonce?: string;
}
export const RequestGuildMembersSchema = {
guild_id: String,
$query: String,
$limit: Number,
$presences: Boolean,
$user_ids: [] as string | string[],
$nonce: String,
};

View File

@ -1,17 +1,17 @@
/* /*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@ -58,6 +58,7 @@ export * from "./PurgeSchema";
export * from "./RegisterSchema"; export * from "./RegisterSchema";
export * from "./RelationshipPostSchema"; export * from "./RelationshipPostSchema";
export * from "./RelationshipPutSchema"; export * from "./RelationshipPutSchema";
export * from "./RequestGuildMembersSchema";
export * from "./RoleModifySchema"; export * from "./RoleModifySchema";
export * from "./RolePositionUpdateSchema"; export * from "./RolePositionUpdateSchema";
export * from "./SelectProtocolSchema"; export * from "./SelectProtocolSchema";