diff --git a/package.json b/package.json index d0d9fe54..66b3b235 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "revolt.js", - "version": "6.0.9", + "version": "6.0.10", "main": "dist/index.js", "typings": "dist/index.d.ts", "module": "esm/index.js", diff --git a/src/maps/Members.ts b/src/maps/Members.ts index 07e72f4a..f45a844e 100644 --- a/src/maps/Members.ts +++ b/src/maps/Members.ts @@ -10,7 +10,7 @@ import type { File } from "revolt-api"; import { makeAutoObservable, runInAction, action, computed } from "mobx"; import isEqual from "lodash.isequal"; -import { Nullable, toNullable } from "../util/null"; +import { Nullable, toNullable, toNullableDate } from "../util/null"; import Collection from "./Collection"; import { Channel, Client, FileArgs, Server } from ".."; import { bitwiseAndEq, calculatePermission } from "../permissions/calculator"; @@ -20,10 +20,12 @@ export class Member { client: Client; _id: MemberCompositeKey; + joined_at: Date; nickname: Nullable = null; avatar: Nullable = null; roles: Nullable = null; + timeout: Nullable = null; /** * Associated user. @@ -50,23 +52,25 @@ export class Member { * Whether the client can kick this user. */ get kickable() { - return this.server?.havePermission('KickMembers') && this.inferior; + return this.server?.havePermission("KickMembers") && this.inferior; } /** * Whether the client can ban this user. */ get bannable() { - return this.server?.havePermission('BanMembers') && this.inferior; + return this.server?.havePermission("BanMembers") && this.inferior; } constructor(client: Client, data: MemberI) { this.client = client; this._id = data._id; + this.joined_at = new Date(data.joined_at); this.nickname = toNullable(data.nickname); this.avatar = toNullable(data.avatar); this.roles = toNullable(data.roles); + this.timeout = toNullableDate(data.timeout); makeAutoObservable(this, { _id: false, @@ -96,12 +100,19 @@ export class Member { case "Avatar": this.avatar = null; break; + case "Roles": + this.roles = []; + break; + case "Timeout": + this.timeout = null; + break; } } apply("nickname"); apply("avatar"); apply("roles"); + apply("timeout"); } /** diff --git a/src/maps/Messages.ts b/src/maps/Messages.ts index 7270b763..08b326e4 100644 --- a/src/maps/Messages.ts +++ b/src/maps/Messages.ts @@ -33,8 +33,8 @@ export class Message { mention_ids: Nullable; reply_ids: Nullable; masquerade: Nullable; - // reactions: Record>; - // interactions: Nullable; + reactions: Record; + interactions: Nullable; get channel() { return this.client.channels.get(this.channel_id); @@ -132,6 +132,8 @@ export class Message { this.mention_ids = toNullable(data.mentions); this.reply_ids = toNullable(data.replies); this.masquerade = toNullable(data.masquerade); + this.reactions = data.reactions ?? {}; + this.interactions = toNullable(data.interactions); makeAutoObservable(this, { _id: false, @@ -166,6 +168,9 @@ export class Message { apply("edited", undefined, toNullableDate as (obj: unknown) => unknown); apply("embeds"); apply("mentions", "mention_ids"); + apply("masquerade"); + apply("reactions"); + apply("interactions"); } @action append({ embeds }: Pick, "embeds">) { diff --git a/src/permissions/calculator.ts b/src/permissions/calculator.ts index d396d2f3..ad49af1f 100644 --- a/src/permissions/calculator.ts +++ b/src/permissions/calculator.ts @@ -1,6 +1,7 @@ import Long from "long"; import { Channel, Server, Member } from ".."; import { + ALLOW_IN_TIMEOUT, DEFAULT_PERMISSION_DIRECT_MESSAGE, DEFAULT_PERMISSION_VIEW_ONLY, Permission, @@ -46,7 +47,7 @@ export function calculatePermission( target.client.members.getKey({ user: user!._id, server: target._id, - }) ?? { roles: null }; + }) ?? { roles: null, timeout: null }; if (!member) return 0; @@ -67,6 +68,11 @@ export function calculatePermission( } } + // 5. Revoke permissions if member is timed out. + if (member.timeout && member.timeout > new Date()) { + perm = perm.and(ALLOW_IN_TIMEOUT); + } + return perm.toNumber(); } } else { @@ -111,7 +117,7 @@ export function calculatePermission( target.client.members.getKey({ user: user!._id, server: server._id, - }) ?? { roles: null }; + }) ?? { roles: null, timeout: null }; if (!member) return 0; @@ -150,6 +156,11 @@ export function calculatePermission( } } + // 8. Revoke permissions if member is timed out. + if (member.timeout && member.timeout > new Date()) { + perm = perm.and(ALLOW_IN_TIMEOUT); + } + return perm.toNumber(); } } diff --git a/src/permissions/definitions.ts b/src/permissions/definitions.ts index 1e33e394..2ef9acaf 100644 --- a/src/permissions/definitions.ts +++ b/src/permissions/definitions.ts @@ -22,7 +22,7 @@ export const Permission = { /// Manage roles on server ManageRole: 2 ** 3, /// Manage server customisation (includes emoji) - ManageCustomisation: 2**4, + ManageCustomisation: 2 ** 4, // % 1 bits reserved @@ -65,8 +65,8 @@ export const Permission = { UploadFiles: 2 ** 27, /// Masquerade messages using custom nickname and avatar Masquerade: 2 ** 28, - - // % 1 bits reserved + /// React to messages with emoji + React: 2 ** 29, // * Voice permissions /// Connect to a voice channel @@ -96,6 +96,12 @@ export const Permission = { */ export const U32_MAX = 2 ** 32 - 1; // 4294967295 +/** + * Permissions allowed for a user while in timeout + */ +export const ALLOW_IN_TIMEOUT = + Permission.ViewChannel + Permission.ReadMessageHistory; + /** * Default permissions if we can only view */