diff --git a/Pipfile b/Pipfile index f4e1dce..9e49fa0 100644 --- a/Pipfile +++ b/Pipfile @@ -37,6 +37,7 @@ hiredis = "*" twisted = {extras = ["http2", "tls"], version = "*"} whitenoise = "*" django-picklefield = "*" +boto3 = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 82c30fd..ed8ced7 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "97d73a69d57a13005810833cb3d8c3d066ab7a1c934731069061a622f0e3880a" + "sha256": "edd3a9ebec36929c8ff036bf21938fb3ac5d955cc5cbed716f1fa9c34eca854e" }, "pipfile-spec": 6, "requires": { @@ -83,6 +83,22 @@ ], "version": "==3.6.3.0" }, + "boto3": { + "hashes": [ + "sha256:6758751f1181b9363e4e7559dcbd5ac0fc7147b73f429c976ec5ecd1688c9ec7", + "sha256:fa41987f9f71368013767306d9522b627946a01b4843938a26fb19cc8adb06c0" + ], + "index": "pypi", + "version": "==1.17.27" + }, + "botocore": { + "hashes": [ + "sha256:4477803f07649f4d80b17d054820e7a09bb2cb0792d0decc2812108bc3759c4a", + "sha256:57e45c9d443163da7312cae61bcc60382e6d0b3aecda68e850d6438162fe7b5b" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.20.27" + }, "celery": { "hashes": [ "sha256:5e8d364e058554e83bbb116e8377d90c79be254785f357cb2cec026e79febe13", @@ -426,6 +442,14 @@ ], "version": "==21.3.0" }, + "jmespath": { + "hashes": [ + "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9", + "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.10.0" + }, "json-rpc": { "hashes": [ "sha256:84b45058e5ba95f49c7b6afcf7e03ab86bee89bf2c01f3ad8dd41fe114fc1f84", @@ -665,13 +689,21 @@ "index": "pypi", "version": "==0.7.1" }, + "python-dateutil": { + "hashes": [ + "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", + "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.8.1" + }, "python-telegram-bot": { "hashes": [ - "sha256:770d6c19f75e530de7f6a8784ec06945da84bcd2344a72932b8c2a05a78cd421", - "sha256:8b5790cdbd5794da5ee06eb8d0a00a81e3f48b0e04b4d0e33874d45a2495c221" + "sha256:467b0f149bf4d0b9b638530c9a887dd0d6e64da1d5603cfe6eee839671ca1496", + "sha256:4c1fdc3dab192bf1f754ccd0692511976b38e2c6ad75010e30844a19c0193c90" ], "index": "pypi", - "version": "==13.3" + "version": "==13.4.1" }, "python-twitter": { "hashes": [ @@ -747,6 +779,13 @@ ], "version": "==1.3.0" }, + "s3transfer": { + "hashes": [ + "sha256:1e28620e5b444652ed752cf87c7e0cb15b0e578972568c6609f0f18212f259ed", + "sha256:7fdddb4f22275cf1d32129e21f056337fd2a80b6ccef1664528145b72c49e6d2" + ], + "version": "==0.3.4" + }, "sentry-sdk": { "hashes": [ "sha256:71de00c9711926816f750bc0f57ef2abbcb1bfbdf5378c601df7ec978f44857a", @@ -914,11 +953,11 @@ }, "urllib3": { "hashes": [ - "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", - "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" + "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df", + "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0'", - "version": "==1.26.3" + "version": "==1.26.4" }, "vine": { "hashes": [ diff --git a/bots/admin.py b/bots/admin.py index 3626034..70f7dd0 100644 --- a/bots/admin.py +++ b/bots/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from .models import TelegramBot +from .models import TelegramBot, BotUser from .modules import EchoBotModuleConfig, ChannelHelperBotModuleConfig, OverlayBotModuleConfig, QueuedItem,\ - CyberLinaBotModuleConfig, ChannelHelperUser + CyberLinaBotModuleConfig @admin.register(TelegramBot) @@ -13,5 +13,5 @@ admin.site.register(EchoBotModuleConfig) admin.site.register(OverlayBotModuleConfig) admin.site.register(ChannelHelperBotModuleConfig) admin.site.register(QueuedItem) -admin.site.register(ChannelHelperUser) +admin.site.register(BotUser) admin.site.register(CyberLinaBotModuleConfig) diff --git a/bots/forms.py b/bots/forms.py index f3c4101..2a42efd 100644 --- a/bots/forms.py +++ b/bots/forms.py @@ -28,6 +28,9 @@ class BotsAppConfigForm(ConfigForm): title = 'Bots' tmp_uploads_chat_id = forms.CharField(required=True) + aws_access_key_id = forms.CharField(required=True) + aws_secret_access_key = forms.CharField(required=True) + s3_bucket = forms.CharField(required=True) helper = FormHelper() helper.form_class = 'form-horizontal' @@ -36,4 +39,5 @@ class BotsAppConfigForm(ConfigForm): helper.form_tag = False helper.layout = Layout( Fieldset('Global', 'tmp_uploads_chat_id'), + Fieldset('Amazon S3', 'aws_access_key_id', 'aws_secret_access_key', 's3_bucket'), ) diff --git a/bots/migrations/0002_auto_20210315_2115.py b/bots/migrations/0002_auto_20210315_2115.py new file mode 100644 index 0000000..3140fc2 --- /dev/null +++ b/bots/migrations/0002_auto_20210315_2115.py @@ -0,0 +1,17 @@ +# Generated by Django 3.1.7 on 2021-03-15 18:15 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bots', '0001_squashed_0025_auto_20210311_2341'), + ] + + operations = [ + migrations.RenameModel( + old_name='ChannelHelperUser', + new_name='BotUser', + ), + ] diff --git a/bots/migrations/0003_robotbotmoduleconfig.py b/bots/migrations/0003_robotbotmoduleconfig.py new file mode 100644 index 0000000..98613fd --- /dev/null +++ b/bots/migrations/0003_robotbotmoduleconfig.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.7 on 2021-03-15 18:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bots', '0002_auto_20210315_2115'), + ] + + operations = [ + migrations.CreateModel( + name='RobotBotModuleConfig', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('users', models.ManyToManyField(to='bots.BotUser')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/bots/models.py b/bots/models.py index ef10db0..d45c3ed 100644 --- a/bots/models.py +++ b/bots/models.py @@ -65,3 +65,11 @@ class TelegramBotModuleConfig(models.Model): class Meta: abstract = True + + +class BotUser(models.Model): + name = models.CharField(max_length=32) + user_id = models.BigIntegerField(db_index=True) + + def __str__(self): + return self.name diff --git a/bots/modules/__init__.py b/bots/modules/__init__.py index 95f2bb4..983e999 100644 --- a/bots/modules/__init__.py +++ b/bots/modules/__init__.py @@ -1,9 +1,10 @@ from .overlay import OverlayBotModuleConfig -from .channel_helper import ChannelHelperBotModuleConfig, QueuedItem, ChannelHelperUser +from .channel_helper import ChannelHelperBotModuleConfig, QueuedItem from .echo import EchoBotModuleConfig from .cyberlina import CyberLinaBotModuleConfig from .ping import PingBotModuleConfig +from .robot import RobotBotModuleConfig from .spoiler import SpoilerBotModuleConfig BOT_MODULES = [EchoBotModuleConfig, ChannelHelperBotModuleConfig, OverlayBotModuleConfig, CyberLinaBotModuleConfig, - PingBotModuleConfig, SpoilerBotModuleConfig] + PingBotModuleConfig, SpoilerBotModuleConfig, RobotBotModuleConfig] diff --git a/bots/modules/channel_helper.py b/bots/modules/channel_helper.py index c1f8168..17d0170 100644 --- a/bots/modules/channel_helper.py +++ b/bots/modules/channel_helper.py @@ -13,21 +13,13 @@ from telegram.ext import Dispatcher, CallbackContext, MessageHandler, Filters from jsonrpc import Dispatcher as RPCDispatcher from djconfig import config -from bots.models import TelegramBotModuleConfig - - -class ChannelHelperUser(models.Model): - name = models.CharField(max_length=32) - user_id = models.BigIntegerField(db_index=True) - - def __str__(self): - return self.name +from bots.models import TelegramBotModuleConfig, BotUser class ChannelHelperBotModuleConfig(TelegramBotModuleConfig): chat_id = models.CharField(max_length=32) queued = models.BooleanField(default=False) - users = models.ManyToManyField(ChannelHelperUser) + users = models.ManyToManyField(BotUser) MODULE_NAME = 'Channel helper' diff --git a/bots/modules/robot.py b/bots/modules/robot.py new file mode 100644 index 0000000..1263c2f --- /dev/null +++ b/bots/modules/robot.py @@ -0,0 +1,55 @@ +import os +from tempfile import TemporaryDirectory + +import boto3 +from django.db import models +from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton +from telegram.ext import CallbackContext, Dispatcher, MessageHandler, Filters +from djconfig import config + +from bots.models import TelegramBotModuleConfig, BotUser + + +class RobotBotModuleConfig(TelegramBotModuleConfig): + users = models.ManyToManyField(BotUser) + + MODULE_NAME = 'RoBOT' + + def build_dispatcher(self, dispatcher: Dispatcher): + dispatcher.add_handler(MessageHandler(Filters.audio | Filters.photo | Filters.video | Filters.document, + self.save_file)) + return dispatcher + + def save_file(self, update: Update, ctx: CallbackContext): + if self.users.count() and not self.users.filter(user_id=update.effective_user.id).count(): + update.effective_message.reply_text('GTFO') + return + + markup = InlineKeyboardMarkup([]) + + if update.message.photo: + file_id = update.message.photo[-1].file_id + elif update.message.audio: + file_id = update.message.audio.file_id + elif update.message.video: + file_id = update.message.video.file_id + elif update.message.document: + file_id = update.message.document.file_id + else: + return + + file = ctx.bot.get_file(file_id) + filename = os.path.basename(file.file_path) + with TemporaryDirectory() as d: + file_path = os.path.join(d, filename) + file.download(file_path) + s3 = boto3.client('s3', aws_access_key_id=config.aws_access_key_id, aws_secret_access_key=config.aws_secret_access_key) + s3.upload_file(file_path, config.s3_bucket, filename) + file_url = f'https://{config.s3_bucket}.s3.amazonaws.com/{filename}' + if update.message.photo: + markup.inline_keyboard = [[ + InlineKeyboardButton('Google IS', f'https://www.google.com/searchbyimage?image_url={file_url}'), + InlineKeyboardButton('Yandex IS', f'https://yandex.ru/images/search?rpt=imageview&url={file_url}'), + InlineKeyboardButton('SauceNao', f'https://saucenao.com/search.php?url={file_url}') + ]] + update.message.reply_text(file_url, disable_web_page_preview=True, reply_markup=markup)