From 0ecc5d8c0e353676e9f5bdbc724bb33572d3b572 Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Fri, 27 Aug 2021 11:10:42 +0200 Subject: [PATCH] :construction: api --- api/__tests__/routes/auth/login.ts | 1 - api/jest.config.ts | 4 +- api/package-lock.json | Bin 710581 -> 745991 bytes api/package.json | 6 +- api/scripts/setup_test.js | 1 + api/src/middlewares/ErrorHandler.ts | 1 + api/src/routes/auth/login.ts | 12 ++-- api/src/routes/auth/register.ts | 59 +++++++----------- api/src/routes/guilds/#guild_id/channels.ts | 12 ++-- api/src/routes/guilds/#guild_id/templates.ts | 60 ++++++++++--------- api/src/routes/guilds/templates/index.ts | 7 +-- api/src/routes/invites/index.ts | 4 +- api/src/routes/users/#id/profile.ts | 2 +- api/src/routes/users/@me/relationships.ts | 36 +++++------ api/src/util/Channel.ts | 2 +- api/src/util/User.ts | 16 ----- api/tests/routes/auth/login.ts | 1 + 17 files changed, 97 insertions(+), 127 deletions(-) delete mode 100644 api/__tests__/routes/auth/login.ts create mode 100644 api/scripts/setup_test.js delete mode 100644 api/src/util/User.ts create mode 100644 api/tests/routes/auth/login.ts diff --git a/api/__tests__/routes/auth/login.ts b/api/__tests__/routes/auth/login.ts deleted file mode 100644 index 536e03ee..00000000 --- a/api/__tests__/routes/auth/login.ts +++ /dev/null @@ -1 +0,0 @@ -it("works", () => {}); diff --git a/api/jest.config.ts b/api/jest.config.ts index 153a9b2b..50550d9d 100644 --- a/api/jest.config.ts +++ b/api/jest.config.ts @@ -145,9 +145,9 @@ export default { // The glob patterns Jest uses to detect test files testMatch: [ - "**/__tests__/**/*.[jt]s?(x)", + "**/tests/**/*.[jt]s?(x)" // "**/?(*.)+(spec|test).[tj]s?(x)" - ], + ] // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped // testPathIgnorePatterns: [ diff --git a/api/package-lock.json b/api/package-lock.json index 3221969aad5a09a1ab5e43ac85d93ea5528cc8c4..bff4e940a650cbd1c7c3030556b7237df0d274a3 100644 GIT binary patch delta 15397 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 delta 911 zcma)(eQZ-@7{znnzW2Q!g-co2mKHk425c}p8%NwEYU(5bU1cG#5Jv`G2t)S8Tt(s* z#+(U@6bf<|_L-8$dZf&Z~ zTalZ$>Dl6NaS5gy#a1gvdz`Qe4@UhE4Z=Ws!r`%2T}pe+yqjM9k`#|HRL17vz*=dx z)%{&Z&`ex(!L>myGxyBMX2-bzI;RDr3uOYMgQF*n@47Rr=@g=gp!n7d8FP zgA(0eE*;uVfA>fYpCB1!1=Lx|1{8BXiV(iSgD{rJ3hmy&_DWdMDZ6lDt`wx)H&|JO zb{=6L&i^ktc9!R&s!Li%(F?54z;uMEX3OFQh^?1v(DD`Ih+kzx7+t67=*(uXkbSE( z=x&nv0#C|x2WJ=sXB=UM*aHWrQ)$OH6^O?rKPIZBXAl|Fwjp)a;lo6La}11W`EXTn zgPO|u?JBA{%ug#AnJd3eD^K!=rIh~zZ*yThM={V_FBc$uThef*M#{p_pu*9zQJ1l_ zUv|?UQ@pPpAJxf=GL7fZc$K^>KxV7lUP^xr%jaLFm5Ok3`%U&zf0kIIQddy;D*q=_ zvYFlr(bq@CW8V{?=Bi6~Fw`URG4Yx3m^%m3Fvf&J#$|EYO*fNb#Bcs{U*MKU$)?YL z6;l$u`kQ!7qC{G}Q-X;S$=0IGO?shns)j!OSdkB85c=#I_1Pvgy~5AtS!JC(ltDFmATRTf$(NFnT;d+ zwSI)(7Y6OwtFD_xBc{r1k4)aTr&Z4+Qu{PcCHpirLJvo^Srw%C^y>mY7U%&~-W48H zpXB#wGDjbNn%biJIRn>nlst-T)EhTpf1TYh{GRHj!G8Uohk9=4+l#5$<(w>|h6?8w z4s(&^g*|-|C)SEA?Cw@n>T!#534=%Vd6Zl39A&h++W7*5jpk9tE1OcAoj&$2-pgLJ diff --git a/api/package.json b/api/package.json index 7b2de011..1310d577 100644 --- a/api/package.json +++ b/api/package.json @@ -5,7 +5,7 @@ "main": "dist/Server.js", "types": "dist/Server.d.ts", "scripts": { - "test": "jest", + "test": "npm run build && jest", "test:watch": "jest --watch", "start": "npm run build && node dist/start", "build": "npx tsc -b .", @@ -35,6 +35,7 @@ "@types/bcrypt": "^5.0.0", "@types/express": "^4.17.9", "@types/i18next-node-fs-backend": "^2.1.0", + "@types/jest": "^27.0.1", "@types/jsonwebtoken": "^8.5.0", "@types/mongodb": "^3.6.9", "@types/mongoose": "^5.10.5", @@ -79,6 +80,7 @@ "mongoose-autopopulate": "^0.12.3", "mongoose-long": "^0.3.2", "multer": "^1.4.2", - "node-fetch": "^2.6.1" + "node-fetch": "^2.6.1", + "typeorm": "^0.2.37" } } diff --git a/api/scripts/setup_test.js b/api/scripts/setup_test.js new file mode 100644 index 00000000..4b692f7c --- /dev/null +++ b/api/scripts/setup_test.js @@ -0,0 +1 @@ +// TODO: start api diff --git a/api/src/middlewares/ErrorHandler.ts b/api/src/middlewares/ErrorHandler.ts index d080e498..8e2cd923 100644 --- a/api/src/middlewares/ErrorHandler.ts +++ b/api/src/middlewares/ErrorHandler.ts @@ -2,6 +2,7 @@ import { NextFunction, Request, Response } from "express"; import { HTTPError } from "lambert-server"; import { FieldError } from "../util/instanceOf"; +// TODO: update with new body/typorm validation export function ErrorHandler(error: Error, req: Request, res: Response, next: NextFunction) { if (!error) next(); diff --git a/api/src/routes/auth/login.ts b/api/src/routes/auth/login.ts index 579a097e..c0acad4e 100644 --- a/api/src/routes/auth/login.ts +++ b/api/src/routes/auth/login.ts @@ -21,9 +21,6 @@ router.post( async (req: Request, res: Response) => { const { login, password, captcha_key, undelete } = req.body; const email = adjustEmail(login); - const query: any[] = [{ phone: login }]; - if (email) query.push({ email }); - console.log(req.body, email); const config = Config.get(); @@ -41,11 +38,10 @@ router.post( // TODO: check captcha } - const user = await User.findOneOrFail( - { $or: query }, - { "data.hash": true, id: true, disabled: true, deleted: true, "settings.locale": true, "settings.theme": true } - ).catch((e) => { - console.log(e, query); + const user = await User.findOneOrFail({ + where: [{ phone: login }, { email: login }], + select: ["data", "id", "disabled", "deleted", "settings"] + }).catch((e) => { throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } }); }); diff --git a/api/src/routes/auth/register.ts b/api/src/routes/auth/register.ts index 1405e219..62b039d5 100644 --- a/api/src/routes/auth/register.ts +++ b/api/src/routes/auth/register.ts @@ -1,12 +1,12 @@ 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 { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf"; import "missing-native-js-functions"; import { generateToken } from "./login"; import { getIpAdress, IPAnalysis, isProxy } from "../../util/ipAddress"; import { HTTPError } from "lambert-server"; -import RateLimit from "../../middlewares/RateLimit"; +import { In } from "typeorm"; const router: Router = Router(); @@ -55,13 +55,13 @@ router.post( // TODO: check password strength // 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 - let adjusted_password: string = ""; + let adjusted_password = ""; // trim special uf8 control characters -> Backspace, Newline, ... - let adjusted_username: string = trimSpecial(username); + let adjusted_username = trimSpecial(username); // discriminator will be randomly generated let discriminator = ""; @@ -129,7 +129,7 @@ router.post( if (!register.allowMultipleAccounts) { // 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) { 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? for (let tries = 0; tries < 5; tries++) { discriminator = Math.randomIntBetween(1, 9999).toString().padStart(4, "0"); - try { - exists = await User.findOneOrFail({ discriminator, username: adjusted_username }, "id"); - } catch (error) { - // doesn't exist -> break - break; - } + exists = await User.findOne({ where: { discriminator, username: adjusted_username }, select: ["id"] }); + if (!exists) break; } if (exists) { @@ -185,35 +181,26 @@ router.post( // 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 - const user: User = { + const user = await new User({ id: Snowflake.generate(), created_at: new Date(), username: adjusted_username, discriminator, - avatar: null, - accent_color: null, - banner: null, + avatar: undefined, + accent_color: undefined, + banner: undefined, bot: false, system: false, desktop: false, mobile: false, premium: true, premium_type: 2, - phone: null, + phone: undefined, bio: "", mfa_enabled: false, verified: false, disabled: false, deleted: false, - presence: { - activities: [], - client_status: { - desktop: undefined, - mobile: undefined, - web: undefined - }, - status: "offline" - }, email: adjusted_email, nsfw_allowed: true, // TODO: depending on age public_flags: 0n, @@ -221,10 +208,7 @@ router.post( guilds: [], data: { hash: adjusted_password, - valid_tokens_since: new Date(), - relationships: [], - connected_accounts: [], - fingerprints: [] + valid_tokens_since: new Date() }, settings: { afk_timeout: 300, @@ -234,10 +218,10 @@ router.post( contact_sync_enabled: false, convert_emoticons: false, custom_status: { - emoji_id: null, - emoji_name: null, - expires_at: null, - text: null + emoji_id: undefined, + emoji_name: undefined, + expires_at: undefined, + text: undefined }, default_guilds_restricted: false, detect_platform_accounts: true, @@ -265,16 +249,13 @@ router.post( timezone_offset: 0 // timezone_offset: // TODO: timezone from request } - }; - - // insert user into database - await new User(user).save(); + }).save(); 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 const parts = email.match(EMAIL_REGEX); // @ts-ignore diff --git a/api/src/routes/guilds/#guild_id/channels.ts b/api/src/routes/guilds/#guild_id/channels.ts index b53c9a5a..7b0e94b6 100644 --- a/api/src/routes/guilds/#guild_id/channels.ts +++ b/api/src/routes/guilds/#guild_id/channels.ts @@ -1,5 +1,5 @@ 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 { ChannelModifySchema } from "../../../schema/Channel"; @@ -48,15 +48,19 @@ router.patch( if (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) { 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); }) ]); diff --git a/api/src/routes/guilds/#guild_id/templates.ts b/api/src/routes/guilds/#guild_id/templates.ts index 13917dbd..e1d2f5fd 100644 --- a/api/src/routes/guilds/#guild_id/templates.ts +++ b/api/src/routes/guilds/#guild_id/templates.ts @@ -1,5 +1,5 @@ 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 { TemplateCreateSchema, TemplateModifySchema } from "../../../schema/Template"; import { check } from "../../../util/instanceOf"; @@ -7,22 +7,22 @@ import { generateCode } from "../../../util/String"; const router: Router = Router(); -const TemplateGuildProjection = { - name: true, - description: true, - region: true, - verification_level: true, - default_message_notifications: true, - explicit_content_filter: true, - preferred_locale: true, - afk_timeout: true, - roles: true, - channels: true, - afk_channel_id: true, - system_channel_id: true, - system_channel_flags: true, - icon_hash: true -}; +const TemplateGuildProjection: (keyof Guild)[] = [ + "name", + "description", + "region", + "verification_level", + "default_message_notifications", + "explicit_content_filter", + "preferred_locale", + "afk_timeout", + "roles", + "channels", + "afk_channel_id", + "system_channel_id", + "system_channel_flags", + "icon" +]; router.get("/", async (req: Request, res: Response) => { 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) => { 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); perms.hasThrow("MANAGE_GUILD"); const exists = await Template.findOneOrFail({ id: guild_id }).catch((e) => {}); if (exists) throw new HTTPError("Template already exists", 400); - const template = await new TemplateModel({ + const template = await new Template({ ...req.body, code: generateCode(), creator_id: req.user_id, @@ -51,7 +51,7 @@ router.post("/", check(TemplateCreateSchema), async (req: Request, res: Response serialized_source_guild: guild }).save(); - res.json(template)).send(; + res.json(template); }); 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); perms.hasThrow("MANAGE_GUILD"); - const template = await Template.findOneOrFailAndDelete({ + const template = await Template.delete({ code }); - res.send(template); + res.json(template); }); router.put("/:code", async (req: Request, res: Response) => { - const guild_id = req.params.guild_id; - const { code } = req.params; + // synchronizes the template + 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); 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) => { + // updates the template description const { guild_id } = req.params; const { code } = req.params; + const { name, description } = req.body; const perms = await getPermission(req.user_id, guild_id); 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; diff --git a/api/src/routes/guilds/templates/index.ts b/api/src/routes/guilds/templates/index.ts index ad8b676b..b8c1012d 100644 --- a/api/src/routes/guilds/templates/index.ts +++ b/api/src/routes/guilds/templates/index.ts @@ -1,9 +1,8 @@ import { Request, Response, Router } from "express"; 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 { GuildTemplateCreateSchema } from "../../../schema/Guild"; -import { getPublicUser } from "../../../util/User"; import { check } from "../../../util/instanceOf"; import { addMember } from "../../../util/Member"; @@ -12,7 +11,7 @@ router.get("/:code", async (req: Request, res: Response) => { const template = await Template.findOneOrFail({ code: code }); - res.json(template)).send(; + res.json(template); }); 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 { 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) { throw new HTTPError(`Maximum number of guilds reached ${maxGuilds}`, 403); diff --git a/api/src/routes/invites/index.ts b/api/src/routes/invites/index.ts index e871af86..a488c44b 100644 --- a/api/src/routes/invites/index.ts +++ b/api/src/routes/invites/index.ts @@ -1,5 +1,5 @@ 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 { addMember } from "../../util/Member"; 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) => {}); - res.status(200).send({ invite: invite) }; + res.json({ invite: invite }); }); export default router; diff --git a/api/src/routes/users/#id/profile.ts b/api/src/routes/users/#id/profile.ts index 46c96698..9b2e2d5e 100644 --- a/api/src/routes/users/#id/profile.ts +++ b/api/src/routes/users/#id/profile.ts @@ -7,7 +7,7 @@ router.get("/", async (req: Request, res: Response) => { const user = await getPublicUser(req.params.id, { data: true }); res.json({ - connected_accounts: user.data.connected_accounts, + connected_accounts: user.connected_accounts, premium_guild_since: null, // TODO premium_since: null, // TODO user: { diff --git a/api/src/routes/users/@me/relationships.ts b/api/src/routes/users/@me/relationships.ts index 9b8d6199..8c7469ed 100644 --- a/api/src/routes/users/@me/relationships.ts +++ b/api/src/routes/users/@me/relationships.ts @@ -15,14 +15,14 @@ import { check, Length } from "../../../util/instanceOf"; const router = Router(); -const userProjection = { "user_data.relationships": true, ...PublicUserProjection }; +const userProjection = { "data.relationships": true, ...PublicUserProjection }; router.get("/", async (req: Request, res: Response) => { - const user = await User.findOneOrFail({ id: req.user_id }, { user_data: { relationships: true } }).populate({ - path: "user_data.relationships.id", + const user = await User.findOneOrFail({ id: req.user_id }, { data: { relationships: true } }).populate({ + path: "data.relationships.id", 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) { @@ -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"); const user = await User.findOneOrFail({ id: req.user_id }, userProjection); - const newUserRelationships = [...user.user_data.relationships]; - const newFriendRelationships = [...friend.user_data.relationships]; + const newUserRelationships = [...user.data.relationships]; + const newFriendRelationships = [...friend.data.relationships]; var relationship = newUserRelationships.find((x) => x.id === 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) { newFriendRelationships.remove(friendRequest); await Promise.all([ - User.update({ id: friend.id }, { "user_data.relationships": newFriendRelationships }), + User.update({ id: friend.id }, { "data.relationships": newFriendRelationships }), emitEvent({ event: "RELATIONSHIP_REMOVE", data: friendRequest, @@ -58,12 +58,12 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument } await Promise.all([ - User.update({ id: req.user_id }, { "user_data.relationships": newUserRelationships }), + User.update({ id: req.user_id }, { "data.relationships": newUserRelationships }), emitEvent({ event: "RELATIONSHIP_ADD", data: { ...relationship, - user: { ...friend, user_data: undefined } + user: { ...friend, data: undefined } }, user_id: req.user_id } as RelationshipAddEvent) @@ -91,13 +91,13 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument } else newUserRelationships.push(outgoing_relationship); await Promise.all([ - User.update({ id: req.user_id }, { "user_data.relationships": newUserRelationships }), - User.update({ id: friend.id }, { "user_data.relationships": newFriendRelationships }), + User.update({ id: req.user_id }, { "data.relationships": newUserRelationships }), + User.update({ id: friend.id }, { "data.relationships": newFriendRelationships }), emitEvent({ event: "RELATIONSHIP_ADD", data: { ...outgoing_relationship, - user: { ...friend, user_data: undefined } + user: { ...friend, data: undefined } }, user_id: req.user_id } as RelationshipAddEvent), @@ -106,7 +106,7 @@ async function addRelationship(req: Request, res: Response, friend: UserDocument data: { ...incoming_relationship, should_notify: true, - user: { ...user, user_data: undefined } + user: { ...user, data: undefined } }, user_id: id } as RelationshipAddEvent) @@ -138,11 +138,11 @@ router.delete("/:id", async (req: Request, res: Response) => { const friend = await User.findOneOrFail({ id }, userProjection); if (!friend) throw new HTTPError("User not found", 404); - const relationship = user.user_data.relationships.find((x) => x.id === id); - const friendRequest = friend.user_data.relationships.find((x) => x.id === req.user_id); + const relationship = user.data.relationships.find((x) => x.id === id); + const friendRequest = friend.data.relationships.find((x) => x.id === req.user_id); if (relationship?.type === RelationshipType.blocked) { // unblock user - user.user_data.relationships.remove(relationship); + user.data.relationships.remove(relationship); await Promise.all([ 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 (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you"); - user.user_data.relationships.remove(relationship); - friend.user_data.relationships.remove(friendRequest); + user.data.relationships.remove(relationship); + friend.data.relationships.remove(friendRequest); await Promise.all([ user.save(), diff --git a/api/src/util/Channel.ts b/api/src/util/Channel.ts index a618d2df..f518aefd 100644 --- a/api/src/util/Channel.ts +++ b/api/src/util/Channel.ts @@ -57,7 +57,7 @@ export async function createChannel( recipient_ids: null }).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; } diff --git a/api/src/util/User.ts b/api/src/util/User.ts deleted file mode 100644 index 4d9065c4..00000000 --- a/api/src/util/User.ts +++ /dev/null @@ -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; -} diff --git a/api/tests/routes/auth/login.ts b/api/tests/routes/auth/login.ts new file mode 100644 index 00000000..e1938b36 --- /dev/null +++ b/api/tests/routes/auth/login.ts @@ -0,0 +1 @@ +test("works", () => {});