aboutsummaryrefslogtreecommitdiff
path: root/src/lib/common/HighlightManager.ts
blob: a74ce9ebf2925b8ba92b88483da87222108f94a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { Highlight, type BushMessage, type HighlightWord } from '#lib';
import type { Snowflake } from 'discord.js';

export class HighlightManager {
	public cachedHighlights: Map</* guild */ Snowflake, Map</* word */ HighlightWord, /* users */ Set<Snowflake>>> = new Map();
	public userLastTalkedCooldown = new Map<Snowflake, Map<Snowflake, Date>>();
	public lastedDMedUserCooldown = new Map</* user */ Snowflake, /* last dm */ Date>();

	public async syncCache() {
		const highlights = await Highlight.findAll();

		this.cachedHighlights.clear();

		for (const highlight of highlights) {
			highlight.words.forEach((word) => {
				if (!this.cachedHighlights.has(highlight.guild)) this.cachedHighlights.set(highlight.guild, new Map());
				const guildCache = this.cachedHighlights.get(highlight.guild)!;
				if (!guildCache.get(word)) guildCache.set(word, new Set());
				guildCache.get(word)!.add(highlight.user);
			});
		}
	}

	public checkMessage(message: BushMessage): Map<Snowflake, string> {
		// even if there are multiple matches, only the first one is returned
		const ret = new Map<Snowflake, string>();
		if (!message.content || !message.inGuild()) return ret;
		if (!this.cachedHighlights.has(message.guildId)) return ret;

		const guildCache = this.cachedHighlights.get(message.guildId)!;

		for (const [word, users] of guildCache.entries()) {
			if (this.isMatch(message.content, word)) {
				for (const user of users) {
					if (!ret.has(user)) ret.set(user, word.word);
				}
			}
		}

		return ret;
	}

	public async checkPhraseForUser(guild: Snowflake, user: Snowflake, phrase: string): Promise<Map<string, boolean>> {
		const highlights = await Highlight.findAll({ where: { guild, user } });

		const results = new Map<string, boolean>();

		for (const highlight of highlights) {
			for (const word of highlight.words) {
				if (this.isMatch(phrase, word)) {
					results.set(word.word, true);
				}
			}
		}

		return results;
	}

	private isMatch(phrase: string, word: HighlightWord) {
		if (word.regex) {
			return new RegExp(word.word, 'gi').test(phrase);
		} else {
			if (word.word.includes(' ')) {
				return phrase.includes(word.word);
			} else {
				const words = phrase.split(/\s*\b\s/);
				return words.includes(word.word);
			}
		}
	}
}