Skip to content

Commit

Permalink
chore: Update permCheck.ts (#112)
Browse files Browse the repository at this point in the history
* chore: Update permCheck.ts

Allows users to check member perms before using specific sub command groups, sub commands, and options!

* edit: permCheck - revert back to a function

Reverted permCheck back to a function to avoid breaking changes.

* edit: permCheck.ts

Remove console logs

* formatting permCheck.ts

* edit: Update permCheck.ts

Fixed overall formatting
simplified ephemeral booleans
No longer destructuring interaction from ctx
fixed in guild from not fully returning controller.stop()
remove `no_guild` function in favor of hard coding
imported type CommandType

* edit: Update permCheck.ts

Remove ALL destructures `({ ctx })` --> `(ctx)`

* edit: Update permCheck.ts 

edit response for not being in guild

* edit: permCheck - assigned to object

Remove all breaking changes while maintaining integrity of new features as well as original!

* edit: permCheck - remove un-needed code.

Thanks to Duro for simplifying the code into one function!

---------

Co-authored-by: Jacob Nguyen <[email protected]>
  • Loading branch information
Peter-MJ-Parker and jacoobes authored Jul 9, 2024
1 parent e3b4265 commit 21d18bb
Showing 1 changed file with 242 additions and 20 deletions.
262 changes: 242 additions & 20 deletions plugins/permCheck.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
// @ts-nocheck
//@ts-nocheck
/**
* @plugin
* This is perm check, it allows users to parse the permission you want and let the plugin do the rest. (check user for that perm).
* Each function (other than "command") allows multiple options! [ { ... }, { ... }, { ... } ] See examples!
*
* @author @Benzo-Fury [<@762918086349029386>]
* @version 1.0.1
* @author @Peter-MJ-Parker [<@371759410009341952>]
* @version 2.0.0
* @example
* ```ts
* import { permCheck } from "../plugins/permCheck";
* import { commandModule } from "@sern/handler";
* export default commandModule({
* plugins: [ permCheck('permission', 'No permission response') ],
* plugins: [ permCheck(["Administrator", "AddReactions"], "I am a custom response!"),
* permCheck.options([{ name: "user", needAllPerms: true, perms: ["AttachFiles", "CreateEvents"]}]),
* permCheck.subcommands([{ name: "list", needAllPerms: false, perms: ["Connect"]}]),
* permCheck.subGroups([{ name: "list", needAllPerms: false, perms: ["Connect"], response: "I am also a custom response!"}])],
* execute: (ctx) => {
* //your code here
* }
Expand All @@ -19,21 +24,238 @@
* @end
*/

import type { GuildMember, PermissionResolvable } from "discord.js";
import { CommandControlPlugin, CommandType, controller } from "@sern/handler";
export function permCheck(perm: PermissionResolvable, response: string) {
return CommandControlPlugin<CommandType.Both>(async (ctx, args) => {
if (ctx.guild === null) {
await ctx.reply("This command cannot be used here");
console.warn(
"PermCheck > A command stopped because we couldn't check a users permissions (was used in dms)",
); //delete this line if you dont want to be notified when a command is used outside of a guild/server
return controller.stop();
}
if (!(ctx.member! as GuildMember).permissions.has(perm)) {
await ctx.reply(response);
return controller.stop();
}
return controller.next();
});
import {
Colors,
EmbedBuilder,
PermissionsBitField,
type GuildMember,
type PermissionResolvable,
type TextChannel
} from 'discord.js';
import { CommandControlPlugin, type CommandType, controller, Service } from '@sern/handler';

function command(perm: PermissionResolvable, response?: string) {
return CommandControlPlugin<CommandType.Both>(async (ctx) => {
if (ctx.guild === null) {
await ctx.reply({
content: "This command cannot be used in DM's!",
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
const _perms = (ctx.member as GuildMember).permissionsIn(ctx.channel as TextChannel);
if (!_perms.has(perm)) {
await ctx.reply({
embeds: [
sendEmbed(response ?? `You are missing required permissions to run this command:\n${permsToString(perm)}`)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
if (!_perms.any(perm)) {
await ctx.reply({
embeds: [
sendEmbed(
response ??
`You need at least one of the following permissions to run this command:\n${permsToString(perm)}`
)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
return controller.next();
});
}
function subGroups(opts: BaseOptions[]) {
return CommandControlPlugin<CommandType.Slash>(async (ctx) => {
if (ctx.guild === null) {
await ctx.reply({
content: "This sub command group cannot be used in DM's!",
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
const member = ctx.member as GuildMember;
const group = ctx.options.getSubcommandGroup();
for (const opt of opts) {
if (group !== opt.name) {
await ctx.reply({
embeds: [
sendEmbed(`[PLUGIN_permCheck.subGroups]: Failed to find specified subcommandGroup \`${opt.name}\`!`)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
const _perms = member.permissionsIn(ctx.channel as TextChannel);
if (opt.needAllPerms && !_perms.has(opt.perms)) {
await ctx.reply({
embeds: [
sendEmbed(
opt.response ?? `You cannot use this group due to missing permissions: ${permsToString(opt.perms)}`
)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
if (!opt.needAllPerms && !_perms.any(opt.perms)) {
await ctx.reply({
embeds: [
sendEmbed(
opt.response ??
`You cannot use this group because you need at least one of the following permissions: ${permsToString(
opt.perms
)}`
)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
}
return controller.next();
});
}

function subcommands(opts: BaseOptions[]) {
return CommandControlPlugin<CommandType.Slash>(async (ctx) => {
if (ctx.guild === null) {
await ctx.reply({
content: "This sub command cannot be used in DM's!",
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
const member = ctx.member as GuildMember;
const sub = ctx.options.getSubcommand();
for (const { name, needAllPerms, perms, response } of opts) {
if (sub !== name) {
await ctx.reply({
embeds: [sendEmbed(`[PLUGIN_permCheck.subcommands]: Failed to find specified subcommand \`${name}\`!`)],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
const _perms = member.permissionsIn(ctx.channel as TextChannel);
if (needAllPerms && !_perms.has(perms)) {
await ctx.reply({
embeds: [
sendEmbed(response ?? `You cannot use this subcommand due to missing permissions: ${permsToString(perms)}`)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
if (!needAllPerms && !_perms.any(perms)) {
await ctx.reply({
embeds: [
sendEmbed(
response ??
`You cannot use this subcommand because you need at least the following permissions: ${permsToString(
perms
)}`
)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
}
return controller.next();
});
}
function options(opts: BaseOptions[]) {
return CommandControlPlugin<CommandType.Slash>(async (ctx) => {
if (ctx.guild === null) {
await ctx.reply({
content: "This specific option cannot be used in DM's!",
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
const member = ctx.member as GuildMember;
const channel = ctx.channel as TextChannel;

for (const { name, needAllPerms, perms, response } of opts) {
const option = ctx.options.get(name);

if (option && option.name !== name) {
await ctx.reply({
embeds: [sendEmbed(`[PLUGIN_permCheck.options]: Could not find supplied option: \`${name}\``)],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}

const permissions = member.permissionsIn(channel);

if (needAllPerms) {
if (!permissions.has(perms)) {
await ctx.reply({
embeds: [
sendEmbed(
response ??
`You need all the following permissions for option \`${name}\`:\n ${permsToString(...perms)}`
)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
} else {
if (!permissions.any(perms)) {
await ctx.reply({
embeds: [
sendEmbed(
response ??
`You need at least one of the following permissions for option \`${name}\`: \n${permsToString(
...perms
)}`
)
],
ephemeral: !ctx.isMessage()
});
return controller.stop();
}
}
}

return controller.next();
});
}
interface BaseOptions {
name: string;
perms: PermissionResolvable[];
needAllPerms: boolean;
response?: string;
}

const sendEmbed = (description: string) => {
const client = Service('@sern/client');
return new EmbedBuilder({
title: ':x: Permission Error! :x:',
description,
color: Colors.Red,
footer: {
text: client.user?.username!,
icon_url: client.user?.displayAvatarURL()!
}
});
};

export const permsToString = (...perms: PermissionResolvable[]) => {
return new PermissionsBitField(perms)
.toArray()
.map((perm) => `\`${perm}\``)
.join(', ');
};

export const permCheck = Object.assign(command, {
command,
subGroups,
subcommands,
options
});

0 comments on commit 21d18bb

Please sign in to comment.