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

feat: 絵文字が作成されたら #無法地帯 にログを送信する機能の追加 #141

Merged
merged 17 commits into from
May 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 18 additions & 0 deletions src/adaptor/emoji-proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Client } from 'discord.js';
import type { EmojiData } from '../service/emoji-log';
import type { EmojiEventProvider } from '../runner';

export type EmojiHandler<E> = (emoji: E) => Promise<void>;

export class EmojiProxy implements EmojiEventProvider<EmojiData> {
constructor(private readonly client: Client) {}

onEmojiCreate(handler: EmojiHandler<EmojiData>): void {
this.client.on('emojiCreate', (emoji) =>
handler({
emoji: emoji.toString(),
emojiAuthorId: emoji.author?.id ?? undefined
})
);
}
}
46 changes: 46 additions & 0 deletions src/runner/emoji.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export type EmojiEvent = 'CREATE';

export interface EmojiEventResponder<E> {
on(event: EmojiEvent, emoji: E): Promise<void>;
}

export const composeEmojiEventResponders = <E>(
...responders: readonly EmojiEventResponder<E>[]
): EmojiEventResponder<E> => ({
async on(event, emoji) {
await Promise.all(
responders.map((responder) => responder.on(event, emoji))
);
}
});

export interface EmojiEventProvider<E> {
onEmojiCreate(handler: (emoji: E) => Promise<void>): void;
}

export class EmojiResponseRunner<
E,
R extends EmojiEventResponder<E> = EmojiEventResponder<E>
> {
constructor(provider: EmojiEventProvider<E>) {
provider.onEmojiCreate((emoji) => this.triggerEvent('CREATE', emoji));
}

private async triggerEvent(event: EmojiEvent, emoji: E): Promise<void> {
try {
await Promise.all(this.responders.map((res) => res.on(event, emoji)));
} catch (e) {
console.error(e);
}
}

private responders: R[] = [];

addResponder(responder: R) {
this.responders.push(responder);
}

getResponders(): readonly R[] {
return this.responders;
}
}
1 change: 1 addition & 0 deletions src/runner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './message';
export * from './schedule';
export * from './voice-room';
export * from './role';
export * from './emoji';
9 changes: 8 additions & 1 deletion src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
CommandResponder
} from '../service/command-message';
import {
EmojiResponseRunner,
MessageResponseRunner,
MessageUpdateResponseRunner,
RoleResponseRunner,
Expand All @@ -28,6 +29,7 @@ import {
} from '../runner';
import { type VoiceChannelParticipant, VoiceDiff } from '../service/voice-diff';
import {
allEmojiResponder,
allMessageEventResponder,
allMessageUpdateEventResponder,
allRoleResponder,
Expand All @@ -37,6 +39,7 @@ import type { AssetKey } from '../service/party';
import { DiscordMemberStats } from '../adaptor/discord-member-stats';
import { DiscordRoleManager } from '../adaptor/discord-role';
import { DiscordSheriff } from '../adaptor/discord-sheriff';
import { EmojiProxy } from '../adaptor/emoji-proxy';
import type { KaereMusicKey } from '../service/kaere';
import { Snowflake } from '../model/id';
import dotenv from 'dotenv';
Expand All @@ -56,7 +59,8 @@ const intents = new Intents();
intents.add(
Intents.FLAGS.GUILDS, // GUILD_CREATE による初期化
Intents.FLAGS.GUILD_MESSAGES, // ほとんどのメッセージに反応する機能
Intents.FLAGS.GUILD_VOICE_STATES // VoiceDiff 機能
Intents.FLAGS.GUILD_VOICE_STATES, // VoiceDiff 機能
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS // EmojiLog機能
);

const client = new Client({ intents });
Expand Down Expand Up @@ -141,6 +145,9 @@ roleRunner.addResponder(
);
roleProxy(client, roleRunner);

const emojiRunner = new EmojiResponseRunner(new EmojiProxy(client));
emojiRunner.addResponder(allEmojiResponder(output));

client.once('ready', () => {
readyLog(client);
});
Expand Down
30 changes: 30 additions & 0 deletions src/service/emoji-log.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { EmojiLog } from './emoji-log';

test('create emoji', async () => {
const sendEmbed = jest.fn(() => Promise.resolve());
const responder = new EmojiLog({ sendEmbed });
await responder.on('CREATE', {
emoji: '<:kawaehand:903283802443501618>',
emojiAuthorId: '586824421470109716'
});

expect(sendEmbed).toHaveBeenCalledWith({
title: '絵文字警察',
description:
'<@586824421470109716> が <:kawaehand:903283802443501618> を作成しました'
});
});

test('create emoji(author undefined)', async () => {
const sendEmbed = jest.fn(() => Promise.resolve());
const responder = new EmojiLog({ sendEmbed });
await responder.on('CREATE', {
emoji: '<:kawaehand:903283802443501618>',
emojiAuthorId: undefined
});

expect(sendEmbed).toHaveBeenCalledWith({
title: '絵文字警察',
description: '誰かが <:kawaehand:903283802443501618> を作成しました'
});
});
29 changes: 29 additions & 0 deletions src/service/emoji-log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { EmojiEventResponder, RoleEvent } from '../runner';
import type { StandardOutput } from './output';

export interface EmojiData {
emoji: string;
emojiAuthorId: string | undefined;
}

export class EmojiLog implements EmojiEventResponder<EmojiData> {
constructor(private readonly output: StandardOutput) {}
async on(event: RoleEvent, role: EmojiData): Promise<void> {
if (event !== 'CREATE') {
return;
}

if (role.emojiAuthorId == undefined) {
await this.output.sendEmbed({
title: '絵文字警察',
description: `誰かが ${role.emoji} を作成しました`
});
return;
}

await this.output.sendEmbed({
title: '絵文字警察',
description: `<@${role.emojiAuthorId}> が ${role.emoji} を作成しました`
});
}
}
5 changes: 5 additions & 0 deletions src/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
type Clock,
type MessageResponseRunner,
ScheduleRunner,
composeEmojiEventResponders,
composeMessageEventResponders,
composeMessageUpdateEventResponders,
composeRoleEventResponders
Expand All @@ -31,6 +32,7 @@ import {
type TypoRepository
} from './typo-record';
import { DifferenceDetector } from './difference-detector';
import { EmojiLog } from './emoji-log';
import { HelpCommand } from './help';
import { Meme } from './meme';
import type { Snowflake } from '../model/id';
Expand Down Expand Up @@ -90,3 +92,6 @@ export const allRoleResponder = (
composeRoleEventResponders(
new KawaemonHasAllRoles(kawaemonId, roleManager, output)
);

export const allEmojiResponder = (output: StandardOutput) =>
composeEmojiEventResponders(new EmojiLog(output));