signalblast 0.0.1.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- signalblast/__init__.py +0 -0
- signalblast/admin.py +84 -0
- signalblast/bot_answers.py +537 -0
- signalblast/bot_commands.py +84 -0
- signalblast/broadcastbot.py +124 -0
- signalblast/main.py +125 -0
- signalblast/message_handler.py +77 -0
- signalblast/users.py +58 -0
- signalblast/utils.py +29 -0
- signalblast-0.0.1.dev0.dist-info/LICENSE +674 -0
- signalblast-0.0.1.dev0.dist-info/METADATA +54 -0
- signalblast-0.0.1.dev0.dist-info/RECORD +13 -0
- signalblast-0.0.1.dev0.dist-info/WHEEL +4 -0
signalblast/__init__.py
ADDED
|
File without changes
|
signalblast/admin.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import bcrypt
|
|
5
|
+
|
|
6
|
+
from signalblast.utils import get_code_data_path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Admin:
|
|
10
|
+
save_path = get_code_data_path() / "admin.txt"
|
|
11
|
+
|
|
12
|
+
def __init__(self) -> None:
|
|
13
|
+
self.admin_id: str = None
|
|
14
|
+
self._hashed_password: str = None
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
async def create(cls, admin_password: Optional[str]) -> None:
|
|
18
|
+
self = Admin()
|
|
19
|
+
self.admin_id = None
|
|
20
|
+
await self.set_hashed_password(admin_password)
|
|
21
|
+
return self
|
|
22
|
+
|
|
23
|
+
def get_hashed_password(self):
|
|
24
|
+
return self._hashed_password
|
|
25
|
+
|
|
26
|
+
async def set_hashed_password(self, password: str):
|
|
27
|
+
if password is None:
|
|
28
|
+
self._hashed_password = "".encode()
|
|
29
|
+
else:
|
|
30
|
+
self._hashed_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
|
|
31
|
+
await self.save_to_file()
|
|
32
|
+
|
|
33
|
+
async def add(self, id: str, admin_password: Optional[str]) -> bool:
|
|
34
|
+
if admin_password is None:
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
if bcrypt.checkpw(admin_password.encode(), self.get_hashed_password()):
|
|
38
|
+
self.admin_id = id
|
|
39
|
+
await self.save_to_file()
|
|
40
|
+
return True
|
|
41
|
+
else:
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
async def remove(self, admin_password: Optional[str]) -> bool:
|
|
45
|
+
if admin_password is None:
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
if bcrypt.checkpw(admin_password.encode(), self.get_hashed_password()):
|
|
49
|
+
self.admin_id = None
|
|
50
|
+
await self.save_to_file()
|
|
51
|
+
return True
|
|
52
|
+
else:
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
async def save_to_file(self) -> None:
|
|
56
|
+
with open(self.save_path, "w") as f:
|
|
57
|
+
if self.admin_id is None:
|
|
58
|
+
f.write("\n")
|
|
59
|
+
else:
|
|
60
|
+
f.write(self.admin_id + "\n")
|
|
61
|
+
f.write(self.get_hashed_password().decode())
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
async def _load_from_file() -> "Admin":
|
|
65
|
+
admin = Admin()
|
|
66
|
+
with open(Admin.save_path, "r") as f:
|
|
67
|
+
admin.admin_id = f.readline().rstrip()
|
|
68
|
+
admin._hashed_password = f.readline().encode()
|
|
69
|
+
|
|
70
|
+
if admin.admin_id == "":
|
|
71
|
+
admin.admin_id = None
|
|
72
|
+
|
|
73
|
+
return admin
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
async def load_from_file(admin_password: Optional[str]) -> "Admin":
|
|
77
|
+
if not os.path.exists(Admin.save_path):
|
|
78
|
+
return await Admin.create(admin_password)
|
|
79
|
+
|
|
80
|
+
admin = await Admin._load_from_file()
|
|
81
|
+
# Overwrite the password in the file, if no password was given assume we want to keep the one from the file
|
|
82
|
+
if admin_password is not None:
|
|
83
|
+
await admin.set_hashed_password(admin_password)
|
|
84
|
+
return admin
|
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
from asyncio import gather
|
|
3
|
+
from re import Pattern
|
|
4
|
+
|
|
5
|
+
from signalbot import Command
|
|
6
|
+
from signalbot import Context as ChatContext
|
|
7
|
+
|
|
8
|
+
from signalblast.bot_commands import AdminCommandStrings, CommandRegex, PublicCommandStrings
|
|
9
|
+
from signalblast.broadcastbot import BroadcasBot
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def triggered(pattern: Pattern):
|
|
13
|
+
def decorator_triggered(func):
|
|
14
|
+
@functools.wraps(func)
|
|
15
|
+
async def wrapper_triggered(*args, **kwargs):
|
|
16
|
+
c: ChatContext = args[1]
|
|
17
|
+
text = c.message.text
|
|
18
|
+
if not isinstance(text, str):
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
if pattern.match(text) is None:
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
return await func(*args, **kwargs)
|
|
25
|
+
|
|
26
|
+
return wrapper_triggered
|
|
27
|
+
|
|
28
|
+
return decorator_triggered
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Subscribe(Command):
|
|
32
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
33
|
+
super().__init__()
|
|
34
|
+
self.broadcastbot = bot
|
|
35
|
+
|
|
36
|
+
async def subscribe(self, ctx: ChatContext, verbose: bool = False) -> None:
|
|
37
|
+
try:
|
|
38
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
39
|
+
if subscriber_uuid in self.broadcastbot.subscribers:
|
|
40
|
+
if verbose:
|
|
41
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Already subscribed!")
|
|
42
|
+
self.broadcastbot.logger.info("Already subscribed!")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
if subscriber_uuid in self.broadcastbot.banned_users:
|
|
46
|
+
if verbose:
|
|
47
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "This number is not allowed to subscribe")
|
|
48
|
+
self.broadcastbot.logger.info(f"{subscriber_uuid} was not allowed to subscribe")
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
await self.broadcastbot.subscribers.add(subscriber_uuid, ctx.message.source_number)
|
|
52
|
+
if verbose:
|
|
53
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Subscription successful!")
|
|
54
|
+
# if self.broadcastbot.expiration_time is not None:
|
|
55
|
+
# await ctx.bot.set_expiration(subscriber_uuid, self.broadcastbot.expiration_time)
|
|
56
|
+
self.broadcastbot.logger.info(f"{subscriber_uuid} subscribed")
|
|
57
|
+
except Exception as e:
|
|
58
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
59
|
+
try:
|
|
60
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Could not subscribe!")
|
|
61
|
+
except Exception as e:
|
|
62
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
63
|
+
|
|
64
|
+
@triggered(CommandRegex.subscribe)
|
|
65
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
66
|
+
await Subscribe.subscribe(self, ctx, verbose=True)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Unsubscribe(Command):
|
|
70
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
71
|
+
super().__init__()
|
|
72
|
+
self.broadcastbot = bot
|
|
73
|
+
|
|
74
|
+
@triggered(CommandRegex.unsubscribe)
|
|
75
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
76
|
+
try:
|
|
77
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
78
|
+
|
|
79
|
+
if subscriber_uuid not in self.broadcastbot.subscribers:
|
|
80
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Not subscribed!")
|
|
81
|
+
self.broadcastbot.logger.info(f"{subscriber_uuid} tried to unsubscribe but they are not subscribed")
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
await self.broadcastbot.subscribers.remove(subscriber_uuid)
|
|
85
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Successfully unsubscribed!")
|
|
86
|
+
self.broadcastbot.logger.info(f"{subscriber_uuid} unsubscribed")
|
|
87
|
+
except Exception as e:
|
|
88
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
89
|
+
try:
|
|
90
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Could not unsubscribe!")
|
|
91
|
+
except Exception as e:
|
|
92
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
93
|
+
# finally:
|
|
94
|
+
# raise StopPropagation
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Broadcast(Command):
|
|
98
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
99
|
+
super().__init__()
|
|
100
|
+
self.broadcastbot = bot
|
|
101
|
+
|
|
102
|
+
def is_valid_command(self, message: str, invalid_command: Pattern) -> bool:
|
|
103
|
+
regex: Pattern
|
|
104
|
+
for regex in CommandRegex:
|
|
105
|
+
if regex != invalid_command and regex.search(message) is not None:
|
|
106
|
+
return True
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
async def broadcast(bot: BroadcasBot, ctx: ChatContext) -> None:
|
|
111
|
+
num_broadcasts = 0
|
|
112
|
+
num_subscribers = -1
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
116
|
+
if subscriber_uuid in bot.banned_users:
|
|
117
|
+
await bot.send(subscriber_uuid, "This number is not allowed to broadcast messages")
|
|
118
|
+
bot.logger.info(f"{subscriber_uuid} tried to broadcast but they are banned")
|
|
119
|
+
return
|
|
120
|
+
|
|
121
|
+
if subscriber_uuid not in bot.subscribers:
|
|
122
|
+
await bot.send(subscriber_uuid, bot.must_subscribe_message)
|
|
123
|
+
bot.logger.info(f"{subscriber_uuid} tried to broadcast but they are not subscribed")
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
num_subscribers = len(bot.subscribers)
|
|
127
|
+
|
|
128
|
+
# await ctx.message.mark_read()
|
|
129
|
+
message = bot.message_handler.remove_command_from_message(ctx.message.text, PublicCommandStrings.broadcast)
|
|
130
|
+
attachments = bot.message_handler.empty_list_to_none(ctx.message.base64_attachments)
|
|
131
|
+
# link_previews = bot.message_handler.empty_list_to_none(ctx.message.data_message.previews)
|
|
132
|
+
|
|
133
|
+
if message is None and attachments is None:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
if message is None:
|
|
137
|
+
message = ""
|
|
138
|
+
|
|
139
|
+
# Broadcast message to all subscribers.
|
|
140
|
+
send_tasks = [None] * len(bot.subscribers)
|
|
141
|
+
|
|
142
|
+
for i, subscriber in enumerate(bot.subscribers):
|
|
143
|
+
send_tasks[i] = bot.send(subscriber, message, base64_attachments=attachments)
|
|
144
|
+
# link_previews=link_previews)
|
|
145
|
+
|
|
146
|
+
send_task_results = await gather(*send_tasks)
|
|
147
|
+
|
|
148
|
+
for send_task_result in send_task_results:
|
|
149
|
+
if isinstance(send_task_result, str):
|
|
150
|
+
num_broadcasts += 1
|
|
151
|
+
bot.logger.info(f"Message successfully sent to {subscriber}")
|
|
152
|
+
else:
|
|
153
|
+
bot.logger.warning(f"Could not send message to {subscriber}")
|
|
154
|
+
await bot.subscribers.remove(ctx.message.source_uuid)
|
|
155
|
+
|
|
156
|
+
attachments_filenames = bot.message_handler.empty_list_to_none(ctx.message.attachments_filenames)
|
|
157
|
+
bot.message_handler.delete_attachments(attachments_filenames, link_previews=None)
|
|
158
|
+
|
|
159
|
+
await bot.reply_with_warn_on_failure(ctx, f"Message sent to {num_broadcasts - 1} people")
|
|
160
|
+
except Exception as e:
|
|
161
|
+
bot.logger.error(e, exc_info=True)
|
|
162
|
+
try:
|
|
163
|
+
error_str = "Something went wrong when sending the message"
|
|
164
|
+
if num_broadcasts == num_subscribers:
|
|
165
|
+
error_str += ", but it was sent to everybody"
|
|
166
|
+
error_str += ", please contact the admin if the problem persists"
|
|
167
|
+
await bot.reply_with_warn_on_failure(ctx, error_str)
|
|
168
|
+
except Exception as e:
|
|
169
|
+
bot.logger.error(e, exc_info=True)
|
|
170
|
+
# finally:
|
|
171
|
+
# raise StopPropagation
|
|
172
|
+
|
|
173
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
174
|
+
message = ctx.message.text
|
|
175
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
176
|
+
if message is None:
|
|
177
|
+
if ctx.message.base64_attachments == []:
|
|
178
|
+
self.broadcastbot.logger.info(f"Received reaction, sticker or similar from {subscriber_uuid}")
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
# Only attachment, assume the user wants to forward that
|
|
182
|
+
self.broadcastbot.logger.info(f"Received a file from {subscriber_uuid}, broadcasting!")
|
|
183
|
+
await Broadcast.broadcast(self.broadcastbot, ctx)
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
if self.is_valid_command(message, invalid_command=CommandRegex.broadcast):
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
if subscriber_uuid not in self.broadcastbot.subscribers:
|
|
190
|
+
await Subscribe(bot=self.broadcastbot).subscribe(ctx)
|
|
191
|
+
|
|
192
|
+
# By default broadcast all the messages
|
|
193
|
+
await Broadcast.broadcast(self.broadcastbot, ctx)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class DisplayHelp(Command):
|
|
197
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
198
|
+
super().__init__()
|
|
199
|
+
self.broadcastbot = bot
|
|
200
|
+
|
|
201
|
+
def _get_help_message(self, input_message: str, subscriber_uuid: str) -> str:
|
|
202
|
+
if input_message.startswith(PublicCommandStrings.help):
|
|
203
|
+
is_wrong_command = False
|
|
204
|
+
else:
|
|
205
|
+
is_wrong_command = True
|
|
206
|
+
|
|
207
|
+
if subscriber_uuid != self.broadcastbot.admin.admin_id:
|
|
208
|
+
if is_wrong_command:
|
|
209
|
+
return self.broadcastbot.wrong_command_message
|
|
210
|
+
else:
|
|
211
|
+
return self.broadcastbot.help_message
|
|
212
|
+
else:
|
|
213
|
+
if is_wrong_command:
|
|
214
|
+
return self.broadcastbot.admin_wrong_command_message
|
|
215
|
+
else:
|
|
216
|
+
return self.broadcastbot.admin_help_message
|
|
217
|
+
|
|
218
|
+
@triggered(CommandRegex.help)
|
|
219
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
220
|
+
try:
|
|
221
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
222
|
+
message = ctx.message.text
|
|
223
|
+
|
|
224
|
+
help_message = self._get_help_message(message, subscriber_uuid)
|
|
225
|
+
|
|
226
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, help_message)
|
|
227
|
+
self.broadcastbot.logger.info(f"Sent help message to {subscriber_uuid}")
|
|
228
|
+
except Exception as e:
|
|
229
|
+
# if isinstance(e, StopPropagation):
|
|
230
|
+
# raise
|
|
231
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class AddAdmin(Command):
|
|
235
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
236
|
+
super().__init__()
|
|
237
|
+
self.broadcastbot = bot
|
|
238
|
+
|
|
239
|
+
@triggered(CommandRegex.add_admin)
|
|
240
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
241
|
+
try:
|
|
242
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
243
|
+
password = self.broadcastbot.message_handler.remove_command_from_message(
|
|
244
|
+
ctx.message.text, AdminCommandStrings.add_admin
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
previous_admin = self.broadcastbot.admin.admin_id
|
|
248
|
+
if await self.broadcastbot.admin.add(subscriber_uuid, password):
|
|
249
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "You have been added as admin!")
|
|
250
|
+
if previous_admin is not None and subscriber_uuid != previous_admin:
|
|
251
|
+
msg_to_admin = self.broadcastbot.message_handler.compose_message_to_admin(
|
|
252
|
+
"You are no longer an admin!", subscriber_uuid
|
|
253
|
+
)
|
|
254
|
+
await self.broadcastbot.send(previous_admin, msg_to_admin)
|
|
255
|
+
log_message = f"Previous admin was {previous_admin}, new admin is {subscriber_uuid}"
|
|
256
|
+
self.broadcastbot.logger.info(log_message)
|
|
257
|
+
else:
|
|
258
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Adding failed, admin password is incorrect!")
|
|
259
|
+
if previous_admin is not None:
|
|
260
|
+
msg_to_admin = self.broadcastbot.message_handler.compose_message_to_admin(
|
|
261
|
+
"Tried to be added as admin", subscriber_uuid
|
|
262
|
+
)
|
|
263
|
+
await self.broadcastbot.send(previous_admin, msg_to_admin)
|
|
264
|
+
self.broadcastbot.logger.warning(f"{subscriber_uuid} failed password check for add_admin")
|
|
265
|
+
except Exception as e:
|
|
266
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
267
|
+
# finally:
|
|
268
|
+
# raise StopPropagation
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class RemoveAdmin(Command):
|
|
272
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
273
|
+
super().__init__()
|
|
274
|
+
self.broadcastbot = bot
|
|
275
|
+
|
|
276
|
+
@triggered(CommandRegex.remove_admin)
|
|
277
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
278
|
+
try:
|
|
279
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
280
|
+
password = self.broadcastbot.message_handler.remove_command_from_message(
|
|
281
|
+
ctx.message.get_body(), AdminCommandStrings.remove_admin
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
previous_admin = self.broadcastbot.admin.admin_id
|
|
285
|
+
if await self.broadcastbot.admin.remove(password):
|
|
286
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Admin has been removed!")
|
|
287
|
+
if previous_admin is not None and subscriber_uuid != previous_admin:
|
|
288
|
+
msg_to_admin = self.broadcastbot.message_handler.compose_message_to_admin(
|
|
289
|
+
"You are no longer an admin!", subscriber_uuid
|
|
290
|
+
)
|
|
291
|
+
await self.broadcastbot.send(previous_admin, msg_to_admin)
|
|
292
|
+
self.broadcastbot.logger.info(f"{previous_admin} is no longer an admin")
|
|
293
|
+
else:
|
|
294
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Removing failed: admin password is incorrect!")
|
|
295
|
+
if previous_admin is not None:
|
|
296
|
+
msg_to_admin = self.broadcastbot.message_handler.compose_message_to_admin(
|
|
297
|
+
"Tried to remove you as admin", subscriber_uuid
|
|
298
|
+
)
|
|
299
|
+
await self.broadcastbot.send(previous_admin, msg_to_admin)
|
|
300
|
+
self.broadcastbot.logger.warning(f"Failed password check for remove_admin {subscriber_uuid}")
|
|
301
|
+
except Exception as e:
|
|
302
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
303
|
+
# finally:
|
|
304
|
+
# raise StopPropagation
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class MessageToAdmin(Command):
|
|
308
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
309
|
+
super().__init__()
|
|
310
|
+
self.broadcastbot = bot
|
|
311
|
+
|
|
312
|
+
@triggered(CommandRegex.msg_to_admin)
|
|
313
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
314
|
+
try:
|
|
315
|
+
subscriber_uuid = ctx.message.source_uuid
|
|
316
|
+
message = self.broadcastbot.message_handler.remove_command_from_message(
|
|
317
|
+
ctx.message.get_body(), PublicCommandStrings.msg_to_admin
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
if self.broadcastbot.admin.admin_id is None:
|
|
321
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "I'm sorry but there are no admins to contact!")
|
|
322
|
+
self.broadcastbot.logger.info(f"Tried to contact an admin but there is none! {subscriber_uuid}")
|
|
323
|
+
return
|
|
324
|
+
|
|
325
|
+
if subscriber_uuid in self.broadcastbot.banned_users:
|
|
326
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "You are not allowed to contact the admin!")
|
|
327
|
+
self.broadcastbot.logger.info(f"Banned user {subscriber_uuid} tried to contact admin")
|
|
328
|
+
return
|
|
329
|
+
|
|
330
|
+
msg_to_admin = self.broadcastbot.message_handler.compose_message_to_admin(
|
|
331
|
+
"Sent you message:\n", subscriber_uuid
|
|
332
|
+
)
|
|
333
|
+
msg_to_admin += message
|
|
334
|
+
attachments = self.broadcastbot.message_handler.empty_list_to_none(ctx.message.data_message.attachments)
|
|
335
|
+
await self.broadcastbot.send(self.broadcastbot.admin.admin_id, msg_to_admin, attachments=attachments)
|
|
336
|
+
self.broadcastbot.logger.info(
|
|
337
|
+
f"Sent message from {subscriber_uuid} to admin {self.broadcastbot.admin.admin_id}"
|
|
338
|
+
)
|
|
339
|
+
except Exception as e:
|
|
340
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
341
|
+
try:
|
|
342
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Failed to send the message to the admin!")
|
|
343
|
+
except Exception as e:
|
|
344
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
345
|
+
# finally:
|
|
346
|
+
# raise StopPropagation
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class MessageFromAdmin(Command):
|
|
350
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
351
|
+
super().__init__()
|
|
352
|
+
self.broadcastbot = bot
|
|
353
|
+
|
|
354
|
+
@triggered(CommandRegex.msg_from_admin)
|
|
355
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
356
|
+
try:
|
|
357
|
+
message = self.broadcastbot.message_handler.remove_command_from_message(
|
|
358
|
+
ctx.message.get_body(), AdminCommandStrings.msg_from_admin
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
if not await self.broadcastbot.is_user_admin(ctx, AdminCommandStrings.msg_from_admin):
|
|
362
|
+
return
|
|
363
|
+
|
|
364
|
+
user_id, message = message.split(" ", 1)
|
|
365
|
+
|
|
366
|
+
if user_id not in self.broadcastbot.subscribers:
|
|
367
|
+
if " " in message:
|
|
368
|
+
confirmation, message = message.split(" ", 1)
|
|
369
|
+
else:
|
|
370
|
+
confirmation = None
|
|
371
|
+
if confirmation != "!force":
|
|
372
|
+
warn_message = "User is not in subscribers list, use !reply <uuid> !force to message them"
|
|
373
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, warn_message)
|
|
374
|
+
return
|
|
375
|
+
|
|
376
|
+
message = "Admin: " + message
|
|
377
|
+
attachments = self.broadcastbot.message_handler.empty_list_to_none(ctx.message.data_message.attachments)
|
|
378
|
+
|
|
379
|
+
await self.broadcastbot.send(user_id, message, attachments=attachments)
|
|
380
|
+
self.broadcastbot.logger.info(
|
|
381
|
+
f"Sent message from admin {self.broadcastbot.admin.admin_id} to user {user_id}"
|
|
382
|
+
)
|
|
383
|
+
except Exception as e:
|
|
384
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
385
|
+
try:
|
|
386
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Failed to send the message to the user!")
|
|
387
|
+
except Exception as e:
|
|
388
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
389
|
+
# finally:
|
|
390
|
+
# raise StopPropagation
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
class BanSubscriber(Command):
|
|
394
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
395
|
+
super().__init__()
|
|
396
|
+
self.broadcastbot = bot
|
|
397
|
+
|
|
398
|
+
@triggered(CommandRegex.ban_subscriber)
|
|
399
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
400
|
+
try:
|
|
401
|
+
user_id = self.broadcastbot.message_handler.remove_command_from_message(
|
|
402
|
+
ctx.message.text, AdminCommandStrings.ban_subscriber
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
if not await self.broadcastbot.is_user_admin(ctx, AdminCommandStrings.ban_subscriber):
|
|
406
|
+
return
|
|
407
|
+
|
|
408
|
+
if user_id in self.broadcastbot.subscribers:
|
|
409
|
+
await self.broadcastbot.subscribers.remove(user_id)
|
|
410
|
+
|
|
411
|
+
user_phone_number = self.broadcastbot.subscribers.get_phone_number(user_id)
|
|
412
|
+
await self.broadcastbot.banned_users.add(user_id, user_phone_number)
|
|
413
|
+
|
|
414
|
+
await self.broadcastbot.send(user_id, "You have been banned")
|
|
415
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Successfully banned user")
|
|
416
|
+
|
|
417
|
+
self.broadcastbot.logger.info(f"Banned user {user_id}")
|
|
418
|
+
except Exception as e:
|
|
419
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
420
|
+
try:
|
|
421
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Failed to ban user")
|
|
422
|
+
except Exception as e:
|
|
423
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
424
|
+
# finally:
|
|
425
|
+
# raise StopPropagation
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
class LiftBanSubscriber(Command):
|
|
429
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
430
|
+
super().__init__()
|
|
431
|
+
self.broadcastbot = bot
|
|
432
|
+
|
|
433
|
+
@triggered(CommandRegex.lift_ban_subscriber)
|
|
434
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
435
|
+
try:
|
|
436
|
+
user_id = self.broadcastbot.message_handler.remove_command_from_message(
|
|
437
|
+
ctx.message.text, AdminCommandStrings.lift_ban_subscriber
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
if not await self.broadcastbot.is_user_admin(ctx, AdminCommandStrings.lift_ban_subscriber):
|
|
441
|
+
return
|
|
442
|
+
|
|
443
|
+
if user_id in self.broadcastbot.banned_users:
|
|
444
|
+
await self.broadcastbot.banned_users.remove(user_id)
|
|
445
|
+
else:
|
|
446
|
+
await self.broadcastbot.reply_with_warn_on_failure(
|
|
447
|
+
ctx, "Could not lift the ban because the user was not banned"
|
|
448
|
+
)
|
|
449
|
+
self.broadcastbot.logger.info(f"Could not lift the ban of {user_id} because the user was not banned")
|
|
450
|
+
return
|
|
451
|
+
|
|
452
|
+
await self.broadcastbot.send(user_id, "You have banned have been lifted, try subscribing again")
|
|
453
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Successfully lifted the ban on the user")
|
|
454
|
+
|
|
455
|
+
self.broadcastbot.logger.info(f"Lifted the ban on user {user_id}")
|
|
456
|
+
except Exception as e:
|
|
457
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
458
|
+
try:
|
|
459
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Failed lift the ban on the user")
|
|
460
|
+
except Exception as e:
|
|
461
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
462
|
+
# finally:
|
|
463
|
+
# raise StopPropagation
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class SetPing(Command):
|
|
467
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
468
|
+
super().__init__()
|
|
469
|
+
self.broadcastbot = bot
|
|
470
|
+
|
|
471
|
+
async def _send_ping(self, ctx: ChatContext) -> None:
|
|
472
|
+
try:
|
|
473
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Ping")
|
|
474
|
+
except Exception as e:
|
|
475
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
476
|
+
try:
|
|
477
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Failed to send ping")
|
|
478
|
+
except Exception as e:
|
|
479
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
480
|
+
|
|
481
|
+
@triggered(CommandRegex.set_ping)
|
|
482
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
483
|
+
try:
|
|
484
|
+
ping_time = self.broadcastbot.message_handler.remove_command_from_message(
|
|
485
|
+
ctx.message.text, AdminCommandStrings.set_ping
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
if not await self.broadcastbot.is_user_admin(ctx, AdminCommandStrings.set_ping):
|
|
489
|
+
return
|
|
490
|
+
|
|
491
|
+
if self.broadcastbot.ping_job is not None:
|
|
492
|
+
self.broadcastbot.scheduler.remove_job(self.broadcastbot.ping_job.id)
|
|
493
|
+
self.broadcastbot.logger.info("Unset old ping job")
|
|
494
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Unset old ping job")
|
|
495
|
+
|
|
496
|
+
self.broadcastbot.ping_job = self.broadcastbot.scheduler.add_job(
|
|
497
|
+
self._send_ping, "interval", seconds=int(ping_time), args=[ctx]
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, f"Ping set every {ping_time} seconds")
|
|
501
|
+
self.broadcastbot.logger.info(f"Ping set every {ping_time} seconds")
|
|
502
|
+
except Exception as e:
|
|
503
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
504
|
+
try:
|
|
505
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Failed set ping")
|
|
506
|
+
except Exception as e:
|
|
507
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
508
|
+
# finally:
|
|
509
|
+
# raise StopPropagation
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
class UnsetPing(Command):
|
|
513
|
+
def __init__(self, bot: BroadcasBot) -> None:
|
|
514
|
+
super().__init__()
|
|
515
|
+
self.broadcastbot = bot
|
|
516
|
+
|
|
517
|
+
@triggered(CommandRegex.unset_ping)
|
|
518
|
+
async def handle(self, ctx: ChatContext) -> None:
|
|
519
|
+
try:
|
|
520
|
+
if not await self.broadcastbot.is_user_admin(ctx, AdminCommandStrings.unset_ping):
|
|
521
|
+
return
|
|
522
|
+
|
|
523
|
+
if self.broadcastbot.ping_job is None:
|
|
524
|
+
await ctx.reply("Cannot unset because ping was not set!")
|
|
525
|
+
return
|
|
526
|
+
|
|
527
|
+
self.broadcastbot.scheduler.remove_job(self.broadcastbot.ping_job.id)
|
|
528
|
+
self.broadcastbot.ping_job = None
|
|
529
|
+
await ctx.reply("Ping unset!")
|
|
530
|
+
except Exception as e:
|
|
531
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
532
|
+
try:
|
|
533
|
+
await self.broadcastbot.reply_with_warn_on_failure(ctx, "Failed to unset ping")
|
|
534
|
+
except Exception as e:
|
|
535
|
+
self.broadcastbot.logger.error(e, exc_info=True)
|
|
536
|
+
# finally:
|
|
537
|
+
# raise StopPropagation
|