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

Rename pending request channels with the amount of pending requests in that channel #136

Closed
wants to merge 12 commits into from
6 changes: 6 additions & 0 deletions config/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ request:
- '683039615837536380'
- '683040112191340560'
- '692382871578607767'
internalChannelNames:
- 'java-pending-requests'
- 'bedrock-pending-requests'
- 'earth-pending-requests'
- 'other-pending-requests'
- 'dungeons-pending-requests'
logChannel: '683039388825026562'

roleGroups:
Expand Down
9 changes: 9 additions & 0 deletions config/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ request:
- <string>
- <string>
- ...

# The names of the corresponding internal channels.
# The length of this array MUST be the same as the length of `internalChannels`.
# You MAY use the same internal channel names for multiple times.
# Optional; empty by default.
internalChannelNames:
- <string>
- <string>
- ...

# A channel which stores logs like `<volunteer> resolved <original message ID> as <emoji>.`
logChannel: <string>
Expand Down
5 changes: 5 additions & 0 deletions src/BotConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum PrependResponseMessageType {
export class RequestConfig {
public channels: string[];
public internalChannels: string[];
public internalChannelNames: string[];
public logChannel: string;

public invalidTicketEmoji: string;
Expand All @@ -35,11 +36,15 @@ export class RequestConfig {
constructor() {
this.channels = getOrDefault( 'request.channels', [] );
this.internalChannels = this.channels.length ? config.get( 'request.internalChannels' ) : getOrDefault( 'request.internalChannels', [] );
this.internalChannelNames = this.channels.length ? config.get( 'request.internalChannelNames' ) : getOrDefault( 'request.internalChannelNames', [] );
this.logChannel = config.get( 'request.logChannel' );

if ( this.channels.length !== this.internalChannels.length ) {
throw new Error( 'There are not exactly as many Request channels and ' );
}
if ( this.internalChannels.length !== this.internalChannelNames.length ) {
throw new Error( 'There are not exactly as many Internal channels and ' );

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and what?

Suggested change
throw new Error( 'There are not exactly as many Internal channels and ' );
throw new Error( 'There are not exactly as many Internal channels as associated names' );

}

this.invalidTicketEmoji = config.get( 'request.invalidTicketEmoji' );
this.noLinkEmoji = config.get( 'request.noLinkEmoji' );
Expand Down
31 changes: 17 additions & 14 deletions src/MojiraBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,20 @@ export default class MojiraBot {

const requestChannels: TextChannel[] = [];
const internalChannels = new Map<string, string>();
const internalChannelNames = new Map<string, string>();

if ( BotConfig.request.channels ) {
for ( let i = 0; i < BotConfig.request.channels.length; i++ ) {
const requestChannelId = BotConfig.request.channels[i];
const internalChannelId = BotConfig.request.internalChannels[i];
const internalChannelName = BotConfig.request.internalChannelNames[i];
try {
const requestChannel = await DiscordUtil.getChannel( requestChannelId );
const internalChannel = await DiscordUtil.getChannel( internalChannelId );
if ( requestChannel instanceof TextChannel && internalChannel instanceof TextChannel ) {
requestChannels.push( requestChannel );
internalChannels.set( requestChannelId, internalChannelId );
internalChannelNames.set( internalChannelId, internalChannelName );
// https://stackoverflow.com/questions/55153125/fetch-more-than-100-messages
const allMessages: Message[] = [];
let lastId: string | undefined;
Expand All @@ -113,7 +116,7 @@ export default class MojiraBot {
this.logger.info( `Fetched ${ allMessages.length } messages from "${ internalChannel.name }"` );

// Resolve pending resolved requests
const handler = new RequestResolveEventHandler();
const handler = new RequestResolveEventHandler( internalChannels, internalChannelNames );
for ( const message of allMessages ) {
message.reactions.cache.forEach( async reaction => {
const users = await reaction.users.fetch();
Expand All @@ -133,18 +136,18 @@ export default class MojiraBot {
}
}

if ( BotConfig.request.logChannel ) {
try {
const logChannel = await DiscordUtil.getChannel( BotConfig.request.logChannel );
if ( logChannel instanceof TextChannel ) {
await logChannel.messages.fetch( { limit: 100 } );
}
} catch ( err ) {
if ( BotConfig.request.logChannel ) {
try {
const logChannel = await DiscordUtil.getChannel( BotConfig.request.logChannel );
if ( logChannel instanceof TextChannel ) {
await logChannel.messages.fetch( { limit: 100 } );
}
} catch ( err ) {
this.logger.error( err );
}
}
}

const newRequestHandler = new RequestEventHandler( internalChannels );
const newRequestHandler = new RequestEventHandler( internalChannels, internalChannelNames );
for ( const requestChannel of requestChannels ) {
this.logger.info( `Catching up on requests from #${ requestChannel.name }...` );

Expand Down Expand Up @@ -193,11 +196,11 @@ export default class MojiraBot {
this.logger.info( 'Fully caught up on requests.' );
}

EventRegistry.add( new ReactionAddEventHandler( this.client.user.id, internalChannels ) );
EventRegistry.add( new ReactionAddEventHandler( this.client.user.id, internalChannels, internalChannelNames ) );
EventRegistry.add( new ReactionRemoveEventHandler( this.client.user.id ) );
EventRegistry.add( new MessageEventHandler( this.client.user.id, internalChannels ) );
EventRegistry.add( new MessageUpdateEventHandler( this.client.user.id, internalChannels ) );
EventRegistry.add( new MessageDeleteEventHandler( this.client.user.id, internalChannels ) );
EventRegistry.add( new MessageEventHandler( this.client.user.id, internalChannels, internalChannelNames ) );
EventRegistry.add( new MessageUpdateEventHandler( this.client.user.id, internalChannels, internalChannelNames ) );
EventRegistry.add( new MessageDeleteEventHandler( this.client.user.id, internalChannels, internalChannelNames ) );

// #region Schedule tasks.
// Filter feed tasks.
Expand Down
4 changes: 2 additions & 2 deletions src/events/message/MessageDeleteEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export default class MessageDeleteEventHandler implements EventHandler<'messageD

private readonly requestDeleteEventHandler: RequestDeleteEventHandler;

constructor( botUserId: string, internalChannels: Map<string, string> ) {
constructor( botUserId: string, internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
this.botUserId = botUserId;

this.requestDeleteEventHandler = new RequestDeleteEventHandler( internalChannels );
this.requestDeleteEventHandler = new RequestDeleteEventHandler( internalChannels, internalChannelNames );
}

// This syntax is used to ensure that `this` refers to the `MessageDeleteEventHandler` object
Expand Down
4 changes: 2 additions & 2 deletions src/events/message/MessageEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ export default class MessageEventHandler implements EventHandler<'message'> {

private readonly requestEventHandler: RequestEventHandler;

constructor( botUserId: string, internalChannels: Map<string, string> ) {
constructor( botUserId: string, internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
this.botUserId = botUserId;

this.requestEventHandler = new RequestEventHandler( internalChannels );
this.requestEventHandler = new RequestEventHandler( internalChannels, internalChannelNames );
}

// This syntax is used to ensure that `this` refers to the `MessageEventHandler` object
Expand Down
6 changes: 3 additions & 3 deletions src/events/message/MessageUpdateEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ export default class MessageUpdateEventHandler implements EventHandler<'messageU
private readonly requestEventHandler: RequestEventHandler;
private readonly requestDeleteEventHandler: RequestDeleteEventHandler;

constructor( botUserId: string, internalChannels: Map<string, string> ) {
constructor( botUserId: string, internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
this.botUserId = botUserId;

this.requestEventHandler = new RequestEventHandler( internalChannels );
this.requestDeleteEventHandler = new RequestDeleteEventHandler( internalChannels );
this.requestEventHandler = new RequestEventHandler( internalChannels, internalChannelNames );
this.requestDeleteEventHandler = new RequestDeleteEventHandler( internalChannels, internalChannelNames );
}

// This syntax is used to ensure that `this` refers to the `MessageUpdateEventHandler` object
Expand Down
7 changes: 4 additions & 3 deletions src/events/reaction/ReactionAddEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ export default class ReactionAddEventHandler implements DiscordEventHandler<'mes
private readonly botUserId: string;

private readonly roleSelectHandler = new RoleSelectEventHandler();
private readonly requestResolveEventHandler = new RequestResolveEventHandler();
private readonly requestResolveEventHandler: RequestResolveEventHandler;
private readonly requestReactionRemovalEventHandler = new RequestReactionRemovalEventHandler();
private readonly requestReopenEventHandler: RequestReopenEventHandler;

constructor( botUserId: string, internalChannels: Map<string, string> ) {
constructor( botUserId: string, internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
this.botUserId = botUserId;

const requestEventHandler = new RequestEventHandler( internalChannels );
const requestEventHandler = new RequestEventHandler( internalChannels, internalChannelNames );
this.requestReopenEventHandler = new RequestReopenEventHandler( requestEventHandler );
this.requestResolveEventHandler = new RequestResolveEventHandler( internalChannels, internalChannelNames );
}

// This syntax is used to ensure that `this` refers to the `ReactionAddEventHandler` object
Expand Down
7 changes: 6 additions & 1 deletion src/events/request/RequestDeleteEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ export default class RequestDeleteEventHandler implements EventHandler<'messageD
* A map from request channel IDs to internal channel objects.
*/
private readonly internalChannels: Map<string, string>;
private readonly internalChannelNames: Map<string, string>;

constructor( internalChannels: Map<string, string> ) {
constructor( internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
this.internalChannels = internalChannels;
this.internalChannelNames = internalChannelNames;
}

// This syntax is used to ensure that `this` refers to the `RequestDeleteEventHandler` object
Expand All @@ -25,6 +27,7 @@ export default class RequestDeleteEventHandler implements EventHandler<'messageD

const internalChannelId = this.internalChannels.get( origin.channel.id );
const internalChannel = await DiscordUtil.getChannel( internalChannelId );
const internalChannelName = this.internalChannelNames.get( internalChannelId );

if ( internalChannel && internalChannel instanceof TextChannel ) {
for ( const [, internalMessage] of internalChannel.messages.cache ) {
Expand All @@ -37,6 +40,8 @@ export default class RequestDeleteEventHandler implements EventHandler<'messageD
if ( internalMessage.deletable ) {
try {
await internalMessage.delete();
const messageCount = internalChannel.messages.cache.size;
await internalChannel.setName( `${ messageCount }-${ internalChannelName }` );
} catch ( error ) {
this.logger.error( error );
}
Expand Down
11 changes: 9 additions & 2 deletions src/events/request/RequestEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ export default class RequestEventHandler implements EventHandler<'message'> {
private logger = log4js.getLogger( 'RequestEventHandler' );

/**
* A map from request channel IDs to internal channel objects.
* A map from request channel IDs to internal channel objects and names.
*/
private readonly internalChannels: Map<string, string>;
private readonly internalChannelNames: Map<string, string>;

constructor( internalChannels: Map<string, string> ) {
constructor( internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
this.internalChannels = internalChannels;
this.internalChannelNames = internalChannelNames;

this.jira = new JiraClient( {
host: 'bugs.mojang.com',
Expand Down Expand Up @@ -101,6 +103,7 @@ export default class RequestEventHandler implements EventHandler<'message'> {

const internalChannelId = this.internalChannels.get( origin.channel.id );
const internalChannel = await DiscordUtil.getChannel( internalChannelId );
const internalChannelName = this.internalChannelNames.get( internalChannelId );

if ( internalChannel && internalChannel instanceof TextChannel ) {
const embed = new MessageEmbed()
Expand All @@ -118,6 +121,10 @@ export default class RequestEventHandler implements EventHandler<'message'> {

const copy = await internalChannel.send( response, embed ) as Message;

const messageCount = internalChannel.messages.cache.size;

await internalChannel.setName( `${ messageCount }-${ internalChannelName }` );

if ( BotConfig.request.suggestedEmoji ) {
await ReactionsUtil.reactToMessage( copy, [...BotConfig.request.suggestedEmoji] );
}
Expand Down
13 changes: 12 additions & 1 deletion src/events/request/RequestResolveEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ export default class RequestResolveEventHandler implements EventHandler<'message

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

/**
* A map from request channel IDs to internal channel objects.
*/
private readonly internalChannels: Map<string, string>;
private readonly internalChannelNames: Map<string, string>;

constructor( internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
this.internalChannels = internalChannels;
this.internalChannelNames = internalChannelNames;
}

// 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 }'` );
Expand All @@ -33,7 +44,7 @@ export default class RequestResolveEventHandler implements EventHandler<'message
if ( BotConfig.request.ignoreResolutionEmoji !== reaction.emoji.name ) {
TaskScheduler.addOneTimeMessageTask(
reaction.message,
new ResolveRequestMessageTask( reaction.emoji, user ),
new ResolveRequestMessageTask( reaction.emoji, user, this.internalChannels, this.internalChannelNames ),
BotConfig.request.resolveDelay || 0
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/events/request/RequestUnresolveEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MessageReaction, User } from 'discord.js';
import * as log4js from 'log4js';
import BotConfig, { PrependResponseMessageType } from '../../BotConfig';
import TaskScheduler from '../../tasks/TaskScheduler';
import { RequestsUtil } from '../../util/RequestsUtil'
import { RequestsUtil } from '../../util/RequestsUtil';
import EventHandler from '../EventHandler';

export default class RequestUnresolveEventHandler implements EventHandler<'messageReactionRemove'> {
Expand Down
19 changes: 18 additions & 1 deletion src/tasks/ResolveRequestMessageTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ export default class ResolveRequestMessageTask extends MessageTask {

private readonly emoji: EmojiResolvable;
private readonly user: User;
private readonly internalChannels: Map<string, string>;
private readonly internalChannelNames: Map<string, string>;

constructor( emoji: EmojiResolvable, user: User ) {
constructor( emoji: EmojiResolvable, user: User, internalChannels: Map<string, string>, internalChannelNames: Map<string, string> ) {
super();
this.emoji = emoji;
this.user = user;
this.internalChannels = internalChannels;
this.internalChannelNames = internalChannelNames;
}

public async run( copy: Message ): Promise<void> {
Expand All @@ -29,6 +33,7 @@ export default class ResolveRequestMessageTask extends MessageTask {
}

if ( origin ) {

try {
await origin.reactions.removeAll();
} catch ( error ) {
Expand All @@ -41,6 +46,18 @@ export default class ResolveRequestMessageTask extends MessageTask {
ResolveRequestMessageTask.logger.error( error );
}

const internalChannelId = this.internalChannels.get( origin.channel.id );
const internalChannel = await DiscordUtil.getChannel( internalChannelId );
const internalChannelName = this.internalChannelNames.get( internalChannelId );
if ( internalChannel && internalChannel instanceof TextChannel ) {
const messageCount = internalChannel.messages.cache.size;
try {
await internalChannel.setName( `${ messageCount }-${ internalChannelName }` );
} catch ( error ) {
ResolveRequestMessageTask.logger.error( error );
}
}

if ( BotConfig.request.logChannel ) {
const logChannel = await DiscordUtil.getChannel( BotConfig.request.logChannel );
if ( logChannel && logChannel instanceof TextChannel ) {
Expand Down