Skip to content

Commit 200ef61

Browse files
committed
Added /tag remove slash command as well as a confirmation page if you are an admin
1 parent ce3798a commit 200ef61

File tree

7 files changed

+189
-38
lines changed

7 files changed

+189
-38
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"moment-duration-format": "^2.3.2",
1717
"moment-timezone": "^0.5.32",
1818
"node-libcurl": "^2.3.3",
19-
"redis": "^3.1.2"
19+
"redis": "^3.1.2",
20+
"typescript": "^4.1.2"
2021
},
2122
"devDependencies": {
2223
"@types/moment-duration-format": "^2.2.2",

src/commands/interactions/slash/tag/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BaseSlashCommand } from '../../basecommand';
33
import { TagInfoCommand } from './info';
44
import { TagListGroupCommand } from './list';
55
import { TagRandomCommand } from './random';
6+
import { TagRemoveCommand } from './remove';
67
import { TagShowCommand } from './show';
78

89

@@ -16,6 +17,7 @@ export default class TagGroupCommand extends BaseSlashCommand {
1617
new TagShowCommand(),
1718
new TagInfoCommand(),
1819
new TagRandomCommand(),
20+
new TagRemoveCommand(),
1921
new TagListGroupCommand(),
2022
],
2123
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Interaction } from 'detritus-client';
2+
3+
import { Formatter, Parameters, editOrReply } from '../../../../utils';
4+
5+
import { BaseInteractionCommandOption } from '../../basecommand';
6+
7+
8+
export class TagRemoveCommand extends BaseInteractionCommandOption {
9+
description = 'Remove a tag';
10+
name = 'remove';
11+
12+
constructor() {
13+
super({
14+
options: [
15+
{
16+
name: 'name',
17+
description: 'Tag\'s Name',
18+
label: 'tag',
19+
required: true,
20+
value: Parameters.NotSoTag,
21+
onAutoComplete: Parameters.AutoComplete.tags,
22+
},
23+
],
24+
});
25+
}
26+
27+
onBeforeRun(context: Interaction.InteractionContext, args: Formatter.Commands.TagRemove.CommandArgsBefore) {
28+
return !!args.tag;
29+
}
30+
31+
onCancelRun(context: Interaction.InteractionContext, args: Formatter.Commands.TagRemove.CommandArgsBefore) {
32+
if (args.tag === false) {
33+
return editOrReply(context, '⚠ Unknown Tag');
34+
}
35+
return super.onCancelRun(context, args);
36+
}
37+
38+
async run(context: Interaction.InteractionContext, args: Formatter.Commands.TagRemove.CommandArgs) {
39+
return Formatter.Commands.TagRemove.createMessage(context, args);
40+
}
41+
}
Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,11 @@
11
import { Command, CommandClient } from 'detritus-client';
2-
import { Permissions } from 'detritus-client/lib/constants';
3-
import { Markup } from 'detritus-client/lib/utils';
42

5-
import { deleteTag } from '../../../api';
6-
import { RestResponsesRaw } from '../../../api/types';
7-
import { CommandTypes, DateMomentLogFormat, EmbedColors } from '../../../constants';
8-
import { Parameters, createTimestampMomentFromGuild, createUserEmbed, createUserString, editOrReply, fetchMemberOrUserById } from '../../../utils';
3+
import { CommandTypes } from '../../../constants';
4+
import { Formatter, Parameters, editOrReply } from '../../../utils';
95

106
import { BaseCommand } from '../basecommand';
117

128

13-
export interface CommandArgsBefore {
14-
force: boolean,
15-
tag: false | null | RestResponsesRaw.Tag,
16-
}
17-
18-
export interface CommandArgs {
19-
force: boolean,
20-
tag: RestResponsesRaw.Tag,
21-
}
22-
239
export const COMMAND_NAME = 'tag remove';
2410

2511
export default class TagRemoveCommand extends BaseCommand {
@@ -46,29 +32,18 @@ export default class TagRemoveCommand extends BaseCommand {
4632
});
4733
}
4834

49-
onBeforeRun(context: Command.Context, args: CommandArgsBefore) {
35+
onBeforeRun(context: Command.Context, args: Formatter.Commands.TagRemove.CommandArgsBefore) {
5036
return !!args.tag;
5137
}
5238

53-
onCancelRun(context: Command.Context, args: CommandArgsBefore) {
39+
onCancelRun(context: Command.Context, args: Formatter.Commands.TagRemove.CommandArgsBefore) {
5440
if (args.tag === false) {
5541
return editOrReply(context, '⚠ Unknown Tag');
5642
}
5743
return super.onCancelRun(context, args);
5844
}
5945

60-
async run(context: Command.Context, args: CommandArgs) {
61-
const { tag } = args;
62-
if (tag.user.id !== context.userId) {
63-
if (args.force) {
64-
if (!context.user.isClientOwner && !(context.member && context.member.canManageGuild)) {
65-
return editOrReply(context, '⚠ Not enough permissions to force delete a tag!');
66-
}
67-
} else {
68-
return editOrReply(context, '⚠ You\'re not the owner of this tag!');
69-
}
70-
}
71-
await deleteTag(context, {name: tag.name, serverId: context.guildId || context.channelId});
72-
return editOrReply(context, `Removed tag ${tag.name}`);
46+
async run(context: Command.Context, args: Formatter.Commands.TagRemove.CommandArgs) {
47+
return Formatter.Commands.TagRemove.createMessage(context, args);
7348
}
7449
}

src/commands/prefixed/moderation/nick.mass.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,12 @@ export default class NickMassCommand extends BaseCommand {
185185
isExecuting.nick = false;
186186

187187
embed.setColor(EmbedColors.ERROR);
188-
embed.setTitle('Mass Nickname Canceled');
188+
embed.setTitle('Mass Nickname Cancelled');
189189
{
190190
const finished = amounts.changed + amounts.skipped + amounts.failed + errors.length;
191191

192192
const description: Array<string> = [];
193-
description.push(`Canceled editing ${members.length.toLocaleString()} members (Edited ${finished.toLocaleString()} members)`);
193+
description.push(`Cancelled editing ${members.length.toLocaleString()} members (Edited ${finished.toLocaleString()} members)`);
194194
if (finished) {
195195
if (amounts.changed) {
196196
description.push(`- Changed ${amounts.changed.toLocaleString()} members successfully`);
@@ -253,12 +253,12 @@ export default class NickMassCommand extends BaseCommand {
253253

254254
if (!isExecuting.nick) {
255255
embed.setColor(EmbedColors.ERROR);
256-
embed.setTitle('Mass Nickname Canceled');
256+
embed.setTitle('Mass Nickname Cancelled');
257257
{
258258
const finished = amounts.changed + amounts.skipped + amounts.failed + errors.length;
259259

260260
const description: Array<string> = [];
261-
description.push(`Canceled editing ${members.length.toLocaleString()} members (Edited ${finished.toLocaleString()} members)`);
261+
description.push(`Cancelled editing ${members.length.toLocaleString()} members (Edited ${finished.toLocaleString()} members)`);
262262
if (finished) {
263263
if (amounts.changed) {
264264
description.push(`- Changed ${amounts.changed.toLocaleString()} members successfully`);
@@ -322,8 +322,8 @@ export default class NickMassCommand extends BaseCommand {
322322
}
323323

324324
embed.setColor(EmbedColors.ERROR);
325-
embed.setTitle('Mass Nickname Canceled');
326-
embed.setDescription(`Canceled editing ${members.length.toLocaleString()} member\'s nicknames`);
325+
embed.setTitle('Mass Nickname Cancelled');
326+
embed.setDescription(`Cancelled editing ${members.length.toLocaleString()} member\'s nicknames`);
327327
await ctx.editOrRespond({components: [], embed});
328328
},
329329
});

src/utils/formatter/commands/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import * as TagInfo from './tag.info';
3030
import * as TagListServer from './tag.list.server';
3131
import * as TagListUser from './tag.list.user';
3232
import * as TagRandom from './tag.random';
33+
import * as TagRemove from './tag.remove';
3334
import * as TagShow from './tag.show';
3435

3536
import * as ToolsHash from './tools.hash';
@@ -68,6 +69,7 @@ export {
6869
TagListServer,
6970
TagListUser,
7071
TagRandom,
72+
TagRemove,
7173
TagShow,
7274
ToolsHash,
7375
ToolsOCR,
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { Command, Interaction } from 'detritus-client';
2+
import { InteractionCallbackTypes, MessageComponentButtonStyles, Permissions } from 'detritus-client/lib/constants';
3+
import { Components, ComponentContext, Embed, Markup } from 'detritus-client/lib/utils';
4+
5+
import { deleteTag } from '../../../api';
6+
import { RestResponsesRaw } from '../../../api/types';
7+
import { DateMomentLogFormat, EmbedColors } from '../../../constants';
8+
import {
9+
createTimestampMomentFromGuild,
10+
createUserEmbed,
11+
createUserString,
12+
editOrReply,
13+
fetchMemberOrUserById,
14+
} from '../../../utils';
15+
16+
17+
export interface CommandArgsBefore {
18+
force?: boolean,
19+
tag: false | null | RestResponsesRaw.Tag,
20+
}
21+
22+
export interface CommandArgs {
23+
force?: boolean,
24+
tag: RestResponsesRaw.Tag,
25+
}
26+
27+
export async function createMessage(
28+
context: Command.Context | Interaction.InteractionContext,
29+
args: CommandArgs,
30+
) {
31+
const isFromInteraction = (context instanceof Interaction.InteractionContext);
32+
33+
const { tag } = args;
34+
if (tag.user.id !== context.userId) {
35+
const hasPermissionsToForceRemove = context.user.isClientOwner || (!tag.global && (context.member && context.member.canManageGuild));
36+
37+
if (args.force) {
38+
if (!hasPermissionsToForceRemove) {
39+
return editOrReply(context, '⚠ Not enough permissions to force remove this tag!');
40+
}
41+
} else {
42+
if (!hasPermissionsToForceRemove) {
43+
return editOrReply(context, '⚠ You\'re not the owner of this tag!');
44+
}
45+
46+
const embed = createUserEmbed(context.user);
47+
embed.setColor(EmbedColors.DEFAULT);
48+
embed.setTitle(`Force Remove Tag?`);
49+
embed.setDescription(`Tag: ${Markup.codestring(tag.name)}`);
50+
51+
{
52+
const description: Array<string> = [];
53+
54+
{
55+
const timestamp = createTimestampMomentFromGuild(tag.created, context.guildId);
56+
description.push(`**Created**: ${timestamp.fromNow()}`);
57+
description.push(`**->** ${Markup.spoiler(timestamp.format(DateMomentLogFormat))}`);
58+
}
59+
if (tag.edited) {
60+
const timestamp = createTimestampMomentFromGuild(tag.edited, context.guildId);
61+
description.push(`**Edited**: ${timestamp.fromNow()}`);
62+
description.push(`**->** ${Markup.spoiler(timestamp.format(DateMomentLogFormat))}`);
63+
}
64+
65+
// look through cache, else use the tag object
66+
description.push(`**Global**: ${(tag.global) ? 'Yes' : 'No'}`);
67+
description.push(`**NSFW**: ${(tag.nsfw) ? 'Yes' : 'No'}`);
68+
69+
{
70+
const owner = await fetchMemberOrUserById(context, tag.user.id);
71+
description.push(`**Owner**: ${createUserString(tag.user.id, owner, 'Deleted User?')}`);
72+
}
73+
74+
description.push(`**Uses**: ${tag.uses.toLocaleString()}`);
75+
76+
embed.addField('Information', description.join('\n'));
77+
}
78+
79+
const components = new Components({timeout: 5 * (60 * 1000)});
80+
components.createButton({
81+
label: 'Continue',
82+
run: async (ctx: ComponentContext) => {
83+
if (ctx.userId !== context.userId) {
84+
return ctx.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE);
85+
}
86+
87+
await deleteTag(context, {name: tag.name, serverId: context.guildId || context.channelId});
88+
embed.setColor(EmbedColors.LOG_CREATION);
89+
embed.setTitle('Successfully Force Removed Tag');
90+
await ctx.editOrRespond({components: [], embed});
91+
},
92+
});
93+
94+
components.createButton({
95+
label: 'Cancel',
96+
style: MessageComponentButtonStyles.DANGER,
97+
run: async (ctx: ComponentContext) => {
98+
if (ctx.userId !== context.userId) {
99+
return ctx.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE);
100+
}
101+
102+
embed.setColor(EmbedColors.ERROR);
103+
embed.setTitle('Cancelled Force Removal of Tag');
104+
await ctx.editOrRespond({components: [], embed});
105+
},
106+
});
107+
108+
const message = await editOrReply(context, {components, embed});
109+
components.onTimeout = async () => {
110+
try {
111+
embed.setColor(EmbedColors.ERROR);
112+
embed.setFooter('Request expired, press a button next time');
113+
if (context instanceof Interaction.InteractionContext) {
114+
await context.editResponse({components: [], embed});
115+
} else {
116+
if (message && message.canEdit) {
117+
await message.edit({components: [], embed});
118+
}
119+
}
120+
} catch(error) {
121+
122+
}
123+
};
124+
return message;
125+
}
126+
}
127+
128+
await deleteTag(context, {name: tag.name, serverId: context.guildId || context.channelId});
129+
return editOrReply(context, `Removed tag ${tag.name}`);
130+
}

0 commit comments

Comments
 (0)