cyberlina bot

This commit is contained in:
bakatrouble 2019-11-27 21:21:24 +03:00
parent 61da2bd079
commit bddcc562ba
12 changed files with 322 additions and 1 deletions

View File

@ -0,0 +1,63 @@
# Generated by Django 3.0rc1 on 2019-11-25 21:58
from django.db import migrations, models
import django.db.models.deletion
import jsonfield.encoder
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('bots', '0008_auto_20191124_1922'),
]
operations = [
migrations.CreateModel(
name='CyberLinaBotModuleConfig',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('first_part', jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={})),
('second_part', jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={})),
('third_part', jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={})),
('emoji', jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={})),
('already_ran', jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={})),
('welcome_reactions', jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={})),
('inline_reactions', jsonfield.fields.JSONField(default=[], dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={})),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='CyberLinaChat',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField()),
('chat_id', models.BigIntegerField(db_index=True)),
('last_run', models.DateField(blank=True, null=True)),
('config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chats', to='bots.CyberLinaBotModuleConfig')),
],
),
migrations.CreateModel(
name='CyberLinaUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('user_id', models.BigIntegerField(db_index=True)),
('name', models.TextField()),
('chat', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='users', to='bots.CyberLinaChat')),
],
options={
'unique_together': {('chat', 'user_id')},
},
),
migrations.AddField(
model_name='cyberlinachat',
name='last_choice',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='bots.CyberLinaUser'),
),
migrations.AlterUniqueTogether(
name='cyberlinachat',
unique_together={('config', 'chat_id')},
),
]

View File

@ -0,0 +1,50 @@
# Generated by Django 3.0rc1 on 2019-11-25 22:12
from django.db import migrations
import jsonfield.encoder
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('bots', '0009_auto_20191126_0058'),
]
operations = [
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='already_ran',
field=jsonfield.fields.JSONField(default={'items': []}, dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='emoji',
field=jsonfield.fields.JSONField(default={'items': []}, dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='first_part',
field=jsonfield.fields.JSONField(default={'items': []}, dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='inline_reactions',
field=jsonfield.fields.JSONField(default={'items': []}, dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='second_part',
field=jsonfield.fields.JSONField(default={'items': []}, dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='third_part',
field=jsonfield.fields.JSONField(default={'items': []}, dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='welcome_reactions',
field=jsonfield.fields.JSONField(default={'items': []}, dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
]

View File

@ -0,0 +1,50 @@
# Generated by Django 3.0rc1 on 2019-11-27 18:17
from django.db import migrations
import jsonfield.encoder
import jsonfield.fields
class Migration(migrations.Migration):
dependencies = [
('bots', '0010_auto_20191126_0112'),
]
operations = [
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='already_ran',
field=jsonfield.fields.JSONField(default='{"items": []}', dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='emoji',
field=jsonfield.fields.JSONField(default='{"items": []}', dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='first_part',
field=jsonfield.fields.JSONField(default='{"items": []}', dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='inline_reactions',
field=jsonfield.fields.JSONField(default='{"items": []}', dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='second_part',
field=jsonfield.fields.JSONField(default='{"items": []}', dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='third_part',
field=jsonfield.fields.JSONField(default='{"items": []}', dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
migrations.AlterField(
model_name='cyberlinabotmoduleconfig',
name='welcome_reactions',
field=jsonfield.fields.JSONField(default='{"items": []}', dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}),
),
]

View File

@ -1,5 +1,6 @@
from .overlay import OverlayBotModuleConfig from .overlay import OverlayBotModuleConfig
from .channel_helper import ChannelHelperBotModuleConfig, QueuedItem from .channel_helper import ChannelHelperBotModuleConfig, QueuedItem
from .echo import EchoBotModuleConfig from .echo import EchoBotModuleConfig
from .cyberlina import CyberLinaBotModuleConfig
BOT_MODULES = [EchoBotModuleConfig, ChannelHelperBotModuleConfig, OverlayBotModuleConfig] BOT_MODULES = [EchoBotModuleConfig, ChannelHelperBotModuleConfig, OverlayBotModuleConfig, CyberLinaBotModuleConfig]

128
bots/modules/cyberlina.py Normal file
View File

@ -0,0 +1,128 @@
import os
from datetime import timedelta, datetime, time
from random import choice, seed
from uuid import uuid4
import humanize
from django.db import models
from django.utils.timezone import localdate, now, make_aware
from jsoneditor.forms import JSONEditor
from jsonfield import JSONField
from telegram import Update, Chat, User, InlineQueryResultArticle, InputTextMessageContent
from telegram.error import BadRequest
from telegram.ext import Dispatcher, CallbackContext, MessageHandler, Filters, CommandHandler, InlineQueryHandler
from telegram.utils.helpers import mention_html
from bots.models import TelegramBotModuleConfig
class CyberLinaBotModuleConfig(TelegramBotModuleConfig):
first_part = JSONField(default='{"items": []}')
second_part = JSONField(default='{"items": []}')
third_part = JSONField(default='{"items": []}')
emoji = JSONField(default='{"items": []}')
already_ran = JSONField(default='{"items": []}')
welcome_reactions = JSONField(default='{"items": []}')
inline_reactions = JSONField(default='{"items": []}')
MODULE_NAME = 'Киберлиночка'
CUSTOM_WIDGETS = {
'first_part': JSONEditor(),
'second_part': JSONEditor(),
'third_part': JSONEditor(),
'emoji': JSONEditor(),
'already_ran': JSONEditor(),
'welcome_reactions': JSONEditor(),
'inline_reactions': JSONEditor(),
}
def message_handler(self, update: Update, ctx: CallbackContext):
if not update.effective_chat or not update.effective_user:
return
CyberLinaUser.from_tg_obj(self, update.effective_chat, update.effective_user)
def goodmorning_handler(self, update: Update, ctx: CallbackContext):
if not all([self.first_part['items'], self.second_part['items'],
self.third_part['items'], self.emoji['items']]):
return update.effective_message.reply_text('Я не настроена :c')
seed(os.urandom(128))
self.message_handler(update, ctx)
chat = self.chats.get(chat_id=update.effective_chat.id)
if chat.last_run and (chat.last_run >= localdate() or
chat.last_run + timedelta(1) == localdate() and now().hour < 6):
humanize.i18n.activate('ru_RU')
time_left = make_aware(datetime.combine(chat.last_run + timedelta(1), time(6, 0))) - now()
return update.effective_message.reply_text(
choice(self.already_ran['items']).format(
name=chat.last_choice.name,
time=humanize.naturaldelta(time_left)
)
)
while True:
user = chat.users.order_by('?').first() # type: CyberLinaUser
if not user:
return update.effective_message.reply_text('Нет известных юзеров в чате')
try:
member = ctx.bot.get_chat_member(chat.chat_id, user.user_id)
CyberLinaUser.from_tg_obj(self, update.effective_chat, member.user)
break
except BadRequest:
user.delete()
msg = '{}, {}! {}, {} {}'.format(
choice(self.first_part['items']),
choice(self.second_part['items']),
mention_html(user.user_id, user.name),
choice(self.third_part['items']),
choice(self.emoji['items']),
)
update.effective_chat.send_message(msg, parse_mode='html')
chat.last_run = localdate()
chat.last_choice = user
chat.save()
def inline_query_handler(self, update: Update, ctx: CallbackContext):
if not self.inline_reactions:
return
seed(os.urandom(128))
results = [
InlineQueryResultArticle(
id=uuid4(),
title='Не нажимай >_<',
input_message_content=InputTextMessageContent(choice(self.inline_reactions['items']))
)
]
update.inline_query.answer(results)
def build_dispatcher(self, dispatcher: Dispatcher):
dispatcher.add_handler(CommandHandler('goodmorning', self.goodmorning_handler))
dispatcher.add_handler(MessageHandler(Filters.all, self.message_handler))
dispatcher.add_handler(InlineQueryHandler(self.inline_query_handler))
return dispatcher
class CyberLinaChat(models.Model):
config = models.ForeignKey(CyberLinaBotModuleConfig, on_delete=models.CASCADE, related_name='chats')
name = models.TextField()
chat_id = models.BigIntegerField(db_index=True)
last_run = models.DateField(null=True, blank=True)
last_choice = models.ForeignKey('CyberLinaUser', on_delete=models.SET_NULL, null=True, blank=True, related_name='+')
class Meta:
unique_together = 'config', 'chat_id',
class CyberLinaUser(models.Model):
chat = models.ForeignKey(CyberLinaChat, on_delete=models.CASCADE, related_name='users')
user_id = models.BigIntegerField(db_index=True)
name = models.TextField()
@staticmethod
def from_tg_obj(config: CyberLinaBotModuleConfig, chat: Chat, user: User):
chat_title = chat.title or user.full_name
chat, _ = CyberLinaChat.objects.update_or_create(config=config, chat_id=chat.id,
defaults={'name': chat_title})
CyberLinaUser.objects.update_or_create(chat=chat, user_id=user.id,
defaults={'name': user.full_name})
class Meta:
unique_together = 'chat', 'user_id',

View File

@ -53,3 +53,8 @@
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block extra_body %}
{{ bot_form.media }}
{{ config_form.media }}
{% endblock %}

View File

@ -15,6 +15,7 @@
<link rel="stylesheet" href="{% static 'vendor/pnotify/pnotify.custom.css' %}"> <link rel="stylesheet" href="{% static 'vendor/pnotify/pnotify.custom.css' %}">
<link rel="stylesheet" href="{% static 'css/theme.css' %}"> <link rel="stylesheet" href="{% static 'css/theme.css' %}">
<link rel="stylesheet" href="{% static 'css/skins/square-borders.css' %}">
<link rel="stylesheet" href="{% static 'css/custom.css' %}"> <link rel="stylesheet" href="{% static 'css/custom.css' %}">
<script src="{% static 'vendor/modernizr/modernizr.js' %}"></script> <script src="{% static 'vendor/modernizr/modernizr.js' %}"></script>
@ -74,5 +75,7 @@
}); });
{% endfor %} {% endfor %}
</script> </script>
{% block extra_body %}{% endblock %}
</body> </body>
</html> </html>

View File

@ -21,6 +21,7 @@ INSTALLED_APPS = [
'bootstrap4', 'bootstrap4',
'crispy_forms', 'crispy_forms',
'djconfig', 'djconfig',
'jsoneditor',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
@ -122,6 +123,9 @@ LOGOUT_REDIRECT_URL = LOGIN_URL
CRISPY_TEMPLATE_PACK = 'bootstrap4' CRISPY_TEMPLATE_PACK = 'bootstrap4'
JSON_EDITOR_JS = 'https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/7.0.4/jsoneditor.min.js'
JSON_EDITOR_CSS = 'https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/7.0.4/jsoneditor.min.css'
sentry_sdk.init( sentry_sdk.init(
dsn=env.str('SENTRY_DSN', None), dsn=env.str('SENTRY_DSN', None),
integrations=[DjangoIntegration()], integrations=[DjangoIntegration()],

View File

@ -64,6 +64,7 @@ def get_config_form(mdl):
class Meta: class Meta:
model = mdl model = mdl
exclude = () exclude = ()
widgets = mdl.CUSTOM_WIDGETS if hasattr(mdl, 'CUSTOM_WIDGETS') else {}
return ConfigForm return ConfigForm

View File

@ -23,6 +23,7 @@ django-djconfig==0.9.0
django-environ==0.4.5 django-environ==0.4.5
django-extensions==2.1.4 django-extensions==2.1.4
django-jet==1.0.8 django-jet==1.0.8
django-jsoneditor==0.1.4
django-redis-cache==2.1.0 django-redis-cache==2.1.0
django-timezone-field==3.0 django-timezone-field==3.0
django-yamlfield==1.0.3 django-yamlfield==1.0.3
@ -32,13 +33,19 @@ future==0.17.1
h2==3.1.1 h2==3.1.1
hiredis==1.0.1 hiredis==1.0.1
hpack==3.0.0 hpack==3.0.0
humanize==0.5.1
hyperframe==5.2.0 hyperframe==5.2.0
hyperlink==19.0.0 hyperlink==19.0.0
idna==2.8 idna==2.8
importlib-metadata==0.23
incremental==17.5.0 incremental==17.5.0
json-rpc==1.12.1 json-rpc==1.12.1
jsonfield2==3.0.3
jsonschema==3.2.0
kombu==4.2.2.post1 kombu==4.2.2.post1
more-itertools==7.2.0
oauthlib==3.0.1 oauthlib==3.0.1
packaging==19.2
Pillow==5.4.1 Pillow==5.4.1
priority==1.3.0 priority==1.3.0
psycopg2-binary==2.7.6.1 psycopg2-binary==2.7.6.1
@ -48,7 +55,9 @@ pyasn1-modules==0.2.7
pycparser==2.19 pycparser==2.19
PyHamcrest==1.9.0 PyHamcrest==1.9.0
pyOpenSSL==19.1.0 pyOpenSSL==19.1.0
pyparsing==2.4.5
Pyrogram==0.11.0 Pyrogram==0.11.0
pyrsistent==0.15.6
PySocks==1.6.8 PySocks==1.6.8
pyTelegramBotAPI==3.6.6 pyTelegramBotAPI==3.6.6
python-anticaptcha==0.3.1 python-anticaptcha==0.3.1
@ -74,4 +83,5 @@ urllib3==1.24.1
vine==1.2.0 vine==1.2.0
vk-api==11.6.1 vk-api==11.6.1
Werkzeug==0.14.1 Werkzeug==0.14.1
zipp==0.6.0
zope.interface==4.7.1 zope.interface==4.7.1

View File

@ -64,3 +64,6 @@ html.dark .nav-subtitle {
font-size: 12.8px; font-size: 12.8px;
font-size: 0.8rem; font-size: 0.8rem;
} }
html.dark .jsoneditor {
background: #fff;
}

View File

@ -67,3 +67,6 @@ html.dark
padding 15px padding 15px
font-size 12.8px font-size 12.8px
font-size 0.8rem font-size 0.8rem
.jsoneditor
background: #fff