refactor(helpers): separate functions into files (#667)

* refactor(helpers): separate functions into files

* idk

* idk
This commit is contained in:
ayntee
2021-03-13 08:10:31 -05:00
committed by GitHub
parent 88ce4da555
commit e9cbbbff7c
143 changed files with 3362 additions and 2915 deletions
@@ -0,0 +1,9 @@
import { cacheHandlers } from "../../cache.ts";
/** Gets an array of all the channels ids that are the children of this category. */
export function categoryChildrenIDs(guildID: string, id: string) {
return cacheHandlers.filter(
"channels",
(channel) => channel.parentID === id && channel.guildID === guildID,
);
}
@@ -0,0 +1,22 @@
import { Permission, Permissions, RawOverwrite } from "../../types/mod.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[],
permissions: Permission[],
) {
const overwrite = overwrites.find((perm) => perm.id === id) ||
overwrites.find((perm) => perm.id === guildID);
return permissions.every((perm) => {
if (overwrite) {
const allowBits = overwrite.allow;
const denyBits = overwrite.deny;
if (BigInt(denyBits) & BigInt(Permissions[perm])) return false;
if (BigInt(allowBits) & BigInt(Permissions[perm])) return true;
}
return false;
});
}
@@ -0,0 +1,50 @@
import { cacheHandlers } from "../../cache.ts";
import { RequestManager } from "../../rest/request_manager.ts";
import { structures } from "../../structures/mod.ts";
import {
ChannelCreateOptions,
ChannelCreatePayload,
ChannelTypes,
Permission,
} from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
import {
calculateBits,
requireBotGuildPermissions,
} from "../../util/permissions.ts";
/** Create a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */
export async function createGuildChannel(
guildID: string,
name: string,
options?: ChannelCreateOptions,
) {
const requiredPerms: Set<Permission> = new Set(["MANAGE_CHANNELS"]);
options?.permissionOverwrites?.forEach((overwrite) => {
overwrite.allow.forEach(requiredPerms.add, requiredPerms);
overwrite.deny.forEach(requiredPerms.add, requiredPerms);
});
await requireBotGuildPermissions(guildID, [...requiredPerms]);
const result = (await RequestManager.post(
endpoints.GUILD_CHANNELS(guildID),
{
...options,
name,
permission_overwrites: options?.permissionOverwrites?.map((perm) => ({
...perm,
allow: calculateBits(perm.allow),
deny: calculateBits(perm.deny),
})),
type: options?.type || ChannelTypes.GUILD_TEXT,
},
)) as ChannelCreatePayload;
const channelStruct = await structures.createChannelStruct(result);
await cacheHandlers.set("channels", channelStruct.id, channelStruct);
return channelStruct;
}
+32
View File
@@ -0,0 +1,32 @@
import { cacheHandlers } from "../../cache.ts";
import { RequestManager } from "../../rest/request_manager.ts";
import { Errors } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
import { requireBotGuildPermissions } from "../../util/permissions.ts";
/** Delete a channel in your server. Bot needs MANAGE_CHANNEL permissions in the server. */
export async function deleteChannel(
guildID: string,
channelID: string,
reason?: string,
) {
await requireBotGuildPermissions(guildID, ["MANAGE_CHANNELS"]);
const guild = await cacheHandlers.get("guilds", guildID);
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
if (guild?.rulesChannelID === channelID) {
throw new Error(Errors.RULES_CHANNEL_CANNOT_BE_DELETED);
}
if (guild?.publicUpdatesChannelID === channelID) {
throw new Error(Errors.UPDATES_CHANNEL_CANNOT_BE_DELETED);
}
const result = await RequestManager.delete(
endpoints.CHANNEL_BASE(channelID),
{ reason },
);
return result;
}
@@ -0,0 +1,18 @@
import { RequestManager } from "../../rest/request_manager.ts";
import { endpoints } from "../../util/constants.ts";
import { requireBotGuildPermissions } from "../../util/permissions.ts";
/** Delete the channel permission overwrites for a user or role in this channel. Requires `MANAGE_ROLES` permission. */
export async function deleteChannelOverwrite(
guildID: string,
channelID: string,
overwriteID: string,
) {
await requireBotGuildPermissions(guildID, ["MANAGE_ROLES"]);
const result = await RequestManager.delete(
endpoints.CHANNEL_OVERWRITE(channelID, overwriteID),
);
return result;
}
+109
View File
@@ -0,0 +1,109 @@
import { RequestManager } from "../../rest/request_manager.ts";
import { ChannelEditOptions } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
import {
calculateBits,
requireBotChannelPermissions,
} from "../../util/permissions.ts";
/** Update a channel's settings. Requires the `MANAGE_CHANNELS` permission for the guild. */
export async function editChannel(
channelID: string,
options: ChannelEditOptions,
reason?: string,
) {
await requireBotChannelPermissions(channelID, ["MANAGE_CHANNELS"]);
if (options.name || options.topic) {
const request = editChannelNameTopicQueue.get(channelID);
if (!request) {
// If this hasnt been done before simply add 1 for it
editChannelNameTopicQueue.set(channelID, {
channelID: channelID,
amount: 1,
// 10 minutes from now
timestamp: Date.now() + 600000,
items: [],
});
} else if (request.amount === 1) {
// Start queuing future requests to this channel
request.amount = 2;
request.timestamp = Date.now() + 600000;
} else {
// 2 have already been used add to queue
request.items.push({ channelID, options });
if (editChannelProcessing) return;
editChannelProcessing = true;
processEditChannelQueue();
return;
}
}
const payload = {
...options,
// deno-lint-ignore camelcase
rate_limit_per_user: options.rateLimitPerUser,
// deno-lint-ignore camelcase
parent_id: options.parentID,
// deno-lint-ignore camelcase
user_limit: options.userLimit,
// deno-lint-ignore camelcase
permission_overwrites: options.overwrites?.map((overwrite) => {
return {
...overwrite,
allow: calculateBits(overwrite.allow),
deny: calculateBits(overwrite.deny),
};
}),
};
const result = await RequestManager.patch(endpoints.CHANNEL_BASE(channelID), {
...payload,
reason,
});
return result;
}
interface EditChannelRequest {
amount: number;
timestamp: number;
channelID: string;
items: {
channelID: string;
options: ChannelEditOptions;
}[];
}
const editChannelNameTopicQueue = new Map<string, EditChannelRequest>();
let editChannelProcessing = false;
function processEditChannelQueue() {
if (!editChannelProcessing) return;
const now = Date.now();
editChannelNameTopicQueue.forEach((request) => {
if (now > request.timestamp) return;
// 10 minutes have passed so we can reset this channel again
if (!request.items.length) {
return editChannelNameTopicQueue.delete(request.channelID);
}
request.amount = 0;
// There are items to process for this request
const details = request.items.shift();
if (!details) return;
editChannel(details.channelID, details.options);
const secondDetails = request.items.shift();
if (!secondDetails) return;
return editChannel(secondDetails.channelID, secondDetails.options);
});
if (editChannelNameTopicQueue.size) {
setTimeout(() => processEditChannelQueue(), 600000);
} else {
editChannelProcessing = false;
}
}
@@ -0,0 +1,28 @@
import { RequestManager } from "../../rest/request_manager.ts";
import { Overwrite } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
import {
calculateBits,
requireBotGuildPermissions,
} from "../../util/permissions.ts";
/** Edit the channel permission overwrites for a user or role in this channel. Requires `MANAGE_ROLES` permission. */
export async function editChannelOverwrite(
guildID: string,
channelID: string,
overwriteID: string,
options: Omit<Overwrite, "id">,
) {
await requireBotGuildPermissions(guildID, ["MANAGE_ROLES"]);
const result = await RequestManager.put(
endpoints.CHANNEL_OVERWRITE(channelID, overwriteID),
{
allow: calculateBits(options.allow),
deny: calculateBits(options.deny),
type: options.type,
},
);
return result;
}
+21
View File
@@ -0,0 +1,21 @@
import { RequestManager } from "../../rest/request_manager.ts";
import { FollowedChannelPayload } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
import { requireBotChannelPermissions } from "../../util/permissions.ts";
/** Follow a News Channel to send messages to a target channel. Requires the `MANAGE_WEBHOOKS` permission in the target channel. Returns the webhook id. */
export async function followChannel(
sourceChannelID: string,
targetChannelID: string,
) {
await requireBotChannelPermissions(targetChannelID, ["MANAGE_WEBHOOKS"]);
const data = (await RequestManager.post(
endpoints.CHANNEL_FOLLOW(sourceChannelID),
{
webhook_channel_id: targetChannelID,
},
)) as FollowedChannelPayload;
return data.webhook_id;
}
+25
View File
@@ -0,0 +1,25 @@
import { cacheHandlers } from "../../cache.ts";
import { RequestManager } from "../../rest/request_manager.ts";
import { structures } from "../../structures/mod.ts";
import { ChannelCreatePayload } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
/** Fetches a single channel object from the api.
*
* ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your channels will be cached in your guild.**
*/
export async function getChannel(channelID: string, addToCache = true) {
const result = (await RequestManager.get(
endpoints.CHANNEL_BASE(channelID),
)) as ChannelCreatePayload;
const channelStruct = await structures.createChannelStruct(
result,
result.guild_id,
);
if (addToCache) {
await cacheHandlers.set("channels", channelStruct.id, channelStruct);
}
return channelStruct;
}
@@ -0,0 +1,15 @@
import { RequestManager } from "../../rest/request_manager.ts";
import { WebhookPayload } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
import { requireBotChannelPermissions } from "../../util/permissions.ts";
/** Gets the webhooks for this channel. Requires MANAGE_WEBHOOKS */
export async function getChannelWebhooks(channelID: string) {
await requireBotChannelPermissions(channelID, ["MANAGE_WEBHOOKS"]);
const result = await RequestManager.get(
endpoints.CHANNEL_WEBHOOKS(channelID),
);
return result as WebhookPayload[];
}
+24
View File
@@ -0,0 +1,24 @@
import { cacheHandlers } from "../../cache.ts";
import { RequestManager } from "../../rest/request_manager.ts";
import { structures } from "../../structures/mod.ts";
import { ChannelCreatePayload } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
/** Returns a list of guild channel objects.
*
* ⚠️ **If you need this, you are probably doing something wrong. This is not intended for use. Your channels will be cached in your guild.**
*/
export async function getChannels(guildID: string, addToCache = true) {
const result = (await RequestManager.get(
endpoints.GUILD_CHANNELS(guildID),
) as ChannelCreatePayload[]);
return Promise.all(result.map(async (res) => {
const channelStruct = await structures.createChannelStruct(res, guildID);
if (addToCache) {
await cacheHandlers.set("channels", channelStruct.id, channelStruct);
}
return channelStruct;
}));
}
+15
View File
@@ -0,0 +1,15 @@
import { RequestManager } from "../../rest/request_manager.ts";
import { structures } from "../../structures/mod.ts";
import { MessageCreateOptions } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
/** Get pinned messages in this channel. */
export async function getPins(channelID: string) {
const result = (await RequestManager.get(
endpoints.CHANNEL_PINS(channelID),
)) as MessageCreateOptions[];
return Promise.all(
result.map((res) => structures.createMessageStruct(res)),
);
}
+20
View File
@@ -0,0 +1,20 @@
import { cacheHandlers } from "../../cache.ts";
/** Checks whether a channel is synchronized with its parent/category channel or not. */
export async function isChannelSynced(channelID: string) {
const channel = await cacheHandlers.get("channels", channelID);
if (!channel?.parentID) return false;
const parentChannel = await cacheHandlers.get("channels", channel.parentID);
if (!parentChannel) return false;
return channel.permissionOverwrites?.every((overwrite) => {
const permission = parentChannel.permissionOverwrites?.find(
(ow) => ow.id === overwrite.id,
);
if (!permission) return false;
return !(
overwrite.allow !== permission.allow || overwrite.deny !== permission.deny
);
});
}
+40
View File
@@ -0,0 +1,40 @@
import { cacheHandlers } from "../../cache.ts";
import { RequestManager } from "../../rest/request_manager.ts";
import { ChannelTypes, Errors } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
import { botHasChannelPermissions } from "../../util/permissions.ts";
/**
* Trigger a typing indicator for the specified channel. Generally bots should **NOT** implement this route.
* However, if a bot is responding to a command and expects the computation to take a few seconds,
* this endpoint may be called to let the user know that the bot is processing their message.
*/
export async function startTyping(channelID: string) {
const channel = await cacheHandlers.get("channels", channelID);
// If the channel is cached, we can do extra checks/safety
if (channel) {
if (
![
ChannelTypes.DM,
ChannelTypes.GUILD_NEWS,
ChannelTypes.GUILD_TEXT,
].includes(channel.type)
) {
throw new Error(Errors.CHANNEL_NOT_TEXT_BASED);
}
const hasSendMessagesPerm = await botHasChannelPermissions(
channelID,
["SEND_MESSAGES"],
);
if (
!hasSendMessagesPerm
) {
throw new Error(Errors.MISSING_SEND_MESSAGES);
}
}
const result = await RequestManager.post(endpoints.CHANNEL_TYPING(channelID));
return result;
}
+20
View File
@@ -0,0 +1,20 @@
import { RequestManager } from "../../rest/request_manager.ts";
import { PositionSwap } from "../../types/mod.ts";
import { endpoints } from "../../util/constants.ts";
/** Modify the positions of channels on the guild. Requires MANAGE_CHANNELS permisison. */
export async function swapChannels(
guildID: string,
channelPositions: PositionSwap[],
) {
if (channelPositions.length < 2) {
throw "You must provide at least two channels to be swapped.";
}
const result = await RequestManager.patch(
endpoints.GUILD_CHANNELS(guildID),
channelPositions,
);
return result;
}