mirror of
https://github.com/spacebarchat/server.git
synced 2026-08-14 11:10:21 +00:00
HACKHACK: Migrate to typeorm v1.0.0, still work to do in actually updating all the queries properly
This commit is contained in:
Generated
BIN
Binary file not shown.
+1
-1
@@ -118,7 +118,7 @@
|
||||
"prom-client": "^15.1.3",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typeorm": "^0.3.30",
|
||||
"typeorm": "^1.0.0",
|
||||
"why-is-node-running": "^3.2.2",
|
||||
"wretch": "^3.0.8",
|
||||
"ws": "^8.21.0"
|
||||
|
||||
@@ -151,7 +151,7 @@ router.patch(
|
||||
const { channel_id } = req.params as { [key: string]: string };
|
||||
const channel = await Channel.findOneOrFail({
|
||||
where: { id: channel_id },
|
||||
relations: ["available_tags"],
|
||||
relations: { available_tags: true },
|
||||
});
|
||||
|
||||
if (channel.isThread()) {
|
||||
@@ -182,7 +182,7 @@ router.patch(
|
||||
where: {
|
||||
id: channel.parent_id as string,
|
||||
},
|
||||
relations: ["available_tags"],
|
||||
relations: { available_tags: true },
|
||||
});
|
||||
if (!parent.available_tags) throw new Error("shoot, internetal error");
|
||||
const realTags = new Map(parent.available_tags.map((tag) => [tag.id, tag]));
|
||||
|
||||
@@ -111,7 +111,7 @@ router.get(
|
||||
|
||||
const invites = await Invite.find({
|
||||
where: { guild_id, channel_id },
|
||||
relations: PublicInviteRelation,
|
||||
relations: Object.fromEntries(PublicInviteRelation.map((i) => [i, true])), //TODO: cleanup
|
||||
});
|
||||
|
||||
res.status(200).send(invites);
|
||||
|
||||
@@ -161,7 +161,7 @@ router.get(
|
||||
where: {
|
||||
id: In(reaction.user_ids),
|
||||
},
|
||||
select: PublicUserProjection,
|
||||
select: Object.fromEntries(PublicUserProjection.map((i) => [i, true])), //TODO: cleanup
|
||||
take: limit,
|
||||
})
|
||||
).map((user) => user.toPublicUser());
|
||||
|
||||
@@ -44,7 +44,7 @@ router.post(
|
||||
const body = req.body as MessageThreadCreationSchema;
|
||||
const message = await Message.findOneOrFail({
|
||||
where: { id: message_id, channel_id },
|
||||
relations: ["guild"],
|
||||
relations: { guild: true },
|
||||
});
|
||||
const channel = await Channel.findOneOrFail({
|
||||
where: { id: channel_id },
|
||||
|
||||
@@ -65,7 +65,7 @@ router.put(
|
||||
user: (
|
||||
await User.findOneOrFail({
|
||||
where: { id: user_id },
|
||||
select: PublicUserProjection,
|
||||
select: Object.fromEntries(PublicUserProjection.map((i) => [i, true])), //TODO: cleanup
|
||||
})
|
||||
).toPublicUser(),
|
||||
},
|
||||
|
||||
@@ -43,7 +43,7 @@ router.post(
|
||||
|
||||
const channel = await Channel.findOneOrFail({
|
||||
where: { id: channel_id },
|
||||
relations: ["available_tags"],
|
||||
relations: { available_tags: true },
|
||||
});
|
||||
|
||||
if (!channel.isForum()) throw new Error("is not thread only channel");
|
||||
@@ -88,7 +88,7 @@ router.put(
|
||||
|
||||
const channel = await Channel.findOneOrFail({
|
||||
where: { id: channel_id },
|
||||
relations: ["available_tags"],
|
||||
relations: { available_tags: true },
|
||||
});
|
||||
|
||||
if (!channel.isForum()) throw new Error("is not thread only channel");
|
||||
@@ -127,7 +127,7 @@ router.delete(
|
||||
|
||||
const channel = await Channel.findOneOrFail({
|
||||
where: { id: channel_id },
|
||||
relations: ["available_tags"],
|
||||
relations: { available_tags: true },
|
||||
});
|
||||
|
||||
if (!channel.isForum()) throw new Error("is not thread only channel");
|
||||
|
||||
@@ -56,7 +56,7 @@ router.post(
|
||||
|
||||
const channel = await Channel.findOneOrFail({
|
||||
where: { id: channel_id },
|
||||
relations: ["available_tags"],
|
||||
relations: { available_tags: true },
|
||||
});
|
||||
if (!body.applied_tags?.length) {
|
||||
const required = channel.flags & Number(ChannelFlags.FLAGS.REQUIRE_TAG);
|
||||
|
||||
@@ -37,7 +37,7 @@ router.get(
|
||||
|
||||
const invites = await Invite.find({
|
||||
where: { guild_id },
|
||||
relations: PublicInviteRelation,
|
||||
relations: Object.fromEntries(PublicInviteRelation.map((i) => [i, true])), // TODO cleanup
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
|
||||
@@ -60,7 +60,7 @@ router.get(
|
||||
|
||||
const members = await Member.find({
|
||||
where: { guild_id, ...query },
|
||||
select: PublicMemberProjection,
|
||||
select: Object.fromEntries(PublicMemberProjection.map((i) => [i, true])), // TODO: cleanup
|
||||
take: limit,
|
||||
order: { id: "ASC" },
|
||||
});
|
||||
|
||||
@@ -128,7 +128,7 @@ router.get(
|
||||
mentions = mentions instanceof Array ? mentions : mentions ? [mentions] : [];
|
||||
let roleids = [] as string[];
|
||||
if (mentions) {
|
||||
const ms = await Member.find({ where: { id: In(mentions), guild_id: req.params.guild_id as string }, relations: ["roles"] });
|
||||
const ms = await Member.find({ where: { id: In(mentions), guild_id: req.params.guild_id as string }, relations: { roles: true } });
|
||||
const rSet = new Set<string>();
|
||||
ms.forEach((memb) => {
|
||||
memb.roles.forEach(({ id }) => rSet.add(id));
|
||||
|
||||
@@ -86,7 +86,7 @@ router.post(
|
||||
const { guild_id } = req.params as { [key: string]: string };
|
||||
const guild = await Guild.findOneOrFail({
|
||||
where: { id: guild_id },
|
||||
select: TemplateGuildProjection,
|
||||
select: Object.fromEntries(TemplateGuildProjection.map((i) => [i, true])), //TODO: cleanup
|
||||
relations: { roles: true, channels: true },
|
||||
});
|
||||
const exists = await Template.findOne({
|
||||
@@ -142,7 +142,7 @@ router.put(
|
||||
const { code, guild_id } = req.params as { [key: string]: string };
|
||||
const guild = await Guild.findOneOrFail({
|
||||
where: { id: guild_id },
|
||||
select: TemplateGuildProjection,
|
||||
select: Object.fromEntries(TemplateGuildProjection.map((i) => [i, true])), //TODO: cleanup
|
||||
});
|
||||
|
||||
const template = await Template.create({
|
||||
|
||||
@@ -42,7 +42,7 @@ router.get(
|
||||
|
||||
const invite = await Invite.findOneOrFail({
|
||||
where: { code: invite_code },
|
||||
relations: PublicInviteRelation,
|
||||
relations: Object.fromEntries(PublicInviteRelation.map((i) => [i, true])), //TODO: clean up
|
||||
});
|
||||
|
||||
res.status(200).send(invite.toPublicJSON());
|
||||
|
||||
@@ -46,7 +46,7 @@ router.post(
|
||||
const body = req.body as InstanceUserDeleteSchema | undefined;
|
||||
const user = await User.findOneOrFail({
|
||||
where: { id: req.params.user_id as string },
|
||||
select: [...PrivateUserProjection, "data"],
|
||||
select: Object.fromEntries([...PrivateUserProjection, "data"].map((i) => [i, true])), // TODO: clean up
|
||||
});
|
||||
|
||||
if ((body?.persistInstanceBan ?? true) && !(await InstanceBan.findOne({ where: { user_id: user.id } })))
|
||||
|
||||
@@ -120,7 +120,10 @@ router.get("/", route({ responses: { 200: { body: "UserProfileResponse" } } }),
|
||||
const relationshipsIntersection = relationshipsSelf.filter((r1) => relationshipsUser.some((r2) => r2.to_id === r1.to_id));
|
||||
if (with_mutual_friends_count) mutual_friends_count = relationshipsIntersection.length;
|
||||
if (with_mutual_friends) {
|
||||
const users = await User.find({ where: { id: In(relationshipsIntersection.map((r) => r.to_id)) }, select: PublicUserProjection });
|
||||
const users = await User.find({
|
||||
where: { id: In(relationshipsIntersection.map((r) => r.to_id)) },
|
||||
select: Object.fromEntries(PublicUserProjection.map((i) => [i, true])),
|
||||
}); //TODO: clean up
|
||||
mutual_friends = users.map((u) => u.toPublicUser());
|
||||
}
|
||||
}
|
||||
@@ -169,7 +172,7 @@ router.patch("/", route({ requestBody: "UserProfileModifySchema" }), async (req:
|
||||
if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string);
|
||||
const user = await User.findOneOrFail({
|
||||
where: { id: req.user_id },
|
||||
select: [...PrivateUserProjection, "data"],
|
||||
select: Object.fromEntries([...PrivateUserProjection, "data"].map((i) => [i, true])), //TODO: cleanup
|
||||
});
|
||||
|
||||
if (body.bio) {
|
||||
|
||||
@@ -37,7 +37,7 @@ router.get(
|
||||
async (req: Request, res: Response) => {
|
||||
res.json(
|
||||
await User.findOne({
|
||||
select: PrivateUserProjection,
|
||||
select: Object.fromEntries(PrivateUserProjection.map((i) => [i, true])), //TODO: cleanup
|
||||
where: { id: req.user_id },
|
||||
}),
|
||||
);
|
||||
@@ -65,7 +65,7 @@ router.patch(
|
||||
|
||||
const user = await User.findOneOrFail({
|
||||
where: { id: req.user_id },
|
||||
select: [...PrivateUserProjection, "data"],
|
||||
select: Object.fromEntries([...PrivateUserProjection, "data"].map((i) => [i, true])), //TODO: cleanup
|
||||
});
|
||||
|
||||
// Populated on password change
|
||||
|
||||
@@ -72,7 +72,7 @@ router.put(
|
||||
await User.findOneOrFail({
|
||||
where: { id: req.params.user_id as string },
|
||||
relations: { relationships: { to: true } },
|
||||
select: userProjection,
|
||||
select: Object.fromEntries(userProjection.map((i) => [i, true])), // TODO: cleanup
|
||||
}),
|
||||
req.body.type ?? RelationshipType.friends,
|
||||
),
|
||||
@@ -136,7 +136,7 @@ router.post(
|
||||
res,
|
||||
await User.findOneOrFail({
|
||||
relations: { relationships: { to: true } },
|
||||
select: userProjection,
|
||||
select: Object.fromEntries(userProjection.map((i) => [i, true])), // TODO: cleanup
|
||||
where: {
|
||||
discriminator: String(req.body.discriminator).padStart(4, "0"), //Discord send the discriminator as integer, we need to add leading zeroes
|
||||
username: req.body.username,
|
||||
@@ -165,12 +165,12 @@ router.delete(
|
||||
|
||||
const user = await User.findOneOrFail({
|
||||
where: { id: req.user_id },
|
||||
select: userProjection,
|
||||
select: Object.fromEntries(userProjection.map((i) => [i, true])), // TODO: cleanup
|
||||
relations: { relationships: true },
|
||||
});
|
||||
const friend = await User.findOneOrFail({
|
||||
where: { id: user_id },
|
||||
select: userProjection,
|
||||
select: Object.fromEntries(userProjection.map((i) => [i, true])), // TODO: cleanup
|
||||
relations: { relationships: true },
|
||||
});
|
||||
|
||||
@@ -215,8 +215,6 @@ router.delete(
|
||||
},
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
||||
async function updateRelationship(req: Request, res: Response, friend: User, type: RelationshipType) {
|
||||
const id = friend.id;
|
||||
if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend");
|
||||
@@ -224,7 +222,7 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
|
||||
const user = await User.findOneOrFail({
|
||||
where: { id: req.user_id },
|
||||
relations: { relationships: { to: true } },
|
||||
select: userProjection,
|
||||
select: Object.fromEntries(userProjection.map((i) => [i, true])), //TODO: cleanup
|
||||
});
|
||||
|
||||
let relationship = user.relationships.find((x) => x.to_id === id);
|
||||
@@ -316,3 +314,5 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
|
||||
|
||||
return res.sendStatus(204);
|
||||
}
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -546,7 +546,7 @@ export class Channel extends BaseClass {
|
||||
channel_id: channel.id,
|
||||
user: await User.findOneOrFail({
|
||||
where: { id: user_id },
|
||||
select: PublicUserProjection,
|
||||
select: Object.fromEntries(PublicUserProjection.map((i) => [i, true])), //TODO: cleanup
|
||||
}),
|
||||
},
|
||||
channel_id: channel.id,
|
||||
|
||||
@@ -335,7 +335,7 @@ export class Member extends BaseClassWithoutId {
|
||||
where: {
|
||||
id: guild_id,
|
||||
},
|
||||
relations: PublicGuildRelations,
|
||||
relations: Object.fromEntries(PublicGuildRelations.map((i) => [i, true])), //TODO: clean up
|
||||
relationLoadStrategy: "query",
|
||||
});
|
||||
const channelPositionsGuild = await Guild.findOneOrFail({
|
||||
|
||||
@@ -235,7 +235,7 @@ export class User extends BaseClass {
|
||||
static async getPublicUser(user_id: string): Promise<PublicUser> {
|
||||
const user = await User.findOneOrFail({
|
||||
where: { id: user_id },
|
||||
select: PublicUserProjection,
|
||||
select: Object.fromEntries(PublicUserProjection.map((i) => [i, true])), // TODO: clean up
|
||||
});
|
||||
return user.toPublicUser();
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
GuildOrUnavailable,
|
||||
Intents,
|
||||
OPCodes,
|
||||
OrmUtils,
|
||||
PresenceUpdateEvent,
|
||||
ReadyEventData,
|
||||
ReadyGuildDTO,
|
||||
@@ -260,7 +261,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
||||
where: { id: this.user_id },
|
||||
select: {
|
||||
// We only want some member props
|
||||
...Object.fromEntries(["index", ...MemberPrivateProjection].map((x) => [x, true])),
|
||||
...OrmUtils.keysToObject(["index", ...(<string[]>MemberPrivateProjection)]),
|
||||
settings: true, // guild settings
|
||||
roles: { id: true }, // the full role is fetched from the `guild` relation
|
||||
guild: { id: true },
|
||||
@@ -353,7 +354,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
||||
type: Not(In([ChannelType.GUILD_PUBLIC_THREAD, ChannelType.GUILD_PRIVATE_THREAD, ChannelType.GUILD_NEWS_THREAD])),
|
||||
},
|
||||
order: { guild_id: "ASC" },
|
||||
relations: ["available_tags"],
|
||||
relations: { available_tags: true },
|
||||
}),
|
||||
),
|
||||
timePromise(() =>
|
||||
|
||||
@@ -46,7 +46,7 @@ export class DmChannelDTO {
|
||||
.map((r) =>
|
||||
User.findOneOrFail({
|
||||
where: { id: r.user_id },
|
||||
select: PublicUserProjection,
|
||||
select: Object.fromEntries(PublicUserProjection.map((i) => [i, true])), // TODO: clean up
|
||||
}),
|
||||
) || [],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import moduleAlias from "module-alias";
|
||||
moduleAlias(__dirname + "../../../../package.json");
|
||||
import { config } from "dotenv";
|
||||
config({ quiet: true });
|
||||
|
||||
import { describe, test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { OrmUtils } from "./OrmUtils";
|
||||
|
||||
describe("OrmUtils", () => {
|
||||
test("should be able convert string keys to boolean object", () => {
|
||||
const keys = ["member", "member.user", "member.guild.meow", "member.guild", "guild.name"];
|
||||
const expected = {
|
||||
member: {
|
||||
user: true,
|
||||
guild: {
|
||||
meow: true,
|
||||
},
|
||||
},
|
||||
guild: {
|
||||
name: true,
|
||||
},
|
||||
};
|
||||
const result = OrmUtils.keysToObject(keys);
|
||||
assert.deepStrictEqual(result, expected);
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,9 @@
|
||||
// Copyright (c) 2015-2022 TypeORM. http://typeorm.github.io
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// @fc-license-skip
|
||||
import { arrayGroupBy } from "@spacebar/extensions";
|
||||
import { FindOptionsSelect, FindOptionsWhere } from "typeorm";
|
||||
|
||||
export class OrmUtils {
|
||||
// Checks if it's an object made by Object.create(null), {} or new Object()
|
||||
private static isPlainObject(item: unknown) {
|
||||
@@ -96,4 +99,23 @@ export class OrmUtils {
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Copyright Spacebar & contributors 2026 (AGPLv3)
|
||||
static keysToObject(keys: string[]) {
|
||||
const target: FindOptionsSelect<any> = {};
|
||||
for (const k of keys.filter((x) => !x.includes("."))) {
|
||||
target[k] = true;
|
||||
}
|
||||
|
||||
const keyGroups = arrayGroupBy(
|
||||
keys.filter((x) => x.includes(".")),
|
||||
(k) => k.split(".", 2)[0],
|
||||
);
|
||||
|
||||
for (const [k, v] of keyGroups) {
|
||||
target[k] = this.keysToObject(v.map((vv) => vv.replace(k + ".", "")));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { BitField, BitFieldResolvable, BitFlag } from "./BitField";
|
||||
import { HTTPError } from "lambert-server/HTTPError";
|
||||
import { ChannelPermissionOverwrite, ChannelPermissionOverwriteType, ChannelType, UserFlags } from "@spacebar/schemas";
|
||||
import { FindOneOptions } from "typeorm";
|
||||
import { OrmUtils } from "@spacebar/util";
|
||||
|
||||
export type PermissionResolvable = bigint | number | Permissions | PermissionResolvable[] | PermissionString;
|
||||
|
||||
@@ -259,8 +260,8 @@ export async function getPermission(
|
||||
select: { id: true, flags: true },
|
||||
});
|
||||
const query = {
|
||||
relations: ["recipients", "thread_members", "thread_members.member", ...(opts.channel_relations || [])],
|
||||
select: ["type", "parent_id", "id", "recipients", "permission_overwrites", "owner_id", "guild_id", ...(opts.channel_select || [])],
|
||||
relations: OrmUtils.keysToObject(["recipients", "thread_members", "thread_members.member", ...(opts.channel_relations || [])]), // TODO: cleanup
|
||||
select: OrmUtils.keysToObject(["type", "parent_id", "id", "recipients", "permission_overwrites", "owner_id", "guild_id", ...(<string[]>opts.channel_select || [])]), // TODO: cleanup
|
||||
} as FindOneOptions<Channel>;
|
||||
if (typeof channel_id === "string") {
|
||||
channel = await Channel.findOneOrFail({ where: { id: channel_id }, ...query });
|
||||
@@ -287,17 +288,17 @@ export async function getPermission(
|
||||
if (typeof guild_id === "string") {
|
||||
guild = await Guild.findOneOrFail({
|
||||
where: { id: guild_id },
|
||||
select: ["id", "owner_id", ...(opts.guild_select || [])],
|
||||
relations: opts.guild_relations,
|
||||
select: !opts.guild_select ? { id: true, owner_id: true } : OrmUtils.keysToObject(["id", "owner_id", ...(<string[]>opts.guild_select || [])]), // TODO: clean up
|
||||
relations: !opts.guild_relations ? undefined : OrmUtils.keysToObject(opts.guild_relations), // TODO: clean up
|
||||
});
|
||||
} else {
|
||||
guild = guild_id;
|
||||
}
|
||||
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: guild.id, id: user_id },
|
||||
relations: ["roles", ...(opts.member_relations || [])],
|
||||
where: { guild_id: guild!.id, id: user_id },
|
||||
relations: OrmUtils.keysToObject(["roles", ...(opts.member_relations || [])]), // TODO: clean up
|
||||
// select: [
|
||||
// "id", // TODO: Bug in typeorm? adding these selects breaks the query.
|
||||
// "roles",
|
||||
|
||||
+12
-13
@@ -16,18 +16,17 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import jwt from "jsonwebtoken";
|
||||
import { Config } from "./Config";
|
||||
import { InstanceBan, Session, User } from "../../database/entities";
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import { existsSync } from "node:fs";
|
||||
// TODO: dont use deprecated APIs lol
|
||||
import { FindOptionsRelationByString, FindOptionsSelectByString } from "typeorm";
|
||||
import { randomUpperString } from "@spacebar/api";
|
||||
import { TimeSpan } from "../../extensions/Timespan";
|
||||
import { HTTPError } from "lambert-server/HTTPError";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs/promises";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { HTTPError } from "lambert-server/HTTPError";
|
||||
import { InstanceBan, Session, User } from "@spacebar/database";
|
||||
import { randomUpperString } from "@spacebar/api";
|
||||
import { TimeSpan } from "@spacebar/extensions";
|
||||
import { Config } from "./Config";
|
||||
import { OrmUtils } from "@spacebar/util";
|
||||
|
||||
/// Change history:
|
||||
/// 1 - Initial version with HS256
|
||||
@@ -62,8 +61,8 @@ function rejectAndLog(rejectFunction: (reason?: unknown) => void, httpCode: numb
|
||||
export const checkToken = (
|
||||
token: string,
|
||||
opts?: {
|
||||
select?: FindOptionsSelectByString<User>;
|
||||
relations?: FindOptionsRelationByString;
|
||||
select?: string[]; // TODO: clean up
|
||||
relations?: string[]; // TODO: clean up
|
||||
ipAddress?: string;
|
||||
fingerprint?: string;
|
||||
},
|
||||
@@ -85,8 +84,8 @@ export const checkToken = (
|
||||
let [user, session] = await Promise.all([
|
||||
User.findOne({
|
||||
where: { id: decoded.id },
|
||||
select: [...(opts?.select || []), "id", "bot", "disabled", "deleted", "rights", "data"],
|
||||
relations: opts?.relations,
|
||||
select: OrmUtils.keysToObject([...(opts?.select || []), "id", "bot", "disabled", "deleted", "rights", "data"]), // TODO: clean up
|
||||
relations: !opts?.relations ? undefined : OrmUtils.keysToObject(opts.relations), // TODO: clean up
|
||||
}),
|
||||
decoded.did ? Session.findOne({ where: { session_id: decoded.did, user_id: decoded.id } }) : undefined,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user