Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable bulk actions by Jira filter #140

Draft
wants to merge 34 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
3f764b4
add bulk emoji
chandler05 Dec 4, 2020
a0ae9b7
Add bulk command
chandler05 Dec 4, 2020
544d4a8
Formatting and messages
chandler05 Dec 4, 2020
6c0d3a0
Semicolon
chandler05 Dec 4, 2020
635731f
Await
chandler05 Dec 4, 2020
2dfc80d
Error
chandler05 Dec 4, 2020
9b36413
values
chandler05 Dec 5, 2020
6e6eeff
Update BulkCommand.ts
chandler05 Dec 5, 2020
37870ff
Change to arrays
chandler05 Dec 5, 2020
74580c3
spaces
chandler05 Dec 5, 2020
4e6bd21
Update BulkCommand.ts
chandler05 Dec 5, 2020
68ff39d
Merge branch 'master' into feature/bulk-actions
chandler05 Dec 5, 2020
9d04629
Merge branch 'master' into feature/bulk-actions
chandler05 Dec 6, 2020
63e0168
Rework system to work better
chandler05 Dec 6, 2020
da2fb91
Catch promise
chandler05 Dec 6, 2020
367a984
A-WAIT
chandler05 Dec 6, 2020
208f71e
Allow resolving through !jira bulk
chandler05 Dec 6, 2020
69a9820
Update src/events/request/RequestBulkRemoveEventHandler.ts
chandler05 Dec 7, 2020
9c7d8c3
Update src/commands/BulkCommand.ts
chandler05 Dec 7, 2020
27af05f
Fixes batch
chandler05 Dec 7, 2020
fc3b18c
merge branch
chandler05 Dec 7, 2020
93ef5d1
Add EmojiUtil
chandler05 Dec 7, 2020
bb6612f
Initialize properly, add deletion of messages, add to requests util
chandler05 Dec 7, 2020
a2cf642
Let to const
chandler05 Dec 7, 2020
acf0a4c
Remove bulk event handlers
chandler05 Dec 7, 2020
fed0a2b
Merge branch 'master' into feature/bulk-actions
chandler05 Dec 7, 2020
021c83c
Fix poll command not working
SPGoding Dec 7, 2020
ad442bd
Changes
chandler05 Dec 8, 2020
b139334
Merge branch 'master' into feature/bulk-actions
chandler05 May 4, 2021
3bdcbf4
Fix merge errors
chandler05 May 5, 2021
b21e1b2
Merge branch 'master' into feature/bulk-actions
chandler05 May 14, 2021
af6a76c
Refactor command to produce different results in different cases, sto…
chandler05 May 14, 2021
fa0fbb0
Fix some formatting
chandler05 May 14, 2021
a2f84c7
Changes
chandler05 May 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ request:
- ☑️
- ❌
- 💬
- 📁

ignorePrependResponseMessageEmoji: ✅
ignoreResolutionEmoji: 💬
bulkEmoji: 📁

resolveDelay: 10000
prependResponseMessage: whenResolved
Expand Down
3 changes: 3 additions & 0 deletions config/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ request:
# An emoji or emoji ID which, when used, doesn't trigger the response template message.
ignorePrependResponseMessageEmoji: <string>

# An emoji or emoji ID which indicates a request message to be added to a bulk action.
bulkEmoji: <string>

# The amount of time in milliseconds between a volunteer reacts to the message and the bot deletes its message.
resolveDelay: <number>

Expand Down
2 changes: 2 additions & 0 deletions src/BotConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class RequestConfig {
public suggestedEmoji: string[];
public ignorePrependResponseMessageEmoji: string;
public ignoreResolutionEmoji: string;
public bulkEmoji: string;
public resolveDelay: number;
public prependResponseMessage: PrependResponseMessageType;
public prependResponseMessageInLog: boolean;
Expand All @@ -49,6 +50,7 @@ export class RequestConfig {
this.suggestedEmoji = getOrDefault( 'request.suggestedEmoji', [] );
this.ignorePrependResponseMessageEmoji = config.get( 'request.ignorePrependResponseMessageEmoji' );
this.ignoreResolutionEmoji = config.get( 'request.ignoreResolutionEmoji' );
this.bulkEmoji = config.get( 'request.bulkEmoji' );

this.resolveDelay = config.get( 'request.resolveDelay' );
this.prependResponseMessage = getOrDefault( 'request.prependResponseMessage', PrependResponseMessageType.Never );
Expand Down
82 changes: 82 additions & 0 deletions src/commands/BulkCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Message, User } from 'discord.js';
import PrefixCommand from './PrefixCommand';
import MentionCommand from './MentionCommand';
import ResolveRequestMessageTask from '../tasks/ResolveRequestMessageTask';
import TaskScheduler from '../tasks/TaskScheduler';
import emojiRegex = require( 'emoji-regex/text.js' );
import { RequestsUtil } from '../util/RequestsUtil';
import BotConfig from '../BotConfig';

export default class BulkCommand extends PrefixCommand {
public readonly aliases = ['bulk', 'filter'];

public static currentBulkReactions: Map<User, Message[]>;
chandler05 marked this conversation as resolved.
Show resolved Hide resolved

public async run( message: Message, args: string ): Promise<boolean> {
let rawEmoji: string;

if ( args.length ) {
const customEmoji = /^<a?:(\w+):(\d+)>/;
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
const unicodeEmoji = emojiRegex();

if ( customEmoji.test( args ) || unicodeEmoji.test( args ) ) {
rawEmoji = args;
const emojiMatch = customEmoji.exec( args );
if ( emojiMatch ) {
rawEmoji = emojiMatch[2];
}
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
} else {
await message.channel.send( `**Error:** ${ args } is not a valid emoji.` );
return false;
}
}

let ticketKeys: string[];
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
let firstMentioned: string;

try {
const bulkMessages = BulkCommand.currentBulkReactions.get( message.author );
let originMessages: Message[];
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
for ( const bulk of bulkMessages ) {
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
originMessages.push( await RequestsUtil.getOriginMessage( bulk ) );
await bulk.reactions.cache.get( BotConfig.request.bulkEmoji ).users.remove( message.author );
}
originMessages.forEach( origin => this.getTickets( origin.content ).forEach( ticket => ticketKeys.push( ticket ) ) );
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
firstMentioned = ticketKeys[0];
if ( rawEmoji ) {
bulkMessages.forEach( resolvable => TaskScheduler.addOneTimeMessageTask(
resolvable,
new ResolveRequestMessageTask( rawEmoji, message.author ),
BotConfig.request.resolveDelay || 0
) );
SPGoding marked this conversation as resolved.
Show resolved Hide resolved
}
BulkCommand.currentBulkReactions.delete( message.author );
} catch {
return false;
}

const filter = `https://bugs.mojang.com/browse/${ firstMentioned }?jql=key%20in(${ ticketKeys.join( '%2C' ) })`;

try {
await message.channel.send( `${ message.author.toString() } ${ filter }` );
} catch {
return false;
}

return true;
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
}

private getTickets( content: string ): string[] {
let ticketMatch: RegExpExecArray;
const regex = MentionCommand.getTicketIdRegex();
const ticketMatches: string[] = [];
while ( ( ticketMatch = regex.exec( content ) ) !== null ) {
ticketMatches.push( ticketMatch[1] );
}
return ticketMatches;
}
chandler05 marked this conversation as resolved.
Show resolved Hide resolved

public asString( args: string ): string {
return `!jira bulk ${ args }`;
}
}
2 changes: 2 additions & 0 deletions src/commands/CommandRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import BugCommand from './BugCommand';
import BulkCommand from './BulkCommand';
import HelpCommand from './HelpCommand';
import PingCommand from './PingCommand';
import MooCommand from './MooCommand';
Expand All @@ -9,6 +10,7 @@ import ShutdownCommand from './ShutdownCommand';

export default class CommandRegistry {
public static BUG_COMMAND = new BugCommand();
public static BULK_COMMAND = new BulkCommand();
public static HELP_COMMAND = new HelpCommand();
public static MENTION_COMMAND = new MentionCommand();
public static MOO_COMMAND = new MooCommand();
Expand Down
5 changes: 5 additions & 0 deletions src/events/reaction/ReactionAddEventHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { MessageReaction, User } from 'discord.js';
import BotConfig from '../../BotConfig';
import DiscordEventHandler from '../EventHandler';
import RequestBulkAddEventHandler from '../request/RequestBulkAddEventHandler';
import RequestEventHandler from '../request/RequestEventHandler';
import RequestReopenEventHandler from '../request/RequestReopenEventHandler';
import RequestResolveEventHandler from '../request/RequestResolveEventHandler';
Expand All @@ -14,6 +15,7 @@ export default class ReactionAddEventHandler implements DiscordEventHandler<'mes
private readonly botUserId: string;

private readonly roleSelectHandler = new RoleSelectEventHandler();
private readonly requestBulkAddEventHandler = new RequestBulkAddEventHandler();
private readonly requestResolveEventHandler = new RequestResolveEventHandler();
private readonly requestReactionRemovalEventHandler = new RequestReactionRemovalEventHandler();
private readonly requestReopenEventHandler: RequestReopenEventHandler;
Expand All @@ -39,6 +41,9 @@ export default class ReactionAddEventHandler implements DiscordEventHandler<'mes
if ( BotConfig.roleGroups.find( g => g.message === messageReaction.message.id ) ) {
// Handle role selection
return this.roleSelectHandler.onEvent( messageReaction, user );
} else if ( BotConfig.request.internalChannels.includes( messageReaction.message.channel.id ) && messageReaction.emoji.name === BotConfig.request.bulkEmoji ) {
// Handle adding a request to a bulk action
return this.requestBulkAddEventHandler.onEvent( messageReaction, user );
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
} else if ( BotConfig.request.internalChannels.includes( messageReaction.message.channel.id ) ) {
// Handle resolving user request
return this.requestResolveEventHandler.onEvent( messageReaction, user );
Expand Down
5 changes: 5 additions & 0 deletions src/events/reaction/ReactionRemoveEventHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { MessageReaction, User } from 'discord.js';
import BotConfig from '../../BotConfig';
import EventHandler from '../EventHandler';
import RequestBulkRemoveEventHandler from '../request/RequestBulkRemoveEventHandler';
import RequestUnresolveEventHandler from '../request/RequestUnresolveEventHandler';
import RoleRemoveEventHandler from '../roles/RoleRemoveEventHandler';
import MojiraBot from '../../MojiraBot';
Expand All @@ -12,6 +13,7 @@ export default class ReactionRemoveEventHandler implements EventHandler<'message

private readonly roleRemoveHandler = new RoleRemoveEventHandler();
private readonly requestUnresolveEventHandler = new RequestUnresolveEventHandler();
private readonly requestBulkRemoveEventHandler = new RequestBulkRemoveEventHandler();

constructor( botUserId: string ) {
this.botUserId = botUserId;
Expand All @@ -30,6 +32,9 @@ export default class ReactionRemoveEventHandler implements EventHandler<'message
if ( BotConfig.roleGroups.find( g => g.message === messageReaction.message.id ) ) {
// Handle role removal
return this.roleRemoveHandler.onEvent( messageReaction, user );
} else if ( BotConfig.request.internalChannels.includes( messageReaction.message.channel.id ) && messageReaction.emoji.name === BotConfig.request.bulkEmoji ) {
// Handle removing a request from a bulk action
return this.requestBulkRemoveEventHandler.onEvent( messageReaction, user );
} else if ( BotConfig.request.internalChannels.includes( messageReaction.message.channel.id ) ) {
// Handle unresolving user request
return this.requestUnresolveEventHandler.onEvent( messageReaction, user );
Expand Down
21 changes: 21 additions & 0 deletions src/events/request/RequestBulkAddEventHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { MessageReaction, User } from 'discord.js';
import * as log4js from 'log4js';
import EventHandler from '../EventHandler';
import BulkCommand from '../../commands/BulkCommand';

export default class RequestBulkAddEventHandler implements EventHandler<'messageReactionAdd'> {
public readonly eventName = 'messageReactionAdd';

private logger = log4js.getLogger( 'RequestBulkAddEventHandler' );

// This syntax is used to ensure that `this` refers to the `RequestResolveEventHandler` object
public onEvent = async ( reaction: MessageReaction, user: User ): Promise<void> => {
this.logger.info( `User ${ user.tag } added '${ reaction.emoji.name }' reaction to request message '${ reaction.message.id }'` );

if ( BulkCommand.currentBulkReactions.has( user ) ) {
BulkCommand.currentBulkReactions.get( user ).push( reaction.message );
} else {
BulkCommand.currentBulkReactions.set( user, [reaction.message] );
}
};
}
27 changes: 27 additions & 0 deletions src/events/request/RequestBulkRemoveEventHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { MessageReaction, User } from 'discord.js';
import * as log4js from 'log4js';
import BulkCommand from '../../commands/BulkCommand';
import EventHandler from '../EventHandler';

export default class RequestBulkRemoveEventHandler implements EventHandler<'messageReactionRemove'> {
public readonly eventName = 'messageReactionRemove';

private logger = log4js.getLogger( 'RequestBulkRemoveEventHandler' );

// This syntax is used to ensure that `this` refers to the `RequestResolveEventHandler` object
public onEvent = async ( reaction: MessageReaction, user: User ): Promise<void> => {
this.logger.info( `User ${ user.tag } removed '${ reaction.emoji.name }' reaction from request message '${ reaction.message.id }'` );

if ( BulkCommand.currentBulkReactions.has( user ) ) {
const currentMessages = BulkCommand.currentBulkReactions.get( user );
for ( let i = 0; i <= currentMessages.length; i++ ) {
const currentMessage = currentMessages[i];
if ( currentMessage === reaction.message ) {
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
BulkCommand.currentBulkReactions.delete( user );
BulkCommand.currentBulkReactions.set( user, currentMessages.splice( i, 1 ) );
chandler05 marked this conversation as resolved.
Show resolved Hide resolved
break;
}
}
}
};
}