commands.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. from sys import executable
  2. from struct import pack
  3. from asyncio import create_subprocess_shell
  4. from asyncio.subprocess import PIPE
  5. from datetime import datetime
  6. from ujson import dumps
  7. from tortoise.exceptions import IntegrityError
  8. from telethon.utils import get_display_name, get_peer_id
  9. from aiofiles.os import remove
  10. from emoji import is_emoji
  11. from actions import (
  12. find_action,
  13. create_action,
  14. delete_action,
  15. add_gif,
  16. add_sticker,
  17. add_admin,
  18. delete_admin,
  19. add_or_update_birthday,
  20. get_birthdays
  21. )
  22. from utils import (
  23. WORDS_TABLE,
  24. make_temporary_filename,
  25. parse_kind,
  26. get_user_name,
  27. get_word_for,
  28. calculate_age,
  29. unparse
  30. )
  31. class Handler:
  32. def __init__(self, handler, is_restricted=False):
  33. self.handler = handler
  34. self.is_restricted = is_restricted
  35. async def newadmin_handler(bot, event, command):
  36. if command.argc < 1:
  37. await event.reply('Пожалуйста, укажите пользователя!')
  38. return
  39. try:
  40. target = await bot.get_entity(command.args[0])
  41. except ValueError:
  42. await event.reply('Недопустимое имя пользователя!')
  43. return
  44. try:
  45. await add_admin(target)
  46. except IntegrityError:
  47. await event.reply('Данный пользователь уже является администратором!')
  48. return
  49. await event.reply('Готово!~~')
  50. async def deladmin_handler(bot, event, command):
  51. if command.argc < 1:
  52. await event.reply('Пожалуйста, укажите пользователя!')
  53. return
  54. try:
  55. target = await bot.get_entity(command.args[0])
  56. except ValueError:
  57. await event.reply('Недопустимое имя пользователя!')
  58. return
  59. try:
  60. await delete_admin(target)
  61. except IndexError:
  62. await event.reply('Данный пользователь не является администратором!')
  63. return
  64. await event.reply('Готово!~~')
  65. async def newaction_handler(bot, event, command):
  66. if command.argc < 3:
  67. await event.reply('Пожалуйста, укажите тип, имя и шаблон действия!')
  68. return
  69. try:
  70. kind = parse_kind(command.args[0])
  71. except ValueError:
  72. await event.reply('Неверный тип действия!!!')
  73. return
  74. try:
  75. await create_action(command.args[1], ' '.join(command.args[2:]), kind)
  76. except SyntaxError:
  77. await event.reply('Недопустимое имя действия!!!')
  78. return
  79. except IntegrityError:
  80. await event.reply('Действие с таким названием уже существует!')
  81. return
  82. await event.reply('Действие создано!')
  83. async def delaction_handler(bot, event, command):
  84. if command.argc < 1:
  85. await event.reply('Пожалуйста, укажите имя действия!')
  86. return
  87. try:
  88. await delete_action(command.args[0])
  89. except SyntaxError:
  90. await event.reply('Недопустимое имя действия!!!')
  91. return
  92. except NameError:
  93. await event.reply('Действия с таким названием не существует!')
  94. return
  95. await event.reply('Действие удалено!')
  96. async def addgif_handler(bot, event, command):
  97. if command.argc < 1:
  98. await event.reply('Пожалуйста, укажите имя действия!')
  99. return
  100. gif = await event.get_reply_message()
  101. if not gif or not gif.gif:
  102. await event.reply('Пожалуйста, добавьте GIF!')
  103. return
  104. try:
  105. action = await find_action(command.args[0])
  106. await add_gif(action, gif.file.id)
  107. except SyntaxError:
  108. await event.reply('Недопустимое имя действия!!!')
  109. return
  110. except NameError:
  111. await event.reply('Нет такого действия!')
  112. return
  113. await event.reply('Готово!~~')
  114. # Very, very, VERY evil code...
  115. async def make_message_shot(bot, message):
  116. proc = await create_subprocess_shell(
  117. './makeshot/makeshot',
  118. stdin=PIPE
  119. )
  120. output_path = make_temporary_filename('png')
  121. avatar_path = make_temporary_filename('png')
  122. if message.sender is None:
  123. await bot.download_profile_photo(message.peer_id.channel_id, file=avatar_path)
  124. full_name = await bot.get_entity(message.peer_id.channel_id)
  125. full_name = full_name.title
  126. else:
  127. await bot.download_profile_photo(message.sender, file=avatar_path)
  128. full_name = get_display_name(message.sender)
  129. # TO-DO: make it better.
  130. mproc = await create_subprocess_shell(
  131. f'mogrify -format png {avatar_path}'
  132. )
  133. await mproc.communicate()
  134. data = bytes()
  135. data += pack('I', len(output_path))
  136. data += bytes(output_path, encoding='ASCII')
  137. data += pack('I', len(avatar_path))
  138. data += bytes(avatar_path, encoding='ASCII')
  139. username = bytes(full_name if full_name else message.sender.username, encoding='UTF-8')
  140. data += pack('I', len(username))
  141. data += username
  142. data += pack('I', (message.sender.id if message.sender else message.peer_id.channel_id) % 7)
  143. text = bytes(unparse(message.raw_text, [entity for entity, _ in message.get_entities_text()]), encoding='UTF-8')
  144. data += pack('I', len(text))
  145. data += text
  146. await proc.communicate(input=data)
  147. await remove(avatar_path)
  148. return output_path
  149. async def save_handler(bot, event, command):
  150. message = await event.get_reply_message()
  151. if not message:
  152. await event.reply('Пожалуйста, укажите сообщение для сохранения!')
  153. return
  154. emoji = '⚡'
  155. if command.argc >= 1:
  156. emoji = command.args[0]
  157. if len(emoji) not in range(1, 6)\
  158. or not all(map(is_emoji, emoji)):
  159. await event.reply('Указан некорректный эмодзи!!!')
  160. return
  161. path = await make_message_shot(bot, message)
  162. try:
  163. file = await add_sticker(bot, path, emoji)
  164. await bot.send_file(
  165. message.peer_id,
  166. file=file,
  167. reply_to=message
  168. )
  169. finally:
  170. await remove(path)
  171. async def bday_handler(bot, event, command):
  172. if command.argc >= 1:
  173. try:
  174. date = datetime.strptime(' '.join(command.args), '%d.%m.%Y')
  175. except ValueError:
  176. await event.reply('Дата не может быть распознана. Пожалуйста, введите свой день рождения в следующем формате: 01.01.1970 (день, месяц, год).')
  177. return
  178. if date >= datetime.now():
  179. await event.reply('День рождения не может быть в будущем...')
  180. return
  181. if await add_or_update_birthday(get_peer_id(event.peer_id), event.sender, date):
  182. await event.reply('День рождения успешно добавлен!!!')
  183. else:
  184. await event.reply('День рождения успешно обновлён!!!')
  185. return
  186. birthdays = await get_birthdays(get_peer_id(event.peer_id))
  187. if not birthdays:
  188. await event.reply('Пока пусто...')
  189. return
  190. birthdays = map(lambda birthday: (birthday.user_id, calculate_age(birthday.date)), birthdays)
  191. birthdays = sorted(birthdays, key=lambda birthday: birthday[1].days_until)
  192. birthdays_list = ''
  193. for user_id, age in birthdays:
  194. birthdays_list += get_user_name(await bot.get_entity(user_id))
  195. birthdays_list += ' — '
  196. birthdays_list += age.date_string
  197. birthdays_list += f' (через {get_word_for("день", age.days_until)} исполнится {get_word_for("год", age.age)}; сейчас {get_word_for("год", age.age_now)})\n'
  198. await event.reply(f'Дни рождения:\n\n{birthdays_list}')
  199. COMMANDS = {
  200. 'newadmin': Handler(newadmin_handler, is_restricted=True),
  201. 'deladmin': Handler(deladmin_handler, is_restricted=True),
  202. 'newaction': Handler(newaction_handler, is_restricted=True),
  203. 'delaction': Handler(delaction_handler, is_restricted=True),
  204. 'addgif': Handler(addgif_handler, is_restricted=True),
  205. 'save': Handler(save_handler),
  206. 'bday': Handler(bday_handler)
  207. }