Use deep merge everywhere

This commit is contained in:
TheArcaneBrony
2022-08-09 23:28:27 +02:00
parent 3c624cc95a
commit 26293f37a1
27 changed files with 189 additions and 49 deletions
+2 -1
View File
@@ -10,6 +10,7 @@ import {
} from "@fosscord/util";
import { Request, Response, Router } from "express";
import { route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router: Router = Router();
// TODO: delete channel
@@ -78,7 +79,7 @@ router.patch("/", route({ body: "ChannelModifySchema", permission: "MANAGE_CHANN
if (payload.icon) payload.icon = await handleFile(`/channel-icons/${channel_id}`, payload.icon);
let channel = await Channel.findOneOrFail({ where: { id: channel_id } });
channel = Object.assign(channel, payload);
channel = OrmUtils.mergeDeep(channel, payload);
await Promise.all([
channel.save(),
@@ -4,6 +4,7 @@ import { route } from "@fosscord/api";
import { random } from "@fosscord/api";
import { Channel, Invite, InviteCreateEvent, emitEvent, User, Guild, PublicInviteRelation } from "@fosscord/util";
import { isTextChannel } from "./messages";
import { OrmUtils } from "@fosscord/util";
const router: Router = Router();
@@ -33,7 +34,7 @@ router.post("/", route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT
const expires_at = new Date(req.body.max_age * 1000 + Date.now());
const invite = await Object.assign(new Invite(),{
const invite = await OrmUtils.mergeDeep(new Invite(),{
code: random(),
temporary: req.body.temporary,
uses: 0,
@@ -1,6 +1,7 @@
import { emitEvent, getPermission, MessageAckEvent, ReadState, Snowflake } from "@fosscord/util";
import { Request, Response, Router } from "express";
import { route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router = Router();
@@ -20,7 +21,7 @@ router.post("/", route({ body: "MessageAcknowledgeSchema" }), async (req: Reques
permission.hasThrow("VIEW_CHANNEL");
let read_state = await ReadState.findOne({ where: { user_id: req.user_id, channel_id } });
if (!read_state) read_state = Object.assign(new ReadState(), { user_id: req.user_id, channel_id });
if (!read_state) read_state = OrmUtils.mergeDeep(new ReadState(), { user_id: req.user_id, channel_id }) as ReadState;
read_state.last_message_id = message_id;
await read_state.save();
@@ -11,6 +11,7 @@ import {
User
} from "@fosscord/util";
import { route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router: Router = Router();
@@ -28,7 +29,7 @@ router.put("/:user_id", route({}), async (req: Request, res: Response) => {
throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error?
}
channel.recipients!.push(Object.assign(new Recipient(), { channel_id, user_id: user_id }));
channel.recipients!.push(OrmUtils.mergeDeep(new Recipient(), { channel_id, user_id: user_id }));
await channel.save();
await emitEvent({
+3 -2
View File
@@ -2,6 +2,7 @@ import { Request, Response, Router } from "express";
import { DiscordApiErrors, emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, Guild, Ban, User, Member } from "@fosscord/util";
import { HTTPError } from "@fosscord/util";
import { getIpAdress, route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
export interface BanCreateSchema {
delete_message_days?: string;
@@ -90,7 +91,7 @@ router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBER
const banned_user = await User.getPublicUser(banned_user_id);
const ban = Object.assign(new Ban(),{
const ban = OrmUtils.mergeDeep(new Ban(),{
user_id: banned_user_id,
guild_id: guild_id,
ip: getIpAdress(req),
@@ -122,7 +123,7 @@ router.put("/@me", route({ body: "BanCreateSchema"}), async (req: Request, res:
if (req.permission!.cache.guild?.owner_id === req.params.user_id)
throw new HTTPError("You are the guild owner, hence can't ban yourself", 403);
const ban = Object.assign(new Ban(), {
const ban = OrmUtils.mergeDeep(new Ban(), {
user_id: req.params.user_id,
guild_id: guild_id,
ip: getIpAdress(req),
+3 -2
View File
@@ -1,6 +1,7 @@
import { Router, Request, Response } from "express";
import { Config, DiscordApiErrors, emitEvent, Emoji, GuildEmojisUpdateEvent, handleFile, Member, Snowflake, User } from "@fosscord/util";
import { route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router = Router();
@@ -50,7 +51,7 @@ router.post("/", route({ body: "EmojiCreateSchema", permission: "MANAGE_EMOJIS_A
const user = await User.findOneOrFail({ where: { id: req.user_id } });
body.image = (await handleFile(`/emojis/${id}`, body.image)) as string;
const emoji = await Object.assign(new Emoji(), {
const emoji = await OrmUtils.mergeDeep(new Emoji(), {
id: id,
guild_id: guild_id,
...body,
@@ -80,7 +81,7 @@ router.patch(
const { emoji_id, guild_id } = req.params;
const body = req.body as EmojiModifySchema;
const emoji = await Object.assign(new Emoji(), { ...body, id: emoji_id, guild_id: guild_id }).save();
const emoji = await OrmUtils.mergeDeep(new Emoji(), { ...body, id: emoji_id, guild_id: guild_id }).save();
await emitEvent({
event: "GUILD_EMOJIS_UPDATE",
+2 -1
View File
@@ -3,6 +3,7 @@ import { DiscordApiErrors, emitEvent, getPermission, getRights, Guild, GuildUpda
import { HTTPError } from "@fosscord/util";
import { route } from "@fosscord/api";
import { GuildCreateSchema } from "../index";
import { OrmUtils } from "@fosscord/util";
const router = Router();
@@ -59,7 +60,7 @@ router.patch("/", route({ body: "GuildUpdateSchema"}), async (req: Request, res:
relations: ["emojis", "roles", "stickers"]
});
// TODO: check if body ids are valid
guild = Object.assign(guild, body);
guild = OrmUtils.mergeDeep(guild, body);
//TODO: check this, removed toJSON call
const data = JSON.parse(JSON.stringify(guild));
@@ -2,6 +2,7 @@ import { Request, Response, Router } from "express";
import { Member, getPermission, getRights, Role, GuildMemberUpdateEvent, emitEvent, Sticker, Emoji, Rights, Guild } from "@fosscord/util";
import { HTTPError } from "@fosscord/util";
import { route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router = Router();
@@ -31,7 +32,7 @@ router.patch("/", route({ body: "MemberChangeSchema" }), async (req: Request, re
permission.hasThrow("MANAGE_ROLES");
if (body.roles.indexOf(everyone.id) === -1) body.roles.push(everyone.id);
member.roles = body.roles.map((x) => Object.assign(new Role(), { id: x })); // foreign key constraint will fail if role doesn't exist
member.roles = body.roles.map((x) => OrmUtils.mergeDeep(new Role(), { id: x })); // foreign key constraint will fail if role doesn't exist
}
await member.save();
@@ -3,6 +3,7 @@ import { Role, Member, GuildRoleUpdateEvent, GuildRoleDeleteEvent, emitEvent, ha
import { route } from "@fosscord/api";
import { HTTPError } from "@fosscord/util";
import { RoleModifySchema } from "../";
import { OrmUtils } from "@fosscord/util";
const router = Router();
@@ -43,7 +44,7 @@ router.patch("/", route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }
if (body.icon) body.icon = await handleFile(`/role-icons/${role_id}`, body.icon as string);
const role = Object.assign(new Role(), {
const role = OrmUtils.mergeDeep(new Role(), {
...body,
id: role_id,
guild_id,
@@ -13,6 +13,7 @@ import {
} from "@fosscord/util";
import { HTTPError } from "@fosscord/util";
import { route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router: Router = Router();
@@ -51,7 +52,7 @@ router.post("/", route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" })
if (role_count > maxRoles) throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles);
let role: Role = Object.assign(new Role(),{
let role: Role = OrmUtils.mergeDeep(new Role(),{
// values before ...body are default and can be overriden
position: 0,
hoist: false,
+3 -2
View File
@@ -13,6 +13,7 @@ import { Router, Request, Response } from "express";
import { route } from "@fosscord/api";
import multer from "multer";
import { HTTPError } from "@fosscord/util";
import { OrmUtils } from "@fosscord/util";
const router = Router();
router.get("/", route({}), async (req: Request, res: Response) => {
@@ -43,7 +44,7 @@ router.post(
const id = Snowflake.generate();
const [sticker] = await Promise.all([
Object.assign(new Sticker(), {
OrmUtils.mergeDeep(new Sticker(), {
...body,
guild_id,
id,
@@ -105,7 +106,7 @@ router.patch(
const { guild_id, sticker_id } = req.params;
const body = req.body as ModifyGuildStickerSchema;
const sticker = await Object.assign(new Sticker(), { ...body, guild_id, id: sticker_id }).save();
const sticker = await OrmUtils.mergeDeep(new Sticker(), { ...body, guild_id, id: sticker_id }).save();
await sendStickerUpdateEvent(guild_id);
return res.json(sticker);
+4 -3
View File
@@ -3,6 +3,7 @@ import { Guild, Template } from "@fosscord/util";
import { HTTPError } from "@fosscord/util";
import { route } from "@fosscord/api";
import { generateCode } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router: Router = Router();
@@ -47,7 +48,7 @@ router.post("/", route({ body: "TemplateCreateSchema", permission: "MANAGE_GUILD
const exists = await Template.findOneOrFail({ where: { id: guild_id } }).catch((e) => {});
if (exists) throw new HTTPError("Template already exists", 400);
const template = await Object.assign(new Template(), {
const template = await OrmUtils.mergeDeep(new Template(), {
...req.body,
code: generateCode(),
creator_id: req.user_id,
@@ -75,7 +76,7 @@ router.put("/:code", route({ permission: "MANAGE_GUILD" }), async (req: Request,
const { code, guild_id } = req.params;
const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: TemplateGuildProjection });
const template = await Object.assign(new Template(), { code, serialized_source_guild: guild }).save();
const template = await OrmUtils.mergeDeep(new Template(), { code, serialized_source_guild: guild }).save();
res.json(template);
});
@@ -84,7 +85,7 @@ router.patch("/:code", route({ body: "TemplateModifySchema", permission: "MANAGE
const { code, guild_id } = req.params;
const { name, description } = req.body;
const template = await Object.assign(new Template(), { code, name: name, description: description, source_guild_id: guild_id }).save();
const template = await OrmUtils.mergeDeep(new Template(), { code, name: name, description: description, source_guild_id: guild_id }).save();
res.json(template);
});
@@ -2,6 +2,7 @@ import { Channel, ChannelType, getPermission, Guild, Invite, trimSpecial } from
import { Router, Request, Response } from "express";
import { route } from "@fosscord/api";
import { HTTPError } from "@fosscord/util";
import { OrmUtils } from "@fosscord/util";
const router = Router();
@@ -47,7 +48,7 @@ router.patch("/", route({ body: "VanityUrlSchema", permission: "MANAGE_GUILD" })
const { id } = await Channel.findOneOrFail({ where: { guild_id, type: ChannelType.GUILD_TEXT } });
await Object.assign(new Invite(), {
await OrmUtils.mergeDeep(new Invite(), {
vanity_url: true,
code: code,
temporary: false,
@@ -1,6 +1,7 @@
import { Channel, ChannelType, DiscordApiErrors, emitEvent, getPermission, VoiceState, VoiceStateUpdateEvent } from "@fosscord/util";
import { route } from "@fosscord/api";
import { Request, Response, Router } from "express";
import { OrmUtils } from "@fosscord/util";
const router = Router();
//TODO need more testing when community guild and voice stage channel are working
@@ -42,7 +43,7 @@ router.patch("/", route({ body: "VoiceStateUpdateSchema" }), async (req: Request
});
if (!voice_state) throw DiscordApiErrors.UNKNOWN_VOICE_STATE;
voice_state = Object.assign(voice_state, body);
voice_state = OrmUtils.mergeDeep(voice_state, body) as VoiceState;
const channel = await Channel.findOneOrFail({ where: { guild_id, id: body.channel_id } });
if (channel.type !== ChannelType.GUILD_STAGE_VOICE) {
throw DiscordApiErrors.CANNOT_EXECUTE_ON_THIS_CHANNEL_TYPE;
@@ -2,6 +2,7 @@ import { Request, Response, Router } from "express";
import { Config, Permissions, Guild, Invite, Channel, Member } from "@fosscord/util";
import { HTTPError } from "@fosscord/util";
import { random, route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router: Router = Router();
@@ -41,7 +42,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
inviter_id: null
};
invite = await new Invite(body).save();
invite = await OrmUtils.mergeDeep(new Invite(), body).save();
}
// Fetch voice channels, and the @everyone permissions object
+3 -2
View File
@@ -4,6 +4,7 @@ import { route } from "@fosscord/api";
import { DiscordApiErrors } from "@fosscord/util";
import fetch from "node-fetch";
const router: Router = Router();
import { OrmUtils } from "@fosscord/util";
export interface GuildTemplateCreateSchema {
name: string;
@@ -57,13 +58,13 @@ router.post("/:code", route({ body: "GuildTemplateCreateSchema" }), async (req:
const guild_id = Snowflake.generate();
const [guild, role] = await Promise.all([
Object.assign(new Guild(), {
OrmUtils.mergeDeep(new Guild(), {
...body,
...template.serialized_source_guild,
id: guild_id,
owner_id: req.user_id
}).save(),
(Object.assign(new Role(), {
(OrmUtils.mergeDeep(new Role(), {
id: guild_id,
guild_id: guild_id,
color: 0,
+4 -2
View File
@@ -2,6 +2,7 @@ import { Router, Request, Response } from "express";
import { User, PrivateUserProjection, emitEvent, UserUpdateEvent, handleFile, FieldErrors } from "@fosscord/util";
import { route } from "@fosscord/api";
import bcrypt from "bcrypt";
import { OrmUtils } from "@fosscord/util";
const router: Router = Router();
@@ -32,7 +33,8 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res:
const body = req.body as UserModifySchema;
if (body.avatar) body.avatar = await handleFile(`/avatars/${req.user_id}`, body.avatar as string);
if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string);let user = await User.findOneOrFail({ where: { id: req.user_id }, select: [...PrivateUserProjection, "data"] });
if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string);
let user = await User.findOneOrFail({ where: { id: req.user_id }, select: [...PrivateUserProjection, "data"] });
if (body.password) {
if (user.data?.hash) {
@@ -63,7 +65,7 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res:
}
}
user = Object.assign(user, body);
user = OrmUtils.mergeDeep(user, body);
await user.save();
// @ts-ignore
+4 -3
View File
@@ -12,6 +12,7 @@ import { Router, Response, Request } from "express";
import { HTTPError } from "@fosscord/util";
import { DiscordApiErrors } from "@fosscord/util";
import { route } from "@fosscord/api";
import { OrmUtils } from "@fosscord/util";
const router = Router();
@@ -140,7 +141,7 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
relationship.type = RelationshipType.blocked;
await relationship.save();
} else {
relationship = await Object.assign(new Relationship(), { to_id: id, type: RelationshipType.blocked, from_id: req.user_id }).save();
relationship = await (OrmUtils.mergeDeep(new Relationship(), { to_id: id, type: RelationshipType.blocked, from_id: req.user_id }) as Relationship).save();
}
if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
@@ -166,8 +167,8 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
const { maxFriends } = Config.get().limits.user;
if (user.relationships.length >= maxFriends) throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
let incoming_relationship = Object.assign(new Relationship(), { nickname: undefined, type: RelationshipType.incoming, to: user, from: friend });
let outgoing_relationship = Object.assign(new Relationship(), {
let incoming_relationship = OrmUtils.mergeDeep(new Relationship(), { nickname: undefined, type: RelationshipType.incoming, to: user, from: friend });
let outgoing_relationship = OrmUtils.mergeDeep(new Relationship(), {
nickname: undefined,
type: RelationshipType.outgoing,
to: friend,
+5 -4
View File
@@ -26,6 +26,7 @@ import { HTTPError } from "@fosscord/util";
import fetch from "node-fetch";
import cheerio from "cheerio";
import { MessageCreateSchema } from "../../routes/channels/#channel_id/messages";
import { OrmUtils } from "@fosscord/util";
const allow_empty = false;
// TODO: check webhook, application, system author, stickers
// TODO: embed gifs/videos/images
@@ -47,7 +48,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
const channel = await Channel.findOneOrFail({ where: { id: opts.channel_id }, relations: ["recipients"] });
if (!channel || !opts.channel_id) throw new HTTPError("Channel not found", 404);
const message = Object.assign(new Message(), {
const message = OrmUtils.mergeDeep(new Message(), {
...opts,
sticker_items: opts.sticker_ids?.map((x) => ({ id: x })),
guild_id: channel.guild_id,
@@ -132,9 +133,9 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
}
}
message.mention_channels = mention_channel_ids.map((x) => Object.assign(new Channel(), { id: x }));
message.mention_roles = mention_role_ids.map((x) => Object.assign(new Role(), { id: x }));
message.mentions = mention_user_ids.map((x) => Object.assign(new User(), { id: x }));
message.mention_channels = mention_channel_ids.map((x) => OrmUtils.mergeDeep(new Channel(), { id: x }));
message.mention_roles = mention_role_ids.map((x) => OrmUtils.mergeDeep(new Role(), { id: x }));
message.mentions = mention_user_ids.map((x) => OrmUtils.mergeDeep(new User(), { id: x }));
message.mention_everyone = mention_everyone;
// TODO: check and put it all in the body
+3 -2
View File
@@ -28,6 +28,7 @@ import { IdentifySchema } from "../schema/Identify";
const experiments: any = [];
import { check } from "./instanceOf";
import { Recipient } from "@fosscord/util";
import { OrmUtils } from "@fosscord/util";
// TODO: user sharding
// TODO: check privileged intents, if defined in the config
@@ -50,7 +51,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
const session_id = genSessionId();
this.session_id = session_id; //Set the session of the WebSocket object
const [user, read_states, members, recipients, session, application] =
await Promise.all([
User.findOneOrFail({
@@ -83,7 +84,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
// TODO: public user selection
}),
// save the session and delete it when the websocket is closed
Object.assign(new Session(),{
await OrmUtils.mergeDeep(new Session(), {
user_id: this.user_id,
session_id: session_id,
// TODO: check if status is only one of: online, dnd, offline, idle
+3 -2
View File
@@ -12,6 +12,7 @@ import {
VoiceState,
VoiceStateUpdateEvent,
} from "@fosscord/util";
import { OrmUtils } from "@fosscord/util";
// TODO: check if a voice server is setup
// Notice: Bot users respect the voice channel's user limit, if set. When the voice channel is full, you will not receive the Voice State Update or Voice Server Update events in response to your own Voice State Update. Having MANAGE_CHANNELS permission bypasses this limit and allows you to join regardless of the channel being full or not.
@@ -47,9 +48,9 @@ export async function onVoiceStateUpdate(this: WebSocket, data: Payload) {
//The event send by Discord's client on channel leave has both guild_id and channel_id as null
if (body.guild_id === null) body.guild_id = voiceState.guild_id;
voiceState = Object.assign(voiceState, body);
voiceState = OrmUtils.mergeDeep(voiceState, body);
} catch (error) {
voiceState = Object.assign(new VoiceState(), {
voiceState = OrmUtils.mergeDeep(new VoiceState(), {
...body,
user_id: this.user_id,
deaf: false,
+6 -5
View File
@@ -1,4 +1,5 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm";
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId} from "typeorm";
import { OrmUtils } from "@fosscord/util";
import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild";
import { PublicUserProjection, User } from "./User";
@@ -222,7 +223,7 @@ export class Channel extends BaseClass {
};
await Promise.all([
Object.assign(new Channel(),channel).save(),
OrmUtils.mergeDeep(new Channel(),channel).save(),
!opts?.skipEventEmit
? emitEvent({
event: "CHANNEL_CREATE",
@@ -263,7 +264,7 @@ export class Channel extends BaseClass {
if (containsAll(re, channelRecipients)) {
if (channel == null) {
channel = ur.channel;
ur = Object.assign(ur, { closed: false });
ur = OrmUtils.mergeDeep(ur, { closed: false });
await ur.save();
}
}
@@ -273,7 +274,7 @@ export class Channel extends BaseClass {
if (channel == null) {
name = trimSpecial(name);
channel = await (Object.assign(new Channel(), {
channel = await (OrmUtils.mergeDeep(new Channel(), {
name,
type,
owner_id: type === ChannelType.DM ? undefined : null, // 1:1 DMs are ownerless in fosscord-server
@@ -281,7 +282,7 @@ export class Channel extends BaseClass {
last_message_id: null,
recipients: channelRecipients.map(
(x) =>
Object.assign(new Recipient(), { user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })
OrmUtils.mergeDeep(new Recipient(), { user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })
),
}) as Channel).save();
}
+4 -3
View File
@@ -1,4 +1,5 @@
import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm";
import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, OneToOne, RelationId} from "typeorm";
import { OrmUtils } from "@fosscord/util";
import { Config, handleFile, Snowflake } from "..";
import { Ban } from "./Ban";
import { BaseClass } from "./BaseClass";
@@ -285,7 +286,7 @@ export class Guild extends BaseClass {
}) {
const guild_id = Snowflake.generate();
const guild: Guild = Object.assign(new Guild(),{
const guild: Guild = OrmUtils.mergeDeep(new Guild(),{
name: body.name || "Fosscord",
icon: await handleFile(`/icons/${guild_id}`, body.icon as string),
region: Config.get().regions.default,
@@ -321,7 +322,7 @@ export class Guild extends BaseClass {
// we have to create the role _after_ the guild because else we would get a "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" error
// TODO: make the @everyone a pseudorole that is dynamically generated at runtime so we can save storage
let role: Role = Object.assign(new Role(), {
let role: Role = OrmUtils.mergeDeep(new Role(), {
id: guild_id,
guild_id: guild_id,
color: 0,
+5 -4
View File
@@ -25,6 +25,7 @@ import { Role } from "./Role";
import { BaseClassWithoutId } from "./BaseClass";
import { Ban, PublicGuildRelations } from ".";
import { DiscordApiErrors } from "../util/Constants";
import { OrmUtils } from "@fosscord/util";
export const MemberPrivateProjection: (keyof Member)[] = [
"id",
@@ -161,7 +162,7 @@ export class Member extends BaseClassWithoutId {
}),
Role.findOneOrFail({ where: { id: role_id, guild_id }, select: ["id"] }),
]);
member.roles.push(Object.assign(new Role(), { id: role_id }));
member.roles.push(OrmUtils.mergeDeep(new Role(), { id: role_id }));
await Promise.all([
member.save(),
@@ -256,7 +257,7 @@ export class Member extends BaseClassWithoutId {
nick: undefined,
roles: [guild_id], // @everyone role
joined_at: new Date(),
premium_since: (new Date()).getTime(),
premium_since: new Date(),
deaf: false,
mute: false,
pending: false,
@@ -264,9 +265,9 @@ export class Member extends BaseClassWithoutId {
//TODO: check for bugs
if(guild.member_count) guild.member_count++;
await Promise.all([
Object.assign(new Member(), {
OrmUtils.mergeDeep(new Member(), {
...member,
roles: [Object.assign(new Role(), { id: guild_id })],
roles: [OrmUtils.mergeDeep(new Role(), { id: guild_id })],
// read_state: {},
settings: {
channel_overrides: [],
+3 -2
View File
@@ -1,4 +1,5 @@
import { Column, Entity, FindOneOptions, FindOptionsSelectByString, JoinColumn, ManyToMany, OneToMany, RelationId } from "typeorm";
import { Column, Entity, FindOneOptions, FindOptionsSelectByString, JoinColumn, ManyToMany, OneToMany, RelationId} from "typeorm";
import { OrmUtils } from "@fosscord/util";
import { BaseClass } from "./BaseClass";
import { BitField } from "../util/BitField";
import { Relationship } from "./Relationship";
@@ -255,7 +256,7 @@ export class User extends BaseClass {
// if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false
const language = req.language === "en" ? "en-US" : req.language || "en-US";
const user = Object.assign(new User(), {
const user = OrmUtils.mergeDeep(new User(), {
created_at: new Date(),
username: username,
discriminator,
+113
View File
@@ -0,0 +1,113 @@
//source: https://github.com/typeorm/typeorm/blob/master/src/util/OrmUtils.ts
export class OrmUtils {
// Checks if it's an object made by Object.create(null), {} or new Object()
private static isPlainObject(item: any) {
if (item === null || item === undefined) {
return false
}
return !item.constructor || item.constructor === Object
}
private static mergeArrayKey(
target: any,
key: number,
value: any,
memo: Map<any, any>,
) {
// Have we seen this before? Prevent infinite recursion.
if (memo.has(value)) {
target[key] = memo.get(value)
return
}
if (value instanceof Promise) {
// Skip promises entirely.
// This is a hold-over from the old code & is because we don't want to pull in
// the lazy fields. Ideally we'd remove these promises via another function first
// but for now we have to do it here.
return
}
if (!this.isPlainObject(value) && !Array.isArray(value)) {
target[key] = value
return
}
if (!target[key]) {
target[key] = Array.isArray(value) ? [] : {}
}
memo.set(value, target[key])
this.merge(target[key], value, memo)
memo.delete(value)
}
private static mergeObjectKey(
target: any,
key: string,
value: any,
memo: Map<any, any>,
) {
// Have we seen this before? Prevent infinite recursion.
if (memo.has(value)) {
Object.assign(target, { [key]: memo.get(value) })
return
}
if (value instanceof Promise) {
// Skip promises entirely.
// This is a hold-over from the old code & is because we don't want to pull in
// the lazy fields. Ideally we'd remove these promises via another function first
// but for now we have to do it here.
return
}
if (!this.isPlainObject(value) && !Array.isArray(value)) {
Object.assign(target, { [key]: value })
return
}
if (!target[key]) {
Object.assign(target, { [key]: value })
}
memo.set(value, target[key])
this.merge(target[key], value, memo)
memo.delete(value)
}
private static merge(
target: any,
source: any,
memo: Map<any, any> = new Map(),
): any {
if (Array.isArray(target) && Array.isArray(source)) {
for (let key = 0; key < source.length; key++) {
this.mergeArrayKey(target, key, source[key], memo)
}
}
else {
for (const key of Object.keys(source)) {
this.mergeObjectKey(target, key, source[key], memo)
}
}
}
/**
* Deep Object.assign.
*/
static mergeDeep(target: any, ...sources: any[]): any {
if (!sources.length) {
return target
}
for (const source of sources) {
OrmUtils.merge(target, source)
}
return target
}
}
+1
View File
@@ -1,2 +1,3 @@
export * from './Checks';
export * from './HTTPError';
export * from './OrmUtils';