|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+from discord import Guild, Message
|
|
|
2
|
+from discord.ext import commands
|
|
|
3
|
+from datetime import timedelta
|
|
|
4
|
+
|
|
|
5
|
+from cogs.basecog import BaseCog, BotMessage
|
|
|
6
|
+from storage import Storage
|
|
|
7
|
+
|
|
|
8
|
+class Criterion:
|
|
|
9
|
+ def __init__(self, type, **kwargs):
|
|
|
10
|
+ self.type = type
|
|
|
11
|
+ if type == 'contains':
|
|
|
12
|
+ text = kwargs['text']
|
|
|
13
|
+ self.text = text
|
|
|
14
|
+ self.test = lambda m : text.lower() in m.content.lower()
|
|
|
15
|
+ elif type == 'joinage':
|
|
|
16
|
+ min = kwargs['min']
|
|
|
17
|
+ self.min = min
|
|
|
18
|
+ self.test = lambda m : m.created_at - m.author.joined_at < min
|
|
|
19
|
+ else:
|
|
|
20
|
+ raise RuntimeError(f'Unknown criterion type "{type}"')
|
|
|
21
|
+
|
|
|
22
|
+ def matches(self, message: Message) -> bool:
|
|
|
23
|
+ return self.test(message)
|
|
|
24
|
+
|
|
|
25
|
+ @classmethod
|
|
|
26
|
+ def decode(cls, val: dict):
|
|
|
27
|
+ type = val['type']
|
|
|
28
|
+ if type == 'contains':
|
|
|
29
|
+ return Criterion(type, text=val['text'])
|
|
|
30
|
+ elif type == 'joinage':
|
|
|
31
|
+ return Criterion(type, min=timedelta(seconds=val['min']))
|
|
|
32
|
+
|
|
|
33
|
+class Pattern:
|
|
|
34
|
+ def __init__(self, criteria: list, action: str, must_match_all: bool = True):
|
|
|
35
|
+ self.criteria = criteria
|
|
|
36
|
+ self.action = action
|
|
|
37
|
+ self.must_match_all = must_match_all
|
|
|
38
|
+
|
|
|
39
|
+ def matches(self, message: Message) -> bool:
|
|
|
40
|
+ for criterion in self.criteria:
|
|
|
41
|
+ crit_matches = criterion.matches(message)
|
|
|
42
|
+ if crit_matches and not self.must_match_all:
|
|
|
43
|
+ return True
|
|
|
44
|
+ if not crit_matches and self.must_match_all:
|
|
|
45
|
+ return False
|
|
|
46
|
+ return self.must_match_all
|
|
|
47
|
+
|
|
|
48
|
+ @classmethod
|
|
|
49
|
+ def decode(cls, val: dict):
|
|
|
50
|
+ match_all = val.get('must_match_all')
|
|
|
51
|
+ action = val.get('action')
|
|
|
52
|
+ encoded_criteria = val.get('criteria')
|
|
|
53
|
+ criteria = []
|
|
|
54
|
+ for ec in encoded_criteria:
|
|
|
55
|
+ criteria.append(Criterion.decode(ec))
|
|
|
56
|
+ return Pattern(criteria, action, match_all if isinstance(match_all, bool) else True)
|
|
|
57
|
+
|
|
|
58
|
+class PatternCog(BaseCog):
|
|
|
59
|
+ def __init__(self, bot):
|
|
|
60
|
+ super().__init__(bot)
|
|
|
61
|
+
|
|
|
62
|
+ def __patterns(self, guild: Guild) -> list:
|
|
|
63
|
+ patterns = Storage.get_state_value(guild, 'pattern_patterns')
|
|
|
64
|
+ if patterns is None:
|
|
|
65
|
+ patterns_encoded = Storage.get_config_value(guild, 'pattern_patterns')
|
|
|
66
|
+ if patterns_encoded:
|
|
|
67
|
+ patterns = []
|
|
|
68
|
+ for pe in patterns_encoded:
|
|
|
69
|
+ patterns.append(Pattern.decode(pe))
|
|
|
70
|
+ Storage.set_state_value(guild, 'pattern_patterns', patterns)
|
|
|
71
|
+ return patterns
|
|
|
72
|
+
|
|
|
73
|
+ @commands.Cog.listener()
|
|
|
74
|
+ async def on_message(self, message: Message) -> None:
|
|
|
75
|
+ if message.guild is None or message.content is None:
|
|
|
76
|
+ return
|
|
|
77
|
+ patterns = self.__patterns(message.guild)
|
|
|
78
|
+ for pattern in patterns:
|
|
|
79
|
+ if pattern.matches(message):
|
|
|
80
|
+ msg = None
|
|
|
81
|
+ if pattern.action == 'delete':
|
|
|
82
|
+ await message.delete()
|
|
|
83
|
+ msg = f'Message from {message.author.mention} matched ' + \
|
|
|
84
|
+ 'banned pattern. Deleted.'
|
|
|
85
|
+ elif pattern.action == 'kick':
|
|
|
86
|
+ await message.delete()
|
|
|
87
|
+ await message.author.kick(reason='Rocketbot: Message matched banned pattern')
|
|
|
88
|
+ msg = f'Message from {message.author.mention} matched ' + \
|
|
|
89
|
+ 'banned pattern. Message deleted and user kicked.'
|
|
|
90
|
+ elif pattern.action == 'ban':
|
|
|
91
|
+ await message.delete()
|
|
|
92
|
+ await message.author.ban(reason='Rocketbot: Message matched banned pattern')
|
|
|
93
|
+ msg = f'Message from {message.author.mention} matched ' + \
|
|
|
94
|
+ 'banned pattern. Message deleted and user banned.'
|
|
|
95
|
+ if msg:
|
|
|
96
|
+ m = BotMessage(message.guild,
|
|
|
97
|
+ text = msg,
|
|
|
98
|
+ type = BotMessage.TYPE_MOD_WARNING)
|
|
|
99
|
+ m.quote = message.content
|
|
|
100
|
+ await self.post_message(m)
|
|
|
101
|
+ break
|