cyberlina bot
This commit is contained in:
parent
61da2bd079
commit
bddcc562ba
63
bots/migrations/0009_auto_20191126_0058.py
Normal file
63
bots/migrations/0009_auto_20191126_0058.py
Normal 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')},
|
||||||
|
),
|
||||||
|
]
|
50
bots/migrations/0010_auto_20191126_0112.py
Normal file
50
bots/migrations/0010_auto_20191126_0112.py
Normal 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={}),
|
||||||
|
),
|
||||||
|
]
|
50
bots/migrations/0011_auto_20191127_2117.py
Normal file
50
bots/migrations/0011_auto_20191127_2117.py
Normal 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={}),
|
||||||
|
),
|
||||||
|
]
|
@ -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
128
bots/modules/cyberlina.py
Normal 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',
|
@ -53,3 +53,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_body %}
|
||||||
|
{{ bot_form.media }}
|
||||||
|
{{ config_form.media }}
|
||||||
|
{% endblock %}
|
||||||
|
@ -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>
|
||||||
|
@ -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()],
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user