diff options
author | Hayden Young <hi@hbjy.dev> | 2021-10-15 10:33:02 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-15 10:33:02 +0000 |
commit | 365f15f03686f51014a8cc3200a0cbb3e03cc84a (patch) | |
tree | 0aab701def5b292d26bdabe6a507ee6b71a6332e /api/src | |
parent | chore: update ts-node during npm run setup (diff) | |
parent | Merge pull request #460 from fosscord/dev (diff) | |
download | server-365f15f03686f51014a8cc3200a0cbb3e03cc84a.tar.xz |
Merge branch 'master' into cdn-s3
Diffstat (limited to 'api/src')
-rw-r--r-- | api/src/middlewares/Authentication.ts | 2 | ||||
-rw-r--r-- | api/src/routes/-/healthz.ts | 17 | ||||
-rw-r--r-- | api/src/routes/-/readyz.ts | 17 | ||||
-rw-r--r-- | api/src/routes/channels/#channel_id/messages/index.ts | 42 | ||||
-rw-r--r-- | api/src/routes/guilds/#guild_id/prune.ts | 82 | ||||
-rw-r--r-- | api/src/util/Instance.ts | 8 |
6 files changed, 144 insertions, 24 deletions
diff --git a/api/src/middlewares/Authentication.ts b/api/src/middlewares/Authentication.ts index 5a082751..59a181e6 100644 --- a/api/src/middlewares/Authentication.ts +++ b/api/src/middlewares/Authentication.ts @@ -9,6 +9,8 @@ export const NO_AUTHORIZATION_ROUTES = [ "/ping", "/gateway", "/experiments", + "/-/readyz", + "/-/healthz", /\/guilds\/\d+\/widget\.(json|png)/ ]; diff --git a/api/src/routes/-/healthz.ts b/api/src/routes/-/healthz.ts new file mode 100644 index 00000000..a42575f8 --- /dev/null +++ b/api/src/routes/-/healthz.ts @@ -0,0 +1,17 @@ +import { Router, Response, Request } from "express"; +import { route } from "@fosscord/api"; +import { getConnection } from "typeorm"; + +const router = Router(); + +router.get("/", route({}), (req: Request, res: Response) => { + try { + // test that the database is alive & responding + getConnection(); + return res.sendStatus(200); + } catch(e) { + res.sendStatus(503); + } +}); + +export default router; diff --git a/api/src/routes/-/readyz.ts b/api/src/routes/-/readyz.ts new file mode 100644 index 00000000..a42575f8 --- /dev/null +++ b/api/src/routes/-/readyz.ts @@ -0,0 +1,17 @@ +import { Router, Response, Request } from "express"; +import { route } from "@fosscord/api"; +import { getConnection } from "typeorm"; + +const router = Router(); + +router.get("/", route({}), (req: Request, res: Response) => { + try { + // test that the database is alive & responding + getConnection(); + return res.sendStatus(200); + } catch(e) { + res.sendStatus(503); + } +}); + +export default router; diff --git a/api/src/routes/channels/#channel_id/messages/index.ts b/api/src/routes/channels/#channel_id/messages/index.ts index 26bb9e5d..b5a2d334 100644 --- a/api/src/routes/channels/#channel_id/messages/index.ts +++ b/api/src/routes/channels/#channel_id/messages/index.ts @@ -10,7 +10,8 @@ import { getPermission, Message, MessageCreateEvent, - uploadFile + uploadFile, + Member } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { handleMessage, postHandleMessage, route } from "@fosscord/api"; @@ -186,33 +187,34 @@ router.post( message = await message.save(); - await channel.assign({ last_message_id: message.id }).save(); - if (channel.isDm()) { const channel_dto = await DmChannelDTO.from(channel); - for (let recipient of channel.recipients!) { - if (recipient.closed) { - await emitEvent({ - event: "CHANNEL_CREATE", - data: channel_dto.excludedRecipients([recipient.user_id]), - user_id: recipient.user_id - }); - } - } - //Only one recipients should be closed here, since in group DMs the recipient is deleted not closed + await Promise.all( - channel - .recipients!.filter((r) => r.closed) - .map(async (r) => { - r.closed = false; - return await r.save(); - }) + channel.recipients!.map((recipient) => { + if (recipient.closed) { + recipient.closed = false; + return Promise.all([ + recipient.save(), + emitEvent({ + event: "CHANNEL_CREATE", + data: channel_dto.excludedRecipients([recipient.user_id]), + user_id: recipient.user_id + }) + ]); + } + }) ); } - await emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent); + await Promise.all([ + channel.assign({ last_message_id: message.id }).save(), + new Member({ id: req.user_id, last_message_id: message.id }).save(), + emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent) + ]); + postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error return res.json(message); diff --git a/api/src/routes/guilds/#guild_id/prune.ts b/api/src/routes/guilds/#guild_id/prune.ts new file mode 100644 index 00000000..92809985 --- /dev/null +++ b/api/src/routes/guilds/#guild_id/prune.ts @@ -0,0 +1,82 @@ +import { Router, Request, Response } from "express"; +import { Guild, Member, Snowflake } from "@fosscord/util"; +import { LessThan, IsNull } from "typeorm"; +import { route } from "@fosscord/api"; +const router = Router(); + +//Returns all inactive members, respecting role hierarchy +export const inactiveMembers = async (guild_id: string, user_id: string, days: number, roles: string[] = []) => { + var date = new Date(); + date.setDate(date.getDate() - days); + //Snowflake should have `generateFromTime` method? Or similar? + var minId = BigInt(date.valueOf() - Snowflake.EPOCH) << BigInt(22); + + var members = await Member.find({ + where: [ + { + guild_id, + last_message_id: LessThan(minId.toString()) + }, + { + last_message_id: IsNull() + } + ], + relations: ["roles"] + }); + console.log(members); + if (!members.length) return []; + + //I'm sure I can do this in the above db query ( and it would probably be better to do so ), but oh well. + if (roles.length && members.length) members = members.filter((user) => user.roles?.some((role) => roles.includes(role.id))); + + const me = await Member.findOneOrFail({ id: user_id, guild_id }, { relations: ["roles"] }); + const myHighestRole = Math.max(...(me.roles?.map((x) => x.position) || [])); + + const guild = await Guild.findOneOrFail({ where: { id: guild_id } }); + + members = members.filter( + (member) => + member.id !== guild.owner_id && //can't kick owner + member.roles?.some( + (role) => + role.position < myHighestRole || //roles higher than me can't be kicked + me.id === guild.owner_id //owner can kick anyone + ) + ); + + return members; +}; + +router.get("/", route({ permission: "KICK_MEMBERS" }), async (req: Request, res: Response) => { + const days = parseInt(req.query.days as string); + + var roles = req.query.include_roles; + if (typeof roles === "string") roles = [roles]; //express will return array otherwise + + const members = await inactiveMembers(req.params.guild_id, req.user_id, days, roles as string[]); + + res.send({ pruned: members.length }); +}); + +export interface PruneSchema { + /** + * @min 0 + */ + days: number; +} + +router.post("/", route({ permission: "KICK_MEMBERS" }), async (req: Request, res: Response) => { + const days = parseInt(req.body.days); + + var roles = req.query.include_roles; + if (typeof roles === "string") roles = [roles]; + + const { guild_id } = req.params; + const members = await inactiveMembers(guild_id, req.user_id, days, roles as string[]); + + await Promise.all(members.map((x) => Member.removeFromGuild(x.id, guild_id))); + + res.send({ purged: members.length }); +}); + +export default router; diff --git a/api/src/util/Instance.ts b/api/src/util/Instance.ts index d1d9e1ab..7dcd126e 100644 --- a/api/src/util/Instance.ts +++ b/api/src/util/Instance.ts @@ -10,9 +10,9 @@ export async function initInstance() { if (autoJoin.enabled && !autoJoin.guilds?.length) { let guild = await Guild.findOne({}); - if (!guild) guild = await Guild.createGuild({}); - - // @ts-ignore - await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } }); + if (guild) { + // @ts-ignore + await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } }); + } } } |