import Client from "../Client.js";
import { LIMITS, PERMISSIONS } from "../constants.js";
import Message from "../structures/Message.js";
import checkPermission from "../util/discord/checkPermission.js";
import BaseCacheManager from "./BaseCacheManager.js";
/**
* Manages all messages within a channel.
*/
class ChannelMessageManager extends BaseCacheManager {
#_client;
#channel;
#guild;
static identifier = "messages";
/**
* Creates a channel message manager.
* @param {Client} client The client instance.
* @param {Guild} guild The guild that this message manager belongs to.
* @param {Channel} channel The channel that is being managed.
* @throws {TypeError}
* @constructor
* @public
*/
constructor(client, guild, channel) {
super(client, { structureType: ChannelMessageManager });
if (!(client instanceof Client))
throw new TypeError("GLUON: Client must be a Client instance.");
if (!guild)
throw new TypeError("GLUON: Guild must be a valid guild instance.");
if (!channel)
throw new TypeError("GLUON: Channel must be a valid channel instance.");
/**
* The client instance.
* @type {Client}
* @private
*/
this.#_client = client;
/**
* The channel that is being managed.
* @type {Channel}
* @private
*/
this.#channel = channel;
/**
* The guild that this message manager belongs to.
* @type {Guild}
* @private
*/
this.#guild = guild;
}
/**
* The guild that this message manager belongs to.
* @type {Guild}
* @readonly
*/
get guild() {
return this.#guild;
}
/**
* Fetches a collection of messages or a singular message from the channel.
* @param {Object | String} options Either an object of {@link https://discord.com/developers/docs/resources/channel#get-channel-messages-query-string-params|options} or a message id.
* @returns {Promise<Array<Message>> | Promise<Message>}
* @public
* @async
* @method
* @throws {TypeError | Error}
*/
async fetch(options) {
if (
!checkPermission(
(await this.#guild.me()).permissions,
PERMISSIONS.VIEW_CHANNEL,
)
)
throw new Error("MISSING PERMISSIONS: VIEW_CHANNEL");
if (
!checkPermission(
(await this.#guild.me()).permissions,
PERMISSIONS.READ_MESSAGE_HISTORY,
)
)
throw new Error("MISSING PERMISSIONS: READ_MESSAGE_HISTORY");
if (typeof options === "object") {
return ChannelMessageManager.fetchMessages(
this.#_client,
this.#guild.id,
this.#channel.id,
options,
);
} else if (typeof options === "string") {
return ChannelMessageManager.fetchMessage(
this.#_client,
this.#guild.id,
this.#channel.id,
options,
);
} else
throw new TypeError(
"GLUON: Must provide an object of options or a string of a message ID.",
);
}
/**
* Fetches all the pinned messages that belong to the channel.
* @returns {Promise<Array<Message>>}
* @public
* @async
* @method
*/
async fetchPinned() {
const data = await this.#_client.request.makeRequest("getPinned", [
this.#channel.id,
]);
const messages = [];
for (let i = 0; i < data.length; i++)
messages.push(
new Message(this.#_client, data[i], {
channelId: data[i].channel_id,
guildId: this.#channel.guild.id,
}),
);
return messages;
}
/**
* Adds a message to the cache.
* @param {String} id The ID of the message to cache.
* @param {Message} message The message to cache.
* @returns {Message}
* @public
* @method
* @throws {TypeError}
* @override
*/
set(id, message) {
if (!(message instanceof Message))
throw new TypeError("GLUON: Message must be a Message instance.");
return super.set(id, message);
}
/**
* Returns the cache manager.
* @param {Client} client The client instance.
* @param {String} guildId The ID of the guild.
* @param {String} channelId The ID of the channel.
* @returns {ChannelMessageManager}
* @public
* @static
* @method
* @throws {TypeError}
*/
static getCacheManager(client, guildId, channelId) {
if (!(client instanceof Client))
throw new TypeError("GLUON: Client must be a Client instance.");
if (typeof guildId !== "string")
throw new TypeError("GLUON: Guild ID must be a string.");
if (typeof channelId !== "string")
throw new TypeError("GLUON: Channel ID must be a string.");
return client.guilds.get(guildId).channels.get(channelId).messages;
}
/**
* Gets a message from the cache.
* @param {Client} client The client instance.
* @param {String} guildId The ID of the guild.
* @param {String} channelId The ID of the channel.
* @param {String} messageId The ID of the message.
* @returns {Message}
* @public
* @static
* @method
* @throws {TypeError}
*/
static getMessage(client, guildId, channelId, messageId) {
if (!(client instanceof Client))
throw new TypeError("GLUON: Client must be a Client instance.");
if (typeof guildId !== "string")
throw new TypeError("GLUON: Guild ID must be a string.");
if (typeof channelId !== "string")
throw new TypeError("GLUON: Channel ID must be a string.");
if (typeof messageId !== "string")
throw new TypeError("GLUON: Message ID must be a string.");
return ChannelMessageManager.getCacheManager(
client,
guildId,
channelId,
).get(messageId);
}
/**
* Fetches a message from the channel.
* @param {Client} client The client instance.
* @param {String} guildId The ID of the guild.
* @param {String} channelId The ID of the channel.
* @param {String} messageId The ID of the message.
* @returns {Message}
* @public
* @async
* @static
* @method
* @throws {TypeError | Error}
*/
static async fetchMessage(client, guildId, channelId, messageId) {
if (!(client instanceof Client))
throw new TypeError("GLUON: Client is not a Client instance.");
if (typeof guildId !== "string")
throw new TypeError("GLUON: Guild ID is not a string.");
if (typeof channelId !== "string")
throw new TypeError("GLUON: Channel ID is not a string.");
if (typeof messageId !== "string")
throw new TypeError("GLUON: Message ID is not a string.");
if (
!checkPermission(
(
await ChannelMessageManager.getCacheManager(
client,
guildId,
channelId,
).guild.me()
).permissions,
PERMISSIONS.VIEW_CHANNEL,
)
)
throw new Error("MISSING PERMISSIONS: VIEW_CHANNEL");
if (
!checkPermission(
(
await ChannelMessageManager.getCacheManager(
client,
guildId,
channelId,
).guild.me()
).permissions,
PERMISSIONS.READ_MESSAGE_HISTORY,
)
)
throw new Error("MISSING PERMISSIONS: READ_MESSAGE_HISTORY");
const fromCache = ChannelMessageManager.getMessage(
client,
guildId,
channelId,
messageId,
);
if (fromCache) return fromCache;
const data = await client.request.makeRequest("getChannelMessage", [
channelId,
messageId,
]);
return new Message(client, data, {
channelId,
guildId,
});
}
/**
* Fetches a collection of messages from the channel.
* @param {Client} client The client instance.
* @param {String} guildId The ID of the guild.
* @param {String} channelId The ID of the channel.
* @param {Object} options The options for fetching messages.
* @param {String} options.around The ID of the message to fetch messages around.
* @param {String} options.before The ID of the message to fetch messages before.
* @param {String} options.after The ID of the message to fetch messages after.
* @param {Number} options.limit The maximum number of messages to fetch.
* @returns {Array<Message>}
* @public
* @async
* @static
* @method
* @throws {TypeError | Error}
*/
static async fetchMessages(
client,
guildId,
channelId,
{ around, before, after, limit } = {},
) {
if (!(client instanceof Client))
throw new TypeError("GLUON: Client is not a Client instance.");
if (typeof guildId !== "string")
throw new TypeError("GLUON: Guild ID is not a string.");
if (typeof channelId !== "string")
throw new TypeError("GLUON: Channel ID is not a string.");
if (around && typeof around !== "string")
throw new TypeError("GLUON: Around is not a string.");
if (before && typeof before !== "string")
throw new TypeError("GLUON: Before is not a string.");
if (after && typeof after !== "string")
throw new TypeError("GLUON: After is not a string.");
if (typeof limit !== "undefined" && typeof limit !== "number")
throw new TypeError("GLUON: Limit is not a number.");
if (
typeof limit !== "undefined" &&
(limit < LIMITS.MIN_MESSAGES_FETCH_LIMIT ||
limit > LIMITS.MAX_MESSAGES_FETCH_LIMIT)
)
throw new RangeError(
`GLUON: Limit must be between ${LIMITS.MIN_MESSAGES_FETCH_LIMIT} and ${LIMITS.MAX_MESSAGES_FETCH_LIMIT}.`,
);
if (
!checkPermission(
(
await ChannelMessageManager.getCacheManager(
client,
guildId,
channelId,
).guild.me()
).permissions,
PERMISSIONS.VIEW_CHANNEL,
)
)
throw new Error("MISSING PERMISSIONS: VIEW_CHANNEL");
if (
!checkPermission(
(
await ChannelMessageManager.getCacheManager(
client,
guildId,
channelId,
).guild.me()
).permissions,
PERMISSIONS.READ_MESSAGE_HISTORY,
)
)
throw new Error("MISSING PERMISSIONS: READ_MESSAGE_HISTORY");
let providedFilters = 0;
if (around) providedFilters++;
if (before) providedFilters++;
if (after) providedFilters++;
if (providedFilters > 1)
throw new Error(
"GLUON: Only one of around, before, or after may be provided.",
);
const body = {};
if (around) body.around = around;
else if (before) body.before = before;
else if (after) body.after = after;
if (limit) body.limit = limit;
const data = await client.request.makeRequest(
"getChannelMessages",
[channelId],
body,
);
const messages = [];
for (let i = 0; i < data.length; i++) {
messages.push(
new Message(client, data[i], {
channelId: data[i].channel_id,
guildId,
}),
);
}
return messages;
}
/**
* Bulk deletes channel messages.
* @param {Client} client The client instance.
* @param {String} channelId The id of the channel to purge messages in.
* @param {Array<String>} messages An array of message ids to delete.
* @param {Object} options
* @returns {Promise<void>}
* @public
* @method
* @async
* @throws {TypeError}
* @static
*/
static async purgeChannelMessages(
client,
channelId,
messages,
{ reason } = {},
) {
if (!(client instanceof Client))
throw new TypeError("GLUON: Client must be a Client instance.");
if (typeof channelId !== "string")
throw new TypeError("GLUON: Channel ID is not a string.");
if (
!Array.isArray(messages) ||
!messages.every((m) => typeof m === "string")
)
throw new TypeError(
"GLUON: Messages is not an array of message id strings.",
);
if (typeof reason !== "undefined" && typeof reason !== "string")
throw new TypeError("GLUON: Reason is not a string.");
const body = {};
body.messages = messages;
if (reason) body["X-Audit-Log-Reason"] = reason;
await client.request.makeRequest(
"postBulkDeleteMessages",
[channelId],
body,
);
}
}
export default ChannelMessageManager;