mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 11:28:15 +00:00
Merge pull request #159 from Skillz4Killz/rename-permission_overwrites
Rename permission overwrites
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { eventHandlers } from "../module/client.ts";
|
||||
import type { DiscordPayload } from "../types/discord.ts";
|
||||
import type { GuildBanPayload } from "../types/guild.ts";
|
||||
import { DiscordPayload } from "../types/discord.ts";
|
||||
import { GuildBanPayload } from "../types/guild.ts";
|
||||
import { cacheHandlers } from "./cache.ts";
|
||||
|
||||
export async function handleInternalGuildBanAdd(data: DiscordPayload) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Channel } from "../structures/channel.ts";
|
||||
import type { Guild } from "../structures/guild.ts";
|
||||
import type { Message } from "../structures/message.ts";
|
||||
import type { PresenceUpdatePayload } from "../types/discord.ts";
|
||||
import { Channel } from "../structures/channel.ts";
|
||||
import { Guild } from "../structures/guild.ts";
|
||||
import { Message } from "../structures/message.ts";
|
||||
import { PresenceUpdatePayload } from "../types/discord.ts";
|
||||
import { cache } from "../utils/cache.ts";
|
||||
import type { Collection } from "../utils/collection.ts";
|
||||
import { Collection } from "../utils/collection.ts";
|
||||
|
||||
export type TableName =
|
||||
| "guilds"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { eventHandlers } from "../module/client.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { ChannelCreatePayload } from "../types/channel.ts";
|
||||
import { ChannelTypes } from "../types/channel.ts";
|
||||
import type { DiscordPayload } from "../types/discord.ts";
|
||||
import { ChannelCreatePayload, ChannelTypes } from "../types/channel.ts";
|
||||
import { DiscordPayload } from "../types/discord.ts";
|
||||
import { cacheHandlers } from "./cache.ts";
|
||||
|
||||
export async function handleInternalChannelCreate(data: DiscordPayload) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { eventHandlers } from "../module/client.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { DiscordPayload } from "../types/discord.ts";
|
||||
import type {
|
||||
import { DiscordPayload } from "../types/discord.ts";
|
||||
import {
|
||||
CreateGuildPayload,
|
||||
GuildDeletePayload,
|
||||
GuildEmojisUpdatePayload,
|
||||
UpdateGuildPayload,
|
||||
} from "../types/guild.ts";
|
||||
import type { GuildUpdateChange } from "../types/options.ts";
|
||||
import { GuildUpdateChange } from "../types/options.ts";
|
||||
import { cache } from "../utils/cache.ts";
|
||||
import { cacheHandlers } from "./cache.ts";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { eventHandlers } from "../module/client.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { DiscordPayload } from "../types/discord.ts";
|
||||
import type {
|
||||
import { DiscordPayload } from "../types/discord.ts";
|
||||
import {
|
||||
GuildBanPayload,
|
||||
GuildMemberAddPayload,
|
||||
GuildMemberChunkPayload,
|
||||
@@ -41,11 +41,6 @@ export async function handleInternalGuildMemberRemove(data: DiscordPayload) {
|
||||
member || payload.user,
|
||||
);
|
||||
|
||||
eventHandlers.guildMemberRemove?.(
|
||||
guild,
|
||||
member || payload.user,
|
||||
);
|
||||
|
||||
guild.members.delete(payload.user.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { eventHandlers } from "../module/client.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { DiscordPayload } from "../types/discord.ts";
|
||||
import type {
|
||||
import { DiscordPayload } from "../types/discord.ts";
|
||||
import {
|
||||
MessageCreateOptions,
|
||||
MessageDeleteBulkPayload,
|
||||
MessageDeletePayload,
|
||||
@@ -15,9 +15,6 @@ export async function handleInternalMessageCreate(data: DiscordPayload) {
|
||||
const channel = await cacheHandlers.get("channels", payload.channel_id);
|
||||
if (channel) channel.lastMessageID = payload.id;
|
||||
|
||||
const message = await structures.createMessage(payload);
|
||||
// Cache the message
|
||||
cacheHandlers.set("messages", payload.id, message);
|
||||
const guild = payload.guild_id
|
||||
? await cacheHandlers.get("guilds", payload.guild_id)
|
||||
: undefined;
|
||||
@@ -46,6 +43,10 @@ export async function handleInternalMessageCreate(data: DiscordPayload) {
|
||||
}
|
||||
});
|
||||
|
||||
const message = await structures.createMessage(payload);
|
||||
// Cache the message
|
||||
cacheHandlers.set("messages", payload.id, message);
|
||||
|
||||
eventHandlers.messageCreate?.(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { delay } from "../../deps.ts";
|
||||
import { eventHandlers, setBotID } from "../module/client.ts";
|
||||
import { allowNextShard } from "../module/shardingManager.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type {
|
||||
import {
|
||||
DiscordPayload,
|
||||
PresenceUpdatePayload,
|
||||
ReadyPayload,
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
VoiceStateUpdatePayload,
|
||||
WebhookUpdatePayload,
|
||||
} from "../types/discord.ts";
|
||||
import type { UserPayload } from "../types/guild.ts";
|
||||
import { UserPayload } from "../types/guild.ts";
|
||||
import { cache } from "../utils/cache.ts";
|
||||
import { cacheHandlers } from "./cache.ts";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { botID, eventHandlers } from "../module/client.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { DiscordPayload } from "../types/discord.ts";
|
||||
import type {
|
||||
import { DiscordPayload } from "../types/discord.ts";
|
||||
import {
|
||||
BaseMessageReactionPayload,
|
||||
MessageReactionPayload,
|
||||
MessageReactionRemoveEmojiPayload,
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { eventHandlers } from "../module/client.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { DiscordPayload } from "../types/discord.ts";
|
||||
import type {
|
||||
GuildRoleDeletePayload,
|
||||
GuildRolePayload,
|
||||
} from "../types/guild.ts";
|
||||
import { DiscordPayload } from "../types/discord.ts";
|
||||
import { GuildRoleDeletePayload, GuildRolePayload } from "../types/guild.ts";
|
||||
import { cacheHandlers } from "./cache.ts";
|
||||
|
||||
export async function handleInternalGuildRoleCreate(data: DiscordPayload) {
|
||||
@@ -30,6 +27,11 @@ export async function handleInternalGuildRoleDelete(data: DiscordPayload) {
|
||||
const cachedRole = guild.roles.get(payload.role_id)!;
|
||||
guild.roles.delete(payload.role_id);
|
||||
eventHandlers.roleDelete?.(guild, cachedRole);
|
||||
|
||||
// For bots without GUILD_MEMBERS member.roles is never updated breaking permissions checking.
|
||||
guild.members.forEach((member) => {
|
||||
member.roles = member.roles.filter((id) => id !== payload.role_id);
|
||||
});
|
||||
}
|
||||
|
||||
export async function handleInternalGuildRoleUpdate(data: DiscordPayload) {
|
||||
@@ -43,5 +45,6 @@ export async function handleInternalGuildRoleUpdate(data: DiscordPayload) {
|
||||
if (!cachedRole) return;
|
||||
|
||||
const role = await structures.createRole(payload.role);
|
||||
guild.roles.set(payload.role.id, role);
|
||||
eventHandlers.roleUpdate?.(guild, role, cachedRole);
|
||||
}
|
||||
|
||||
+23
-7
@@ -1,8 +1,10 @@
|
||||
import { endpoints } from "../constants/discord.ts";
|
||||
import { cacheHandlers } from "../controllers/cache.ts";
|
||||
import { RequestManager } from "../module/requestManager.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type {
|
||||
import {
|
||||
ChannelEditOptions,
|
||||
ChannelTypes,
|
||||
CreateInviteOptions,
|
||||
FollowedChannelPayload,
|
||||
GetMessages,
|
||||
@@ -12,16 +14,19 @@ import type {
|
||||
MessageContent,
|
||||
} from "../types/channel.ts";
|
||||
import { Errors } from "../types/errors.ts";
|
||||
import type { RawOverwrite } from "../types/guild.ts";
|
||||
import type { MessageCreateOptions } from "../types/message.ts";
|
||||
import { PermissionOverwrite } from "../types/guild.ts";
|
||||
import { MessageCreateOptions } from "../types/message.ts";
|
||||
import { Permissions } from "../types/permission.ts";
|
||||
import { botHasChannelPermissions } from "../utils/permissions.ts";
|
||||
import {
|
||||
botHasChannelPermissions,
|
||||
calculateBits,
|
||||
} from "../utils/permissions.ts";
|
||||
|
||||
/** Checks if a channel overwrite for a user id or a role id has permission in this channel */
|
||||
export function channelOverwriteHasPermission(
|
||||
guildID: string,
|
||||
id: string,
|
||||
overwrites: RawOverwrite[],
|
||||
overwrites: PermissionOverwrite[],
|
||||
permissions: Permissions[],
|
||||
) {
|
||||
const overwrite = overwrites.find((perm) => perm.id === id) ||
|
||||
@@ -29,8 +34,10 @@ export function channelOverwriteHasPermission(
|
||||
|
||||
return permissions.every((perm) => {
|
||||
if (overwrite) {
|
||||
if (BigInt(overwrite.deny) & BigInt(perm)) return false;
|
||||
if (BigInt(overwrite.allow) & BigInt(perm)) return true;
|
||||
const allowBits = calculateBits(overwrite.allow);
|
||||
const denyBits = calculateBits(overwrite.deny);
|
||||
if (BigInt(denyBits) & BigInt(perm)) return false;
|
||||
if (BigInt(allowBits) & BigInt(perm)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -160,6 +167,15 @@ export async function sendMessage(
|
||||
}
|
||||
}
|
||||
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
if (!channel) throw new Error(Errors.CHANNEL_NOT_FOUND);
|
||||
if (
|
||||
![ChannelTypes.DM, ChannelTypes.GUILD_NEWS, ChannelTypes.GUILD_TEXT]
|
||||
.includes(channel.type)
|
||||
) {
|
||||
throw new Error(Errors.CHANNEL_NOT_TEXT_BASED);
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(
|
||||
endpoints.CHANNEL_MESSAGES(channelID),
|
||||
{
|
||||
|
||||
+14
-9
@@ -3,13 +3,13 @@ import { cacheHandlers } from "../controllers/cache.ts";
|
||||
import { identifyPayload } from "../module/client.ts";
|
||||
import { RequestManager } from "../module/requestManager.ts";
|
||||
import { requestAllMembers } from "../module/shardingManager.ts";
|
||||
import type { Guild } from "../structures/guild.ts";
|
||||
import type { Member } from "../structures/member.ts";
|
||||
import { Guild } from "../structures/guild.ts";
|
||||
import { Member } from "../structures/member.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { ImageFormats, ImageSize } from "../types/cdn.ts";
|
||||
import { ImageFormats, ImageSize } from "../types/cdn.ts";
|
||||
import { ChannelCreatePayload, ChannelTypes } from "../types/channel.ts";
|
||||
import { Errors } from "../types/errors.ts";
|
||||
import type {
|
||||
import {
|
||||
BannedUser,
|
||||
BanOptions,
|
||||
ChannelCreateOptions,
|
||||
@@ -26,13 +26,13 @@ import type {
|
||||
PrunePayload,
|
||||
UserPayload,
|
||||
} from "../types/guild.ts";
|
||||
import type { MemberCreatePayload } from "../types/member.ts";
|
||||
import { MemberCreatePayload } from "../types/member.ts";
|
||||
import { Intents } from "../types/options.ts";
|
||||
import { Permissions } from "../types/permission.ts";
|
||||
import type { RoleData } from "../types/role.ts";
|
||||
import { RoleData } from "../types/role.ts";
|
||||
import { formatImageURL } from "../utils/cdn.ts";
|
||||
import { Collection } from "../utils/collection.ts";
|
||||
import { botHasPermission } from "../utils/permissions.ts";
|
||||
import { botHasPermission, calculateBits } from "../utils/permissions.ts";
|
||||
import { urlToBase64 } from "../utils/utils.ts";
|
||||
|
||||
/** Create a new guild. Returns a guild object on success. Fires a Guild Create Gateway event. This endpoint can be used only by bots in less than 10 guilds. */
|
||||
@@ -105,7 +105,7 @@ export async function createGuildChannel(
|
||||
(await RequestManager.post(endpoints.GUILD_CHANNELS(guild.id), {
|
||||
...options,
|
||||
name,
|
||||
permission_overwrites: options?.permission_overwrites?.map((perm) => ({
|
||||
permission_overwrites: options?.permissionOverwrites?.map((perm) => ({
|
||||
...perm,
|
||||
|
||||
allow: perm.allow.reduce(
|
||||
@@ -317,7 +317,12 @@ export function editRole(
|
||||
) {
|
||||
throw new Error(Errors.MISSING_MANAGE_ROLES);
|
||||
}
|
||||
return RequestManager.patch(endpoints.GUILD_ROLE(guildID, id), options);
|
||||
return RequestManager.patch(endpoints.GUILD_ROLE(guildID, id), {
|
||||
...options,
|
||||
permissions: options.permissions
|
||||
? calculateBits(options.permissions)
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
/** Delete a guild role. Requires the MANAGE_ROLES permission. */
|
||||
|
||||
@@ -2,15 +2,12 @@ import { endpoints } from "../constants/discord.ts";
|
||||
import { cacheHandlers } from "../controllers/cache.ts";
|
||||
import { botID } from "../module/client.ts";
|
||||
import { RequestManager } from "../module/requestManager.ts";
|
||||
import type { Member } from "../structures/member.ts";
|
||||
import { Member } from "../structures/member.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { ImageFormats, ImageSize } from "../types/cdn.ts";
|
||||
import type {
|
||||
DMChannelCreatePayload,
|
||||
MessageContent,
|
||||
} from "../types/channel.ts";
|
||||
import { ImageFormats, ImageSize } from "../types/cdn.ts";
|
||||
import { DMChannelCreatePayload, MessageContent } from "../types/channel.ts";
|
||||
import { Errors } from "../types/errors.ts";
|
||||
import type { EditMemberOptions } from "../types/member.ts";
|
||||
import { EditMemberOptions } from "../types/member.ts";
|
||||
import { Permissions } from "../types/permission.ts";
|
||||
import { formatImageURL } from "../utils/cdn.ts";
|
||||
import {
|
||||
|
||||
@@ -3,12 +3,12 @@ import { endpoints } from "../constants/discord.ts";
|
||||
import { cacheHandlers } from "../controllers/cache.ts";
|
||||
import { botID } from "../module/client.ts";
|
||||
import { RequestManager } from "../module/requestManager.ts";
|
||||
import type { Message } from "../structures/message.ts";
|
||||
import { Message } from "../structures/message.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import type { MessageContent } from "../types/channel.ts";
|
||||
import { MessageContent } from "../types/channel.ts";
|
||||
import { Errors } from "../types/errors.ts";
|
||||
import type { UserPayload } from "../types/guild.ts";
|
||||
import type { MessageCreateOptions } from "../types/message.ts";
|
||||
import { UserPayload } from "../types/guild.ts";
|
||||
import { MessageCreateOptions } from "../types/message.ts";
|
||||
import { Permissions } from "../types/permission.ts";
|
||||
import { botHasChannelPermissions } from "../utils/permissions.ts";
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ import { endpoints } from "../constants/discord.ts";
|
||||
import { RequestManager } from "../module/requestManager.ts";
|
||||
import { structures } from "../structures/mod.ts";
|
||||
import { Errors } from "../types/errors.ts";
|
||||
import type { MessageCreateOptions } from "../types/message.ts";
|
||||
import { MessageCreateOptions } from "../types/message.ts";
|
||||
import { Permissions } from "../types/permission.ts";
|
||||
import type {
|
||||
import {
|
||||
ExecuteWebhookOptions,
|
||||
WebhookCreateOptions,
|
||||
WebhookPayload,
|
||||
|
||||
+38
-14
@@ -7,21 +7,22 @@ import {
|
||||
isWebSocketPongEvent,
|
||||
WebSocket,
|
||||
} from "../../deps.ts";
|
||||
import type {
|
||||
import {
|
||||
DiscordBotGatewayData,
|
||||
DiscordHeartbeatPayload,
|
||||
GatewayOpcode,
|
||||
ReadyPayload,
|
||||
} from "../types/discord.ts";
|
||||
import { GatewayOpcode } from "../types/discord.ts";
|
||||
import type { FetchMembersOptions } from "../types/guild.ts";
|
||||
import type { BotStatusRequest } from "../utils/utils.ts";
|
||||
import type { IdentifyPayload } from "./client.ts";
|
||||
import { botGatewayData, eventHandlers } from "./client.ts";
|
||||
import { FetchMembersOptions } from "../types/guild.ts";
|
||||
import { BotStatusRequest } from "../utils/utils.ts";
|
||||
import { botGatewayData, eventHandlers, IdentifyPayload } from "./client.ts";
|
||||
import { handleDiscordPayload } from "./shardingManager.ts";
|
||||
|
||||
const basicShards = new Map<number, BasicShard>();
|
||||
const heartbeating = new Set<number>();
|
||||
const heartbeating = new Map<number, boolean>();
|
||||
const utf8decoder = new TextDecoder();
|
||||
const RequestMembersQueue: RequestMemberQueuedRequest[] = [];
|
||||
let processQueue = false;
|
||||
|
||||
export interface BasicShard {
|
||||
id: number;
|
||||
@@ -32,9 +33,6 @@ export interface BasicShard {
|
||||
needToResume: boolean;
|
||||
}
|
||||
|
||||
const RequestMembersQueue: RequestMemberQueuedRequest[] = [];
|
||||
let processQueue = false;
|
||||
|
||||
interface RequestMemberQueuedRequest {
|
||||
guildID: string;
|
||||
shardID: number;
|
||||
@@ -52,7 +50,7 @@ export async function createBasicShard(
|
||||
|
||||
const basicShard: BasicShard = {
|
||||
id: shardID,
|
||||
socket: await connectWebSocket(`${data.url}?v=6&encoding=json`),
|
||||
socket: await connectWebSocket(`${data.url}?v=8&encoding=json`),
|
||||
resumeInterval: 0,
|
||||
sessionID: oldShard?.sessionID || "",
|
||||
previousSequenceNumber: oldShard?.previousSequenceNumber || 0,
|
||||
@@ -123,9 +121,13 @@ export async function createBasicShard(
|
||||
heartbeat(
|
||||
basicShard,
|
||||
(data.d as DiscordHeartbeatPayload).heartbeat_interval,
|
||||
identifyPayload,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case GatewayOpcode.HeartbeatACK:
|
||||
heartbeating.set(shardID, true);
|
||||
break;
|
||||
case GatewayOpcode.Reconnect:
|
||||
eventHandlers.debug?.(
|
||||
{ type: "reconnect", data: { shardID: basicShard.id } },
|
||||
@@ -200,17 +202,39 @@ function resume(shard: BasicShard, payload: IdentifyPayload) {
|
||||
}));
|
||||
}
|
||||
|
||||
// TODO: If a client does not receive a heartbeat ack between its attempts at sending heartbeats, it should immediately terminate the connection with a non-1000 close code, reconnect, and attempt to resume.
|
||||
async function heartbeat(
|
||||
shard: BasicShard,
|
||||
interval: number,
|
||||
payload: IdentifyPayload,
|
||||
) {
|
||||
// We lost socket connection between heartbeats, resume connection
|
||||
if (shard.socket.isClosed) {
|
||||
shard.needToResume = true;
|
||||
resumeConnection(botGatewayData, payload, shard.id);
|
||||
heartbeating.delete(shard.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!heartbeating.has(shard.id)) heartbeating.add(shard.id);
|
||||
if (heartbeating.has(shard.id)) {
|
||||
const receivedACK = heartbeating.get(shard.id);
|
||||
// If a ACK response was not received since last heartbeat, issue invalid session close
|
||||
if (!receivedACK) {
|
||||
eventHandlers.debug?.(
|
||||
{
|
||||
type: "heartbeatStopped",
|
||||
data: {
|
||||
interval,
|
||||
previousSequenceNumber: shard.previousSequenceNumber,
|
||||
shardID: shard.id,
|
||||
},
|
||||
},
|
||||
);
|
||||
return shard.socket.send(JSON.stringify({ op: 4009 }));
|
||||
}
|
||||
}
|
||||
|
||||
// Set it to false as we are issuing a new heartbeat
|
||||
heartbeating.set(shard.id, false);
|
||||
|
||||
shard.socket.send(
|
||||
JSON.stringify(
|
||||
@@ -228,7 +252,7 @@ async function heartbeat(
|
||||
},
|
||||
);
|
||||
await delay(interval);
|
||||
heartbeat(shard, interval);
|
||||
heartbeat(shard, interval, payload);
|
||||
}
|
||||
|
||||
async function resumeConnection(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { endpoints } from "../constants/discord.ts";
|
||||
import type { DiscordBotGatewayData } from "../types/discord.ts";
|
||||
import type { ClientOptions, EventHandlers } from "../types/options.ts";
|
||||
import { DiscordBotGatewayData } from "../types/discord.ts";
|
||||
import { ClientOptions, EventHandlers } from "../types/options.ts";
|
||||
import { RequestManager } from "./requestManager.ts";
|
||||
import { spawnShards } from "./shardingManager.ts";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { delay } from "../../deps.ts";
|
||||
import { baseEndpoints } from "../constants/discord.ts";
|
||||
import { HttpResponseCode } from "../types/discord.ts";
|
||||
import { Errors } from "../types/errors.ts";
|
||||
import type { RequestMethods } from "../types/fetch.ts";
|
||||
import { RequestMethods } from "../types/fetch.ts";
|
||||
import { authorization, eventHandlers } from "./client.ts";
|
||||
|
||||
const pathQueues: { [key: string]: QueuedRequest[] } = {};
|
||||
@@ -286,6 +286,23 @@ async function runMethod(
|
||||
});
|
||||
}
|
||||
|
||||
async function logErrors(response: Response, errorStack?: unknown) {
|
||||
try {
|
||||
const error = await response.json();
|
||||
console.error(error);
|
||||
|
||||
eventHandlers.debug?.({ type: "error", data: { errorStack, error } });
|
||||
} catch {
|
||||
eventHandlers.debug?.(
|
||||
{
|
||||
type: "error",
|
||||
data: { errorStack },
|
||||
},
|
||||
);
|
||||
console.error(response);
|
||||
}
|
||||
}
|
||||
|
||||
function handleStatusCode(response: Response, errorStack?: unknown) {
|
||||
const status = response.status;
|
||||
|
||||
@@ -296,13 +313,7 @@ function handleStatusCode(response: Response, errorStack?: unknown) {
|
||||
return true;
|
||||
}
|
||||
|
||||
eventHandlers.debug?.(
|
||||
{
|
||||
type: "error",
|
||||
data: { errorStack },
|
||||
},
|
||||
);
|
||||
console.error(response);
|
||||
logErrors(response, errorStack);
|
||||
|
||||
switch (status) {
|
||||
case HttpResponseCode.BadRequest:
|
||||
|
||||
+10
-6
@@ -1,13 +1,17 @@
|
||||
import type { WebSocket } from "../../deps.ts";
|
||||
import { connectWebSocket, delay, isWebSocketCloseEvent } from "../../deps.ts";
|
||||
import type {
|
||||
import {
|
||||
connectWebSocket,
|
||||
delay,
|
||||
isWebSocketCloseEvent,
|
||||
WebSocket,
|
||||
} from "../../deps.ts";
|
||||
import {
|
||||
DiscordBotGatewayData,
|
||||
DiscordHeartbeatPayload,
|
||||
GatewayOpcode,
|
||||
ReadyPayload,
|
||||
} from "../types/discord.ts";
|
||||
import { GatewayOpcode } from "../types/discord.ts";
|
||||
import type { FetchMembersOptions } from "../types/guild.ts";
|
||||
import type { DebugArg } from "../types/options.ts";
|
||||
import { FetchMembersOptions } from "../types/guild.ts";
|
||||
import { DebugArg } from "../types/options.ts";
|
||||
|
||||
let shardSocket: WebSocket;
|
||||
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
import { delay } from "../../deps.ts";
|
||||
import { controllers } from "../controllers/mod.ts";
|
||||
import type { Guild } from "../structures/guild.ts";
|
||||
import type {
|
||||
import { Guild } from "../structures/guild.ts";
|
||||
import {
|
||||
DiscordBotGatewayData,
|
||||
DiscordPayload,
|
||||
GatewayOpcode,
|
||||
} from "../types/discord.ts";
|
||||
import { GatewayOpcode } from "../types/discord.ts";
|
||||
import type { FetchMembersOptions } from "../types/guild.ts";
|
||||
import { FetchMembersOptions } from "../types/guild.ts";
|
||||
import { cache } from "../utils/cache.ts";
|
||||
import type { BotStatusRequest } from "../utils/utils.ts";
|
||||
import { BotStatusRequest } from "../utils/utils.ts";
|
||||
import {
|
||||
botGatewayStatusRequest,
|
||||
createBasicShard,
|
||||
requestGuildMembers,
|
||||
} from "./basicShard.ts";
|
||||
import type { IdentifyPayload } from "./client.ts";
|
||||
import { botGatewayData, eventHandlers, identifyPayload } from "./client.ts";
|
||||
import {
|
||||
botGatewayData,
|
||||
eventHandlers,
|
||||
IdentifyPayload,
|
||||
identifyPayload,
|
||||
} from "./client.ts";
|
||||
|
||||
let shardCounter = 0;
|
||||
let basicSharding = false;
|
||||
|
||||
+13
-10
@@ -1,6 +1,7 @@
|
||||
import { cacheHandlers } from "../controllers/cache.ts";
|
||||
import type { ChannelCreatePayload } from "../types/channel.ts";
|
||||
import type { Unpromise } from "../types/misc.ts";
|
||||
import { ChannelCreatePayload } from "../types/channel.ts";
|
||||
import { PermissionOverwrite } from "../types/guild.ts";
|
||||
import { Unpromise } from "../types/misc.ts";
|
||||
import { calculatePermissions } from "../utils/permissions.ts";
|
||||
|
||||
export async function createChannel(
|
||||
@@ -14,13 +15,14 @@ export async function createChannel(
|
||||
rate_limit_per_user: rateLimitPerUser,
|
||||
parent_id: parentID,
|
||||
last_pin_timestamp: lastPinTimestamp,
|
||||
permission_overwrites,
|
||||
...rest
|
||||
} = data;
|
||||
|
||||
const channel = {
|
||||
...rest,
|
||||
/** The guild id of the channel if it is a guild channel. */
|
||||
guildID: guildID || rawGuildID,
|
||||
guildID: guildID || rawGuildID || "",
|
||||
/** The id of the last message sent in this channel */
|
||||
lastMessageID,
|
||||
/** The amount of users allowed in this voice channel. */
|
||||
@@ -32,13 +34,14 @@ export async function createChannel(
|
||||
/** The last time when a message was pinned in this channel */
|
||||
lastPinTimestamp,
|
||||
/** The permission overwrites for this channel */
|
||||
permissions: data.permission_overwrites
|
||||
? data.permission_overwrites.map((perm) => ({
|
||||
...perm,
|
||||
allow: calculatePermissions(BigInt(perm.allow)),
|
||||
deny: calculatePermissions(BigInt(perm.deny)),
|
||||
}))
|
||||
: [],
|
||||
permissionOverwrites:
|
||||
(data.permission_overwrites
|
||||
? data.permission_overwrites.map((perm) => ({
|
||||
...perm,
|
||||
allow: calculatePermissions(BigInt(perm.allow)),
|
||||
deny: calculatePermissions(BigInt(perm.deny)),
|
||||
}))
|
||||
: []) as PermissionOverwrite[],
|
||||
/** Whether this channel is nsfw or not */
|
||||
nsfw: data.nsfw || false,
|
||||
/** The mention of the channel */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CreateGuildPayload } from "../types/guild.ts";
|
||||
import type { Unpromise } from "../types/misc.ts";
|
||||
import { CreateGuildPayload } from "../types/guild.ts";
|
||||
import { Unpromise } from "../types/misc.ts";
|
||||
import { Collection } from "../utils/collection.ts";
|
||||
import type { Member } from "./member.ts";
|
||||
import { Member } from "./member.ts";
|
||||
import { structures } from "./mod.ts";
|
||||
|
||||
export async function createGuild(data: CreateGuildPayload, shardID: number) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MemberCreatePayload } from "../types/member.ts";
|
||||
import type { Unpromise } from "../types/misc.ts";
|
||||
import { MemberCreatePayload } from "../types/member.ts";
|
||||
import { Unpromise } from "../types/misc.ts";
|
||||
|
||||
export async function createMember(data: MemberCreatePayload, guildID: string) {
|
||||
const {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MessageCreateOptions } from "../types/message.ts";
|
||||
import type { Unpromise } from "../types/misc.ts";
|
||||
import { MessageCreateOptions } from "../types/message.ts";
|
||||
import { Unpromise } from "../types/misc.ts";
|
||||
|
||||
export async function createMessage(data: MessageCreateOptions) {
|
||||
const {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Unpromise } from "../types/misc.ts";
|
||||
import type { RoleData } from "../types/role.ts";
|
||||
import { Unpromise } from "../types/misc.ts";
|
||||
import { RoleData } from "../types/role.ts";
|
||||
|
||||
export async function createRole(data: RoleData) {
|
||||
return {
|
||||
|
||||
+49
-3
@@ -1,12 +1,18 @@
|
||||
import type { Timestamps } from "./discord.ts";
|
||||
|
||||
export interface ActivityPayload {
|
||||
name: string;
|
||||
type: number;
|
||||
url?: string;
|
||||
created_at: number;
|
||||
timestamps: Timestamps;
|
||||
timestamps?: ActivityTimestamps;
|
||||
application_id?: string;
|
||||
details?: string;
|
||||
state?: string;
|
||||
emoji?: ActivityEmoji;
|
||||
party?: ActivityParty;
|
||||
assets?: ActivityAssets;
|
||||
secrets?: ActivitySecrets;
|
||||
instance?: boolean;
|
||||
flags?: number;
|
||||
}
|
||||
|
||||
export enum ActivityType {
|
||||
@@ -18,4 +24,44 @@ export enum ActivityType {
|
||||
Listening,
|
||||
/** Example: ":smiley: I am cool" */
|
||||
Custom = 4,
|
||||
/** Example: "Competing in Arena World Champions" */
|
||||
Competing,
|
||||
}
|
||||
|
||||
export interface ActivityTimestamps {
|
||||
start?: number;
|
||||
end?: number;
|
||||
}
|
||||
|
||||
export interface ActivityEmoji {
|
||||
name: string;
|
||||
id?: string;
|
||||
animated?: boolean;
|
||||
}
|
||||
|
||||
export interface ActivityParty {
|
||||
id?: string;
|
||||
size?: [number, number];
|
||||
}
|
||||
|
||||
export interface ActivityAssets {
|
||||
large_image?: string;
|
||||
large_text?: string;
|
||||
small_image?: string;
|
||||
small_text?: string;
|
||||
}
|
||||
|
||||
export interface ActivitySecrets {
|
||||
join?: string;
|
||||
spectate?: string;
|
||||
match?: string;
|
||||
}
|
||||
|
||||
export enum ActivityFlags {
|
||||
INSTANCE = 1 << 0,
|
||||
JOIN = 1 << 1,
|
||||
SPECTATE = 1 << 2,
|
||||
JOIN_REQUEST = 1 << 3,
|
||||
SYNC = 1 << 4,
|
||||
PLAY = 1 << 5,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Overwrite, RawOverwrite } from "./guild.ts";
|
||||
import type { Embed } from "./message.ts";
|
||||
import { Overwrite, RawOverwrite } from "./guild.ts";
|
||||
import { Embed } from "./message.ts";
|
||||
|
||||
export interface ChannelEditOptions {
|
||||
/** 2-100 character channel name. All */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PartialUser, UserPayload } from "./guild.ts";
|
||||
import type { MemberCreatePayload } from "./member.ts";
|
||||
import type { Activity } from "./message.ts";
|
||||
import type { ClientStatusPayload } from "./presence.ts";
|
||||
import { PartialUser, UserPayload } from "./guild.ts";
|
||||
import { MemberCreatePayload } from "./member.ts";
|
||||
import { Activity } from "./message.ts";
|
||||
import { ClientStatusPayload } from "./presence.ts";
|
||||
|
||||
export interface DiscordPayload {
|
||||
/** OP code for the payload */
|
||||
@@ -196,11 +196,6 @@ export interface Properties {
|
||||
$device: string;
|
||||
}
|
||||
|
||||
export interface Timestamps {
|
||||
start?: number;
|
||||
end?: number;
|
||||
}
|
||||
|
||||
export interface Emoji {
|
||||
name: string;
|
||||
id?: string;
|
||||
|
||||
@@ -31,4 +31,6 @@ export enum Errors {
|
||||
CHANNEL_NOT_IN_GUILD = "CHANNEL_NOT_IN_GUILD",
|
||||
INVALID_WEBHOOK_NAME = "INVALID_WEBHOOK_NAME",
|
||||
INVALID_WEBHOOK_OPTIONS = "INVALID_WEBHOOK_OPTIONS",
|
||||
CHANNEL_NOT_FOUND = "CHANNEL_NOT_FOUND",
|
||||
CHANNEL_NOT_TEXT_BASED = "CHANNEL_NOT_TEXT_BASED",
|
||||
}
|
||||
|
||||
+14
-8
@@ -1,10 +1,10 @@
|
||||
import type { ChannelCreatePayload, ChannelTypes } from "./channel.ts";
|
||||
import type { Emoji, StatusType } from "./discord.ts";
|
||||
import type { MemberCreatePayload } from "./member.ts";
|
||||
import type { Activity } from "./message.ts";
|
||||
import type { Permission } from "./permission.ts";
|
||||
import type { ClientStatusPayload } from "./presence.ts";
|
||||
import type { RoleData } from "./role.ts";
|
||||
import { ChannelCreatePayload, ChannelTypes } from "./channel.ts";
|
||||
import { Emoji, StatusType } from "./discord.ts";
|
||||
import { MemberCreatePayload } from "./member.ts";
|
||||
import { Activity } from "./message.ts";
|
||||
import { Permission } from "./permission.ts";
|
||||
import { ClientStatusPayload } from "./presence.ts";
|
||||
import { RoleData } from "./role.ts";
|
||||
|
||||
export interface GuildRolePayload {
|
||||
/** The id of the guild */
|
||||
@@ -473,6 +473,12 @@ export interface RawOverwrite {
|
||||
deny: number;
|
||||
}
|
||||
|
||||
export interface PermissionOverwrite
|
||||
extends Omit<RawOverwrite, "allow" | "deny"> {
|
||||
allow: Permission[];
|
||||
deny: Permission[];
|
||||
}
|
||||
|
||||
export interface ChannelCreateOptions {
|
||||
/** The type of the channel */
|
||||
type?: ChannelTypes;
|
||||
@@ -487,7 +493,7 @@ export interface ChannelCreateOptions {
|
||||
/** The sorting position of the channel */
|
||||
position?: number;
|
||||
/** The channel's permission overwrites */
|
||||
permission_overwrites?: Overwrite[];
|
||||
permissionOverwrites?: Overwrite[];
|
||||
/** The id of the parent category for the channel */
|
||||
parent_id?: string;
|
||||
/** Whether the channel is nsfw */
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import type { UserPayload } from "./guild.ts";
|
||||
import { UserPayload } from "./guild.ts";
|
||||
|
||||
export interface EditMemberOptions {
|
||||
/** Value to set users nickname to. Requires MANAGE_NICKNAMES permission. */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Channel } from "../structures/channel.ts";
|
||||
import type { ChannelType } from "./channel.ts";
|
||||
import type { UserPayload } from "./guild.ts";
|
||||
import type { MemberCreatePayload } from "./member.ts";
|
||||
import { Channel } from "../structures/channel.ts";
|
||||
import { ChannelType } from "./channel.ts";
|
||||
import { UserPayload } from "./guild.ts";
|
||||
import { MemberCreatePayload } from "./member.ts";
|
||||
|
||||
export interface MentionedUser extends UserPayload {
|
||||
member: MemberCreatePayload;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Channel } from "../structures/channel.ts";
|
||||
import type { Guild } from "../structures/guild.ts";
|
||||
import type { Member } from "../structures/member.ts";
|
||||
import type { Message } from "../structures/message.ts";
|
||||
import type { Role } from "../structures/role.ts";
|
||||
import type {
|
||||
import { Channel } from "../structures/channel.ts";
|
||||
import { Guild } from "../structures/guild.ts";
|
||||
import { Member } from "../structures/member.ts";
|
||||
import { Message } from "../structures/message.ts";
|
||||
import { Role } from "../structures/role.ts";
|
||||
import {
|
||||
DiscordPayload,
|
||||
Emoji,
|
||||
PresenceUpdatePayload,
|
||||
@@ -11,8 +11,8 @@ import type {
|
||||
TypingStartPayload,
|
||||
VoiceStateUpdatePayload,
|
||||
} from "./discord.ts";
|
||||
import type { UserPayload } from "./guild.ts";
|
||||
import type {
|
||||
import { UserPayload } from "./guild.ts";
|
||||
import {
|
||||
Attachment,
|
||||
BaseMessageReactionPayload,
|
||||
Embed,
|
||||
@@ -64,6 +64,7 @@ export interface DebugArg {
|
||||
| "requestManagerFetched"
|
||||
| "requestMembersProcessing"
|
||||
| "heartbeat"
|
||||
| "heartbeatStopped"
|
||||
| "createShard"
|
||||
| "invalidSession"
|
||||
| "reconnect"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { StatusType } from "./discord.ts";
|
||||
import { StatusType } from "./discord.ts";
|
||||
|
||||
export interface ClientStatusPayload {
|
||||
/** The user's status set for an active desktop (Windows, Linux, Mac) application session */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { UserPayload } from "./guild.ts";
|
||||
import type { Embed } from "./message.ts";
|
||||
import { UserPayload } from "./guild.ts";
|
||||
import { Embed } from "./message.ts";
|
||||
|
||||
export interface WebhookPayload {
|
||||
/** The id of the webhook */
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
import type { Channel } from "../structures/channel.ts";
|
||||
import type { Guild } from "../structures/guild.ts";
|
||||
import type { Message } from "../structures/message.ts";
|
||||
import type { PresenceUpdatePayload } from "../types/discord.ts";
|
||||
import { Channel } from "../structures/channel.ts";
|
||||
import { Guild } from "../structures/guild.ts";
|
||||
import { Message } from "../structures/message.ts";
|
||||
import { PresenceUpdatePayload } from "../types/discord.ts";
|
||||
import { Collection } from "./collection.ts";
|
||||
|
||||
export interface CacheData {
|
||||
@@ -21,5 +21,5 @@ export const cache: CacheData = {
|
||||
messages: new Collection(),
|
||||
unavailableGuilds: new Collection(),
|
||||
presences: new Collection(),
|
||||
fetchAllMembersProcessingRequests: new Collection<string, Function>(),
|
||||
fetchAllMembersProcessingRequests: new Collection(),
|
||||
};
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import type { ImageFormats, ImageSize } from "../types/cdn.ts";
|
||||
import { ImageFormats, ImageSize } from "../types/cdn.ts";
|
||||
|
||||
export const formatImageURL = (
|
||||
url: string,
|
||||
|
||||
+85
-70
@@ -1,9 +1,9 @@
|
||||
import { cacheHandlers } from "../controllers/cache.ts";
|
||||
import { botID } from "../module/client.ts";
|
||||
import type { Guild } from "../structures/guild.ts";
|
||||
import type { Role } from "../structures/role.ts";
|
||||
import type { Permission } from "../types/permission.ts";
|
||||
import { Permissions } from "../types/permission.ts";
|
||||
import { Guild } from "../structures/guild.ts";
|
||||
import { Role } from "../structures/role.ts";
|
||||
import { PermissionOverwrite } from "../types/guild.ts";
|
||||
import { Permission, Permissions } from "../types/permission.ts";
|
||||
|
||||
/** Checks if the member has this permission. If the member is an owner or has admin perms it will always be true. */
|
||||
export async function memberIDHasPermission(
|
||||
@@ -34,6 +34,8 @@ export function memberHasPermission(
|
||||
const permissionBits = memberRoleIDs.map((id) =>
|
||||
guild.roles.get(id)?.permissions
|
||||
)
|
||||
// Removes any edge case undefined
|
||||
.filter((id) => id)
|
||||
.reduce((bits, permissions) => {
|
||||
bits |= BigInt(permissions);
|
||||
return bits;
|
||||
@@ -58,6 +60,8 @@ export async function botHasPermission(
|
||||
|
||||
const permissionBits = member.roles
|
||||
.map((id) => guild.roles.get(id)!)
|
||||
// Remove any edge case undefined
|
||||
.filter((r) => r)
|
||||
.reduce((bits, data) => {
|
||||
bits |= BigInt(data.permissions);
|
||||
|
||||
@@ -84,101 +88,104 @@ export async function hasChannelPermissions(
|
||||
permissions: Permissions[],
|
||||
) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
if (!channel?.guildID) return true;
|
||||
if (!channel) return false;
|
||||
if (!channel.guildID) return true;
|
||||
|
||||
const guild = await cacheHandlers.get("guilds", channel.guildID);
|
||||
if (!guild) return false;
|
||||
|
||||
if (guild.ownerID === memberID) return true;
|
||||
if (botHasPermission(guild.id, [Permissions.ADMINISTRATOR])) return true;
|
||||
if (
|
||||
await memberIDHasPermission(memberID, guild.id, ["ADMINISTRATOR"])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const member = guild.members.get(memberID);
|
||||
if (!member) return false;
|
||||
|
||||
const memberOverwrite = channel.permission_overwrites?.find((o) =>
|
||||
o.id === memberID
|
||||
);
|
||||
let memberOverwrite: PermissionOverwrite | undefined;
|
||||
let everyoneOverwrite: PermissionOverwrite | undefined;
|
||||
let rolesOverwrites: PermissionOverwrite[] = [];
|
||||
|
||||
const rolesOverwrites = channel.permission_overwrites?.filter((o) =>
|
||||
member.roles.includes(o.id)
|
||||
);
|
||||
|
||||
const everyoneOverwrite = channel.permission_overwrites?.find((o) =>
|
||||
o.id === guild.id
|
||||
);
|
||||
for (const overwrite of channel.permissionOverwrites || []) {
|
||||
// If the overwrite on this channel is specific to this member
|
||||
if (overwrite.id === memberID) memberOverwrite = overwrite;
|
||||
// If it is the everyone role overwrite
|
||||
if (overwrite.id === guild.id) everyoneOverwrite = overwrite;
|
||||
// If it is one of the roles the member has
|
||||
if (member.roles.includes(overwrite.id)) rolesOverwrites.push(overwrite);
|
||||
}
|
||||
|
||||
const allowedPermissions = new Set<Permissions>();
|
||||
|
||||
// Member perms override everything so we must check them first
|
||||
if (memberOverwrite) {
|
||||
// One of the necessary permissions is denied
|
||||
if (
|
||||
permissions.some((perm) => BigInt(memberOverwrite.deny) & BigInt(perm))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
permissions.forEach((perm) => {
|
||||
const allowBits = calculateBits(memberOverwrite.allow);
|
||||
const denyBits = calculateBits(memberOverwrite.deny);
|
||||
for (const perm of permissions) {
|
||||
// One of the necessary permissions is denied. Since this is main permission we can cancel if its denied.
|
||||
if (BigInt(denyBits) & BigInt(perm)) return false;
|
||||
// Already allowed perm
|
||||
if (allowedPermissions.has(perm)) return;
|
||||
if (allowedPermissions.has(perm)) continue;
|
||||
|
||||
// This perm is allowed so we save it
|
||||
if (BigInt(memberOverwrite.allow) & BigInt(perm)) {
|
||||
if (BigInt(allowBits) & BigInt(perm)) {
|
||||
allowedPermissions.add(perm);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Check the necessary permissions for roles
|
||||
if (rolesOverwrites?.length) {
|
||||
if (
|
||||
rolesOverwrites.some((overwrite) =>
|
||||
permissions.some((perm) =>
|
||||
(BigInt(overwrite.deny) & BigInt(perm)) &&
|
||||
// If another role allows these perms then they are not denied
|
||||
!rolesOverwrites.some((o) => BigInt(o.allow) & BigInt(perm)) &&
|
||||
// Make sure the memberOverwrite does not allow this perm
|
||||
!(memberOverwrite && BigInt(memberOverwrite.allow) & BigInt(perm))
|
||||
)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
for (const perm of permissions) {
|
||||
// If this is already allowed, skip
|
||||
if (allowedPermissions.has(perm)) continue;
|
||||
|
||||
permissions.forEach((perm) => {
|
||||
for (const overwrite of rolesOverwrites) {
|
||||
const allowBits = calculateBits(overwrite.allow);
|
||||
// This perm is allowed so we save it
|
||||
if (BigInt(allowBits) & BigInt(perm)) {
|
||||
allowedPermissions.add(perm);
|
||||
break;
|
||||
}
|
||||
|
||||
const denyBits = calculateBits(overwrite.deny);
|
||||
// If this role denies it we need to save and check if another role allows it, allows > deny
|
||||
if (BigInt(denyBits) & BigInt(perm)) {
|
||||
// This role denies his perm, but before denying we need to check all other roles if any allow as allow > deny
|
||||
const isAllowed = rolesOverwrites.some((o) =>
|
||||
BigInt(calculateBits(o.allow)) & BigInt(perm)
|
||||
);
|
||||
if (isAllowed) continue;
|
||||
// This permission is in fact denied. Since Roles overrule everything below here we can cancel ou here
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (everyoneOverwrite) {
|
||||
const allowBits = calculateBits(everyoneOverwrite.allow);
|
||||
const denyBits = calculateBits(everyoneOverwrite.deny);
|
||||
for (const perm of permissions) {
|
||||
// Already allowed perm
|
||||
if (allowedPermissions.has(perm)) return;
|
||||
rolesOverwrites.forEach((overwrite) => {
|
||||
// This perm is allowed so we save it
|
||||
if (BigInt(overwrite.allow) & BigInt(perm)) {
|
||||
allowedPermissions.add(perm);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Check the necessary permissions for everyone
|
||||
if (
|
||||
everyoneOverwrite
|
||||
) {
|
||||
if (
|
||||
permissions.some((perm) =>
|
||||
BigInt(everyoneOverwrite.deny) & BigInt(perm) &&
|
||||
!allowedPermissions.has(perm)
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
// If all permissions are granted
|
||||
if (
|
||||
permissions.every((perm) =>
|
||||
BigInt(everyoneOverwrite.allow) & BigInt(perm)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
if (allowedPermissions.has(perm)) continue;
|
||||
// One of the necessary permissions is denied. Since everyone overwrite overrides role perms we can cancel here
|
||||
if (BigInt(denyBits) & BigInt(perm)) return false;
|
||||
// This perm is allowed so we save it
|
||||
if (BigInt(allowBits) & BigInt(perm)) {
|
||||
allowedPermissions.add(perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is there any remaining permission to check role perms or can we determine that permissions are allowed
|
||||
if (permissions.every((perm) => allowedPermissions.has(perm))) return true;
|
||||
|
||||
// Some permission was not explicitly allowed so we default to checking role perms directly
|
||||
return botHasPermission(guild.id, permissions);
|
||||
}
|
||||
|
||||
/** This function converts a bitwise string to permission strings */
|
||||
export function calculatePermissions(permissionBits: bigint) {
|
||||
return Object.keys(Permissions).filter((perm) => {
|
||||
if (typeof perm !== "number") return false;
|
||||
@@ -186,6 +193,14 @@ export function calculatePermissions(permissionBits: bigint) {
|
||||
}) as Permission[];
|
||||
}
|
||||
|
||||
/** This function converts an array of permissions into the bitwise string. */
|
||||
export function calculateBits(permissions: Permission[]) {
|
||||
return permissions.reduce(
|
||||
(bits, perm) => bits |= BigInt(Permissions[perm]),
|
||||
BigInt(0),
|
||||
).toString();
|
||||
}
|
||||
|
||||
export async function highestRole(guildID: string, memberID: string) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) return;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { encode } from "../../deps.ts";
|
||||
import { sendGatewayCommand } from "../module/shardingManager.ts";
|
||||
import { ActivityType } from "../types/activity.ts";
|
||||
import type { StatusType } from "../types/discord.ts";
|
||||
import { StatusType } from "../types/discord.ts";
|
||||
|
||||
export const sleep = (timeout: number) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, timeout));
|
||||
|
||||
Reference in New Issue
Block a user