This commit is contained in:
Flam3rboy 2021-08-27 11:10:42 +02:00
parent 18deb1e4b0
commit 0ecc5d8c0e
17 changed files with 1129 additions and 164 deletions

View File

@ -1 +0,0 @@
it("works", () => {});

View File

@ -145,9 +145,9 @@ export default {
// The glob patterns Jest uses to detect test files // The glob patterns Jest uses to detect test files
testMatch: [ testMatch: [
"**/__tests__/**/*.[jt]s?(x)", "**/tests/**/*.[jt]s?(x)"
// "**/?(*.)+(spec|test).[tj]s?(x)" // "**/?(*.)+(spec|test).[tj]s?(x)"
], ]
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [ // testPathIgnorePatterns: [

1069
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"main": "dist/Server.js", "main": "dist/Server.js",
"types": "dist/Server.d.ts", "types": "dist/Server.d.ts",
"scripts": { "scripts": {
"test": "jest", "test": "npm run build && jest",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"start": "npm run build && node dist/start", "start": "npm run build && node dist/start",
"build": "npx tsc -b .", "build": "npx tsc -b .",
@ -35,6 +35,7 @@
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/express": "^4.17.9", "@types/express": "^4.17.9",
"@types/i18next-node-fs-backend": "^2.1.0", "@types/i18next-node-fs-backend": "^2.1.0",
"@types/jest": "^27.0.1",
"@types/jsonwebtoken": "^8.5.0", "@types/jsonwebtoken": "^8.5.0",
"@types/mongodb": "^3.6.9", "@types/mongodb": "^3.6.9",
"@types/mongoose": "^5.10.5", "@types/mongoose": "^5.10.5",
@ -79,6 +80,7 @@
"mongoose-autopopulate": "^0.12.3", "mongoose-autopopulate": "^0.12.3",
"mongoose-long": "^0.3.2", "mongoose-long": "^0.3.2",
"multer": "^1.4.2", "multer": "^1.4.2",
"node-fetch": "^2.6.1" "node-fetch": "^2.6.1",
"typeorm": "^0.2.37"
} }
} }

View File

@ -0,0 +1 @@
// TODO: start api

View File

@ -2,6 +2,7 @@ import { NextFunction, Request, Response } from "express";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { FieldError } from "../util/instanceOf"; import { FieldError } from "../util/instanceOf";
// TODO: update with new body/typorm validation
export function ErrorHandler(error: Error, req: Request, res: Response, next: NextFunction) { export function ErrorHandler(error: Error, req: Request, res: Response, next: NextFunction) {
if (!error) next(); if (!error) next();

View File

@ -21,9 +21,6 @@ router.post(
async (req: Request, res: Response) => { async (req: Request, res: Response) => {
const { login, password, captcha_key, undelete } = req.body; const { login, password, captcha_key, undelete } = req.body;
const email = adjustEmail(login); const email = adjustEmail(login);
const query: any[] = [{ phone: login }];
if (email) query.push({ email });
console.log(req.body, email); console.log(req.body, email);
const config = Config.get(); const config = Config.get();
@ -41,11 +38,10 @@ router.post(
// TODO: check captcha // TODO: check captcha
} }
const user = await User.findOneOrFail( const user = await User.findOneOrFail({
{ $or: query }, where: [{ phone: login }, { email: login }],
{ "data.hash": true, id: true, disabled: true, deleted: true, "settings.locale": true, "settings.theme": true } select: ["data", "id", "disabled", "deleted", "settings"]
).catch((e) => { }).catch((e) => {
console.log(e, query);
throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } }); throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } });
}); });

View File

@ -1,12 +1,12 @@
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
import { trimSpecial, User, Snowflake, User, Config } from "@fosscord/util"; import { trimSpecial, User, Snowflake, Config } from "@fosscord/util";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf"; import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf";
import "missing-native-js-functions"; import "missing-native-js-functions";
import { generateToken } from "./login"; import { generateToken } from "./login";
import { getIpAdress, IPAnalysis, isProxy } from "../../util/ipAddress"; import { getIpAdress, IPAnalysis, isProxy } from "../../util/ipAddress";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import RateLimit from "../../middlewares/RateLimit"; import { In } from "typeorm";
const router: Router = Router(); const router: Router = Router();
@ -55,13 +55,13 @@ router.post(
// TODO: check password strength // TODO: check password strength
// adjusted_email will be slightly modified version of the user supplied email -> e.g. protection against GMail Trick // adjusted_email will be slightly modified version of the user supplied email -> e.g. protection against GMail Trick
let adjusted_email: string | null = adjustEmail(email); let adjusted_email = adjustEmail(email);
// adjusted_password will be the hash of the password // adjusted_password will be the hash of the password
let adjusted_password: string = ""; let adjusted_password = "";
// trim special uf8 control characters -> Backspace, Newline, ... // trim special uf8 control characters -> Backspace, Newline, ...
let adjusted_username: string = trimSpecial(username); let adjusted_username = trimSpecial(username);
// discriminator will be randomly generated // discriminator will be randomly generated
let discriminator = ""; let discriminator = "";
@ -129,7 +129,7 @@ router.post(
if (!register.allowMultipleAccounts) { if (!register.allowMultipleAccounts) {
// TODO: check if fingerprint was eligible generated // TODO: check if fingerprint was eligible generated
const exists = await User.findOneOrFail({ fingerprints: fingerprint }).catch((e) => {}); const exists = await User.findOne({ where: { fingerprints: In(fingerprint) } });
if (exists) { if (exists) {
throw FieldErrors({ throw FieldErrors({
@ -164,12 +164,8 @@ router.post(
// TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the mongodb database? // TODO: is there any better way to generate a random discriminator only once, without checking if it already exists in the mongodb database?
for (let tries = 0; tries < 5; tries++) { for (let tries = 0; tries < 5; tries++) {
discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0"); discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0");
try { exists = await User.findOne({ where: { discriminator, username: adjusted_username }, select: ["id"] });
exists = await User.findOneOrFail({ discriminator, username: adjusted_username }, "id"); if (!exists) break;
} catch (error) {
// doesn't exist -> break
break;
}
} }
if (exists) { if (exists) {
@ -185,35 +181,26 @@ router.post(
// appearently discord doesn't save the date of birth and just calculate if nsfw is allowed // appearently discord doesn't save the date of birth and just calculate if nsfw is allowed
// if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false // if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false
const user: User = { const user = await new User({
id: Snowflake.generate(), id: Snowflake.generate(),
created_at: new Date(), created_at: new Date(),
username: adjusted_username, username: adjusted_username,
discriminator, discriminator,
avatar: null, avatar: undefined,
accent_color: null, accent_color: undefined,
banner: null, banner: undefined,
bot: false, bot: false,
system: false, system: false,
desktop: false, desktop: false,
mobile: false, mobile: false,
premium: true, premium: true,
premium_type: 2, premium_type: 2,
phone: null, phone: undefined,
bio: "", bio: "",
mfa_enabled: false, mfa_enabled: false,
verified: false, verified: false,
disabled: false, disabled: false,
deleted: false, deleted: false,
presence: {
activities: [],
client_status: {
desktop: undefined,
mobile: undefined,
web: undefined
},
status: "offline"
},
email: adjusted_email, email: adjusted_email,
nsfw_allowed: true, // TODO: depending on age nsfw_allowed: true, // TODO: depending on age
public_flags: 0n, public_flags: 0n,
@ -221,10 +208,7 @@ router.post(
guilds: [], guilds: [],
data: { data: {
hash: adjusted_password, hash: adjusted_password,
valid_tokens_since: new Date(), valid_tokens_since: new Date()
relationships: [],
connected_accounts: [],
fingerprints: []
}, },
settings: { settings: {
afk_timeout: 300, afk_timeout: 300,
@ -234,10 +218,10 @@ router.post(
contact_sync_enabled: false, contact_sync_enabled: false,
convert_emoticons: false, convert_emoticons: false,
custom_status: { custom_status: {
emoji_id: null, emoji_id: undefined,
emoji_name: null, emoji_name: undefined,
expires_at: null, expires_at: undefined,
text: null text: undefined
}, },
default_guilds_restricted: false, default_guilds_restricted: false,
detect_platform_accounts: true, detect_platform_accounts: true,
@ -265,16 +249,13 @@ router.post(
timezone_offset: 0 timezone_offset: 0
// timezone_offset: // TODO: timezone from request // timezone_offset: // TODO: timezone from request
} }
}; }).save();
// insert user into database
await new User(user).save();
return res.json({ token: await generateToken(user.id) }); return res.json({ token: await generateToken(user.id) });
} }
); );
export function adjustEmail(email: string): string | null { export function adjustEmail(email: string): string | undefined {
// body parser already checked if it is a valid email // body parser already checked if it is a valid email
const parts = <RegExpMatchArray>email.match(EMAIL_REGEX); const parts = <RegExpMatchArray>email.match(EMAIL_REGEX);
// @ts-ignore // @ts-ignore

View File

@ -1,5 +1,5 @@
import { Router, Response, Request } from "express"; import { Router, Response, Request } from "express";
import { Channel, toObject, ChannelUpdateEvent, getPermission, emitEvent } from "@fosscord/util"; import { Channel, ChannelUpdateEvent, getPermission, emitEvent } from "@fosscord/util";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { ChannelModifySchema } from "../../../schema/Channel"; import { ChannelModifySchema } from "../../../schema/Channel";
@ -48,15 +48,19 @@ router.patch(
if (x.parent_id) { if (x.parent_id) {
opts.parent_id = x.parent_id; opts.parent_id = x.parent_id;
const parent_channel = await Channel.findOneOrFail({ id: x.parent_id, guild_id }, { permission_overwrites: true }); const parent_channel = await Channel.findOneOrFail({
where: { id: x.parent_id, guild_id },
select: ["permission_overwrites"]
});
if (x.lock_permissions) { if (x.lock_permissions) {
opts.permission_overwrites = parent_channel.permission_overwrites; opts.permission_overwrites = parent_channel.permission_overwrites;
} }
} }
const channel = await Channel.findOneOrFailAndUpdate({ id: x.id, guild_id }, opts, { new: true }); await Channel.update({ guild_id, id: x.id }, opts);
const channel = await Channel.findOneOrFail({ guild_id, id: x.id });
await emitEvent({ event: "CHANNEL_UPDATE", data: channel), channel_id: x.id, guild_id } as ChannelUpdateEvent; await emitEvent({ event: "CHANNEL_UPDATE", data: channel, channel_id: x.id, guild_id } as ChannelUpdateEvent);
}) })
]); ]);

View File

@ -1,5 +1,5 @@
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
import { TemplateModel, Guild, getPermission, toObject, User, Snowflake } from "@fosscord/util"; import { Guild, getPermission, Template } from "@fosscord/util";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { TemplateCreateSchema, TemplateModifySchema } from "../../../schema/Template"; import { TemplateCreateSchema, TemplateModifySchema } from "../../../schema/Template";
import { check } from "../../../util/instanceOf"; import { check } from "../../../util/instanceOf";
@ -7,22 +7,22 @@ import { generateCode } from "../../../util/String";
const router: Router = Router(); const router: Router = Router();
const TemplateGuildProjection = { const TemplateGuildProjection: (keyof Guild)[] = [
name: true, "name",
description: true, "description",
region: true, "region",
verification_level: true, "verification_level",
default_message_notifications: true, "default_message_notifications",
explicit_content_filter: true, "explicit_content_filter",
preferred_locale: true, "preferred_locale",
afk_timeout: true, "afk_timeout",
roles: true, "roles",
channels: true, "channels",
afk_channel_id: true, "afk_channel_id",
system_channel_id: true, "system_channel_id",
system_channel_flags: true, "system_channel_flags",
icon_hash: true "icon"
}; ];
router.get("/", async (req: Request, res: Response) => { router.get("/", async (req: Request, res: Response) => {
const { guild_id } = req.params; const { guild_id } = req.params;
@ -34,14 +34,14 @@ router.get("/", async (req: Request, res: Response) => {
router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response) => { router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response) => {
const { guild_id } = req.params; const { guild_id } = req.params;
const guild = await Guild.findOneOrFail({ id: guild_id }, TemplateGuildProjection); const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: TemplateGuildProjection });
const perms = await getPermission(req.user_id, guild_id); const perms = await getPermission(req.user_id, guild_id);
perms.hasThrow("MANAGE_GUILD"); perms.hasThrow("MANAGE_GUILD");
const exists = await Template.findOneOrFail({ id: guild_id }).catch((e) => {}); const exists = await Template.findOneOrFail({ id: guild_id }).catch((e) => {});
if (exists) throw new HTTPError("Template already exists", 400); if (exists) throw new HTTPError("Template already exists", 400);
const template = await new TemplateModel({ const template = await new Template({
...req.body, ...req.body,
code: generateCode(), code: generateCode(),
creator_id: req.user_id, creator_id: req.user_id,
@ -51,7 +51,7 @@ router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response
serialized_source_guild: guild serialized_source_guild: guild
}).save(); }).save();
res.json(template)).send(; res.json(template);
}); });
router.delete("/:code", async (req: Request, res: Response) => { router.delete("/:code", async (req: Request, res: Response) => {
@ -61,37 +61,39 @@ router.delete("/:code", async (req: Request, res: Response) => {
const perms = await getPermission(req.user_id, guild_id); const perms = await getPermission(req.user_id, guild_id);
perms.hasThrow("MANAGE_GUILD"); perms.hasThrow("MANAGE_GUILD");
const template = await Template.findOneOrFailAndDelete({ const template = await Template.delete({
code code
}); });
res.send(template); res.json(template);
}); });
router.put("/:code", async (req: Request, res: Response) => { router.put("/:code", async (req: Request, res: Response) => {
const guild_id = req.params.guild_id; // synchronizes the template
const { code } = req.params; const { code, guild_id } = req.params;
const guild = await Guild.findOneOrFail({ id: guild_id }, TemplateGuildProjection); const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: TemplateGuildProjection });
const perms = await getPermission(req.user_id, guild_id); const perms = await getPermission(req.user_id, guild_id);
perms.hasThrow("MANAGE_GUILD"); perms.hasThrow("MANAGE_GUILD");
const template = await Template.findOneOrFailAndUpdate({ code }, { serialized_source_guild: guild }, { new: true }); const template = await new Template({ code, serialized_source_guild: guild }).save();
res.json(template)).send(; res.json(template);
}); });
router.patch("/:code", check(TemplateModifySchema), async (req: Request, res: Response) => { router.patch("/:code", check(TemplateModifySchema), async (req: Request, res: Response) => {
// updates the template description
const { guild_id } = req.params; const { guild_id } = req.params;
const { code } = req.params; const { code } = req.params;
const { name, description } = req.body;
const perms = await getPermission(req.user_id, guild_id); const perms = await getPermission(req.user_id, guild_id);
perms.hasThrow("MANAGE_GUILD"); perms.hasThrow("MANAGE_GUILD");
const template = await Template.findOneOrFailAndUpdate({ code }, { name: req.body.name, description: req.body.description }, { new: true }); const template = await new Template({ code, name: name, description: description }).save();
res.json(template)).send(; res.json(template);
}); });
export default router; export default router;

View File

@ -1,9 +1,8 @@
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
const router: Router = Router(); const router: Router = Router();
import { TemplateModel, Guild, toObject, User, Role, Snowflake, Guild, Config } from "@fosscord/util"; import { Template, Guild, Role, Snowflake, Config, User } from "@fosscord/util";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { GuildTemplateCreateSchema } from "../../../schema/Guild"; import { GuildTemplateCreateSchema } from "../../../schema/Guild";
import { getPublicUser } from "../../../util/User";
import { check } from "../../../util/instanceOf"; import { check } from "../../../util/instanceOf";
import { addMember } from "../../../util/Member"; import { addMember } from "../../../util/Member";
@ -12,7 +11,7 @@ router.get("/:code", async (req: Request, res: Response) => {
const template = await Template.findOneOrFail({ code: code }); const template = await Template.findOneOrFail({ code: code });
res.json(template)).send(; res.json(template);
}); });
router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res: Response) => { router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res: Response) => {
@ -20,7 +19,7 @@ router.post("/:code", check(GuildTemplateCreateSchema), async (req: Request, res
const body = req.body as GuildTemplateCreateSchema; const body = req.body as GuildTemplateCreateSchema;
const { maxGuilds } = Config.get().limits.user; const { maxGuilds } = Config.get().limits.user;
const user = await getPublicUser(req.user_id, { guilds: true }); const user = await User.getPublicUser(req.user_id, { guilds: true });
if (user.guilds.length >= maxGuilds) { if (user.guilds.length >= maxGuilds) {
throw new HTTPError(`Maximum number of guilds reached ${maxGuilds}`, 403); throw new HTTPError(`Maximum number of guilds reached ${maxGuilds}`, 403);

View File

@ -1,5 +1,5 @@
import { Router, Request, Response } from "express"; import { Router, Request, Response } from "express";
import { getPermission, Guild, InviteModel, toObject } from "@fosscord/util"; import { getPermission, Guild, Invite } from "@fosscord/util";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { addMember } from "../../util/Member"; import { addMember } from "../../util/Member";
const router: Router = Router(); const router: Router = Router();
@ -40,7 +40,7 @@ router.delete("/:code", async (req: Request, res: Response) => {
await Guild.update({ vanity_url_code: code }, { $unset: { vanity_url_code: 1 } }).catch((e) => {}); await Guild.update({ vanity_url_code: code }, { $unset: { vanity_url_code: 1 } }).catch((e) => {});
res.status(200).send({ invite: invite) }; res.json({ invite: invite });
}); });
export default router; export default router;

View File

@ -7,7 +7,7 @@ router.get("/", async (req: Request, res: Response) => {
const user = await getPublicUser(req.params.id, { data: true }); const user = await getPublicUser(req.params.id, { data: true });
res.json({ res.json({
connected_accounts: user.data.connected_accounts, connected_accounts: user.connected_accounts,
premium_guild_since: null, // TODO premium_guild_since: null, // TODO
premium_since: null, // TODO premium_since: null, // TODO
user: { user: {

View File

@ -15,14 +15,14 @@ import { check, Length } from "../../../util/instanceOf";
const router = Router(); const router = Router();
const userProjection = { "user_data.relationships": true, ...PublicUserProjection }; const userProjection = { "data.relationships": true, ...PublicUserProjection };
router.get("/", async (req: Request, res: Response) => { router.get("/", async (req: Request, res: Response) => {
const user = await User.findOneOrFail({ id: req.user_id }, { user_data: { relationships: true } }).populate({ const user = await User.findOneOrFail({ id: req.user_id }, { data: { relationships: true } }).populate({
path: "user_data.relationships.id", path: "data.relationships.id",
model: User model: User
}); });
return res.json(user.user_data.relationships); return res.json(user.data.relationships);
}); });
async function addRelationship(req: Request, res: Response, friend: UserDocument, type: RelationshipType) { async function addRelationship(req: Request, res: Response, friend: UserDocument, type: RelationshipType) {
@ -30,8 +30,8 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend"); if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend");
const user = await User.findOneOrFail({ id: req.user_id }, userProjection); const user = await User.findOneOrFail({ id: req.user_id }, userProjection);
const newUserRelationships = [...user.user_data.relationships]; const newUserRelationships = [...user.data.relationships];
const newFriendRelationships = [...friend.user_data.relationships]; const newFriendRelationships = [...friend.data.relationships];
var relationship = newUserRelationships.find((x) => x.id === id); var relationship = newUserRelationships.find((x) => x.id === id);
const friendRequest = newFriendRelationships.find((x) => x.id === req.user_id); const friendRequest = newFriendRelationships.find((x) => x.id === req.user_id);
@ -48,7 +48,7 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
if (friendRequest && friendRequest.type !== RelationshipType.blocked) { if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
newFriendRelationships.remove(friendRequest); newFriendRelationships.remove(friendRequest);
await Promise.all([ await Promise.all([
User.update({ id: friend.id }, { "user_data.relationships": newFriendRelationships }), User.update({ id: friend.id }, { "data.relationships": newFriendRelationships }),
emitEvent({ emitEvent({
event: "RELATIONSHIP_REMOVE", event: "RELATIONSHIP_REMOVE",
data: friendRequest, data: friendRequest,
@ -58,12 +58,12 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
} }
await Promise.all([ await Promise.all([
User.update({ id: req.user_id }, { "user_data.relationships": newUserRelationships }), User.update({ id: req.user_id }, { "data.relationships": newUserRelationships }),
emitEvent({ emitEvent({
event: "RELATIONSHIP_ADD", event: "RELATIONSHIP_ADD",
data: { data: {
...relationship, ...relationship,
user: { ...friend, user_data: undefined } user: { ...friend, data: undefined }
}, },
user_id: req.user_id user_id: req.user_id
} as RelationshipAddEvent) } as RelationshipAddEvent)
@ -91,13 +91,13 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
} else newUserRelationships.push(outgoing_relationship); } else newUserRelationships.push(outgoing_relationship);
await Promise.all([ await Promise.all([
User.update({ id: req.user_id }, { "user_data.relationships": newUserRelationships }), User.update({ id: req.user_id }, { "data.relationships": newUserRelationships }),
User.update({ id: friend.id }, { "user_data.relationships": newFriendRelationships }), User.update({ id: friend.id }, { "data.relationships": newFriendRelationships }),
emitEvent({ emitEvent({
event: "RELATIONSHIP_ADD", event: "RELATIONSHIP_ADD",
data: { data: {
...outgoing_relationship, ...outgoing_relationship,
user: { ...friend, user_data: undefined } user: { ...friend, data: undefined }
}, },
user_id: req.user_id user_id: req.user_id
} as RelationshipAddEvent), } as RelationshipAddEvent),
@ -106,7 +106,7 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument
data: { data: {
...incoming_relationship, ...incoming_relationship,
should_notify: true, should_notify: true,
user: { ...user, user_data: undefined } user: { ...user, data: undefined }
}, },
user_id: id user_id: id
} as RelationshipAddEvent) } as RelationshipAddEvent)
@ -138,11 +138,11 @@ router.delete("/:id", async (req: Request, res: Response) => {
const friend = await User.findOneOrFail({ id }, userProjection); const friend = await User.findOneOrFail({ id }, userProjection);
if (!friend) throw new HTTPError("User not found", 404); if (!friend) throw new HTTPError("User not found", 404);
const relationship = user.user_data.relationships.find((x) => x.id === id); const relationship = user.data.relationships.find((x) => x.id === id);
const friendRequest = friend.user_data.relationships.find((x) => x.id === req.user_id); const friendRequest = friend.data.relationships.find((x) => x.id === req.user_id);
if (relationship?.type === RelationshipType.blocked) { if (relationship?.type === RelationshipType.blocked) {
// unblock user // unblock user
user.user_data.relationships.remove(relationship); user.data.relationships.remove(relationship);
await Promise.all([ await Promise.all([
user.save(), user.save(),
@ -153,8 +153,8 @@ router.delete("/:id", async (req: Request, res: Response) => {
if (!relationship || !friendRequest) throw new HTTPError("You are not friends with the user", 404); if (!relationship || !friendRequest) throw new HTTPError("You are not friends with the user", 404);
if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you"); if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you");
user.user_data.relationships.remove(relationship); user.data.relationships.remove(relationship);
friend.user_data.relationships.remove(friendRequest); friend.data.relationships.remove(friendRequest);
await Promise.all([ await Promise.all([
user.save(), user.save(),

View File

@ -57,7 +57,7 @@ export async function createChannel(
recipient_ids: null recipient_ids: null
}).save(); }).save();
await emitEvent({ event: "CHANNEL_CREATE", data: channel), guild_id: channel.guild_id } as ChannelCreateEvent; await emitEvent({ event: "CHANNEL_CREATE", data: channel, guild_id: channel.guild_id } as ChannelCreateEvent);
return channel; return channel;
} }

View File

@ -1,16 +0,0 @@
import { toObject, User, PublicUserProjection } from "@fosscord/util";
import { HTTPError } from "lambert-server";
export { PublicUserProjection };
export async function getPublicUser(user_id: string, additional_fields?: any) {
const user = await User.findOneOrFail(
{ id: user_id },
{
...PublicUserProjection,
...additional_fields
}
);
if (!user) throw new HTTPError("User not found", 404);
return user;
}

View File

@ -0,0 +1 @@
test("works", () => {});