configurable bot token

This commit is contained in:
bakatrouble 2019-01-19 09:52:00 +03:00
parent 33ff1b800b
commit 999c6af8e7
20 changed files with 154 additions and 60 deletions

View File

@ -17,6 +17,27 @@
</li> </li>
</ul> </ul>
</nav> </nav>
{% if request.user.is_superuser %}
<hr class="separator" />
<div class="nav-subtitle">Admin</div>
<nav class="nav-main" role="navigation">
<ul class="nav nav-main">
<li class="nav-parent {% if sidebar_section %}nav-active{% endif %}">
<a href="#">
<i class="fas fa-cog" aria-hidden="true"></i>
<span>Configs</span>
</a>
<ul class="nav nav-children">
{% for slug, title in admin_configs.items %}
<li><a href="{% url 'cabinet:admin_config' slug=slug %}" class="nav-link">{{ title }}</a></li>
{% endfor %}
</ul>
</li>
</ul>
</nav>
{% endif %}
</div> </div>
<script> <script>

View File

@ -0,0 +1,23 @@
{% extends 'cabinet/_internal_base.html' %}
{% load bootstrap4 %}
{% block breadcrumbs %}
<li><span>Configs</span></li>
<li><span>{{ form.title }}</span></li>
{% endblock %}
{% block content %}
<form action="" method="post" class="card">
{% csrf_token %}
<header class="card-header">
<h2 class="card-title">Config</h2>
</header>
<div class="card-body">
{% bootstrap_form form layout='horizontal' %}
</div>
<footer class="card-footer text-right">
<button type="submit" class="btn btn-primary">Save</button>
</footer>
</form>
{% endblock %}

View File

@ -1,7 +1,7 @@
from django.contrib.auth.views import LogoutView from django.contrib.auth.views import LogoutView
from django.urls import path, include from django.urls import path, include
from cabinet.views import CabinetIndexView, LoginView from cabinet.views import CabinetIndexView, LoginView, AdminConfigView
app_name = 'cabinet' app_name = 'cabinet'
urlpatterns = [ urlpatterns = [
@ -9,4 +9,5 @@ urlpatterns = [
path('login/', LoginView.as_view(), name='login'), path('login/', LoginView.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'), path('logout/', LogoutView.as_view(), name='logout'),
path('feeds/', include('feeds.urls', namespace='feeds')), path('feeds/', include('feeds.urls', namespace='feeds')),
path('admin/config/<slug>/', AdminConfigView.as_view(), name='admin_config'),
] ]

View File

@ -1,3 +1,4 @@
import djconfig
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
@ -13,3 +14,9 @@ class CabinetViewMixin(LoginRequiredMixin):
ctx['title'] = self.get_title() ctx['title'] = self.get_title()
ctx['sidebar_section'] = self.sidebar_section ctx['sidebar_section'] = self.sidebar_section
return ctx return ctx
def cabinet_context_processor(ctx):
return {
'admin_configs': {form.slug: form.title for form in djconfig.config._registry},
}

View File

@ -1,5 +1,7 @@
import djconfig
from django.contrib.auth.views import LoginView as BaseLoginView from django.contrib.auth.views import LoginView as BaseLoginView
from django.views.generic import TemplateView from django.http import Http404
from django.views.generic import TemplateView, FormView
from cabinet.utils import CabinetViewMixin from cabinet.utils import CabinetViewMixin
@ -23,3 +25,16 @@ class LoginView(BaseLoginView):
if not self.request.POST.get('remember'): if not self.request.POST.get('remember'):
self.request.session.set_expiry(0) self.request.session.set_expiry(0)
return res return res
class AdminConfigView(CabinetViewMixin, FormView):
template_name = 'cabinet/admin_config.html'
def get_title(self):
return '{} config'.format(self.get_form_class().title)
def get_form_class(self):
for form in djconfig.config._registry:
if form.slug == self.kwargs.get('slug'):
return form
raise Http404()

View File

@ -2,15 +2,13 @@ import os
from celery import Celery from celery import Celery
config = {
'broker_url': 'redis://127.0.0.1:6379/1',
}
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
app = Celery('telegram_bots') app = Celery('telegram_bots')
app.config_from_object(config) app.config_from_object({
'broker_url': 'redis://127.0.0.1:6379/1',
})
app.autodiscover_tasks() app.autodiscover_tasks()

View File

@ -26,9 +26,10 @@ INSTALLED_APPS = [
'raven.contrib.django.raven_compat', 'raven.contrib.django.raven_compat',
'django_extensions', 'django_extensions',
'bootstrap4', 'bootstrap4',
'djconfig',
'cabinet', 'cabinet.apps.CabinetConfig',
'feeds', 'feeds.apps.FeedsConfig',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -39,6 +40,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'djconfig.middleware.DjConfigMiddleware',
] ]
ROOT_URLCONF = 'config.urls' ROOT_URLCONF = 'config.urls'
@ -54,7 +56,9 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'djconfig.context_processors.config',
'config.utils.turbolinks', 'config.utils.turbolinks',
'cabinet.utils.cabinet_context_processor',
], ],
}, },
}, },
@ -82,6 +86,19 @@ STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.AppDirectoriesFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
] ]
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
PUBLIC_ROOT = BASE_DIR.path('public') PUBLIC_ROOT = BASE_DIR.path('public')
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATIC_ROOT = str(PUBLIC_ROOT.path('static')) STATIC_ROOT = str(PUBLIC_ROOT.path('static'))

View File

@ -4,6 +4,6 @@ from django.views.generic import RedirectView
urlpatterns = [ urlpatterns = [
path('', RedirectView.as_view(pattern_name='cabinet:index')), path('', RedirectView.as_view(pattern_name='cabinet:index')),
path('admin/', admin.site.urls), path('config/', admin.site.urls),
path('cabinet/', include('cabinet.urls', namespace='cabinet')), path('cabinet/', include('cabinet.urls', namespace='cabinet')),
] ]

View File

@ -1,3 +1,3 @@
DJANGO_DEBUG = False DJANGO_DEBUG=False
DATABASE_URL = postgres://bots:bots@localhost/bots DATABASE_URL=postgres://bots:bots@localhost/bots
SENTRY_DSN = https:// SENTRY_DSN=https://

View File

@ -3,3 +3,12 @@ from django.apps import AppConfig
class FeedsConfig(AppConfig): class FeedsConfig(AppConfig):
name = 'feeds' name = 'feeds'
def ready(self):
self.register_config()
def register_config(self):
import djconfig
from .forms import FeedsAppConfigForm
djconfig.register(FeedsAppConfigForm)

View File

@ -1,4 +1,6 @@
from django import forms
from django.forms import ModelForm from django.forms import ModelForm
from djconfig.forms import ConfigForm
from feeds.models import Feed from feeds.models import Feed
@ -19,3 +21,12 @@ def get_config_form(mdl):
model = mdl model = mdl
exclude = () exclude = ()
return ConfigForm return ConfigForm
class FeedsAppConfigForm(ConfigForm):
slug = 'feeds'
title = 'Feeds'
feed_bot_token = forms.CharField(required=True)
vk_username = forms.CharField(required=True)
vk_password = forms.CharField(required=True)

View File

@ -1,15 +1,13 @@
# Generated by Django 2.1.5 on 2019-01-10 17:20 # Generated by Django 2.1.5 on 2019-01-19 05:35
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import picklefield.fields import yamlfield.fields
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True
dependencies = [ dependencies = [
('contenttypes', '0002_remove_content_type_name'), ('contenttypes', '0002_remove_content_type_name'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
@ -32,12 +30,13 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=32)), ('title', models.CharField(max_length=32)),
('chat_id', models.CharField(max_length=33)), ('chat_id', models.CharField(max_length=33)),
('check_interval', models.DurationField()), ('check_interval', models.DurationField(help_text='in seconds')),
('last_check', models.DateTimeField(blank=True, null=True)), ('last_check', models.DateTimeField(blank=True, null=True)),
('last_id', picklefield.fields.PickledObjectField(blank=True, editable=False, null=True)), ('last_id', yamlfield.fields.YAMLField(blank=True, null=True)),
('config_id', models.PositiveIntegerField()), ('config_id', models.PositiveIntegerField()),
('config_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), ('config_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('lock', models.BooleanField(default=False)),
], ],
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(

View File

@ -1,18 +0,0 @@
# Generated by Django 2.1.5 on 2019-01-10 18:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('feeds', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='feed',
name='lock',
field=models.BooleanField(default=False),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 2.1.5 on 2019-01-19 02:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('feeds', '0002_feed_lock'),
]
operations = [
migrations.AlterField(
model_name='feed',
name='check_interval',
field=models.DurationField(help_text='in seconds'),
),
]

View File

@ -3,8 +3,8 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from picklefield import PickledObjectField
from telebot import TeleBot from telebot import TeleBot
from yamlfield.fields import YAMLField
from feeds.tasks import execute_feed from feeds.tasks import execute_feed
@ -15,7 +15,7 @@ class Feed(models.Model):
chat_id = models.CharField(max_length=33) chat_id = models.CharField(max_length=33)
check_interval = models.DurationField(help_text='in seconds') check_interval = models.DurationField(help_text='in seconds')
last_check = models.DateTimeField(null=True, blank=True) last_check = models.DateTimeField(null=True, blank=True)
last_id = PickledObjectField(null=True, blank=True) last_id = YAMLField(null=True, blank=True)
lock = models.BooleanField(default=False) lock = models.BooleanField(default=False)
config_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) config_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)

View File

@ -1,5 +1,6 @@
from django.utils import timezone from django.utils import timezone
from telebot import TeleBot from telebot import TeleBot
from djconfig import config
from config.celery import app from config.celery import app
@ -15,7 +16,7 @@ def execute_feed(feed_pk):
feed.lock = True feed.lock = True
feed.save() feed.save()
bot = TeleBot('450146961:AAFcb9tyIiKAi6BHR1ZYfWuTEkYjhO3xEFE') bot = TeleBot(config.feed_bot_token)
feed.last_id = feed.config.execute(bot, feed.chat_id, feed.last_id) feed.last_id = feed.config.execute(bot, feed.chat_id, feed.last_id)
feed.last_check = timezone.now() feed.last_check = timezone.now()
feed.save() feed.save()

View File

@ -16,7 +16,18 @@
<h4>General options</h4> <h4>General options</h4>
{% bootstrap_form feed_form layout='horizontal' %} {% bootstrap_form feed_form layout='horizontal' %}
{% if feed %} {% if feed %}
Last check: {{ feed.last_check }} <div class="form-group row">
<label class="col-md-3 col-form-label" for="id_feed-last_check">Last check</label>
<div class="col-md-9">
<input type="text" value="{{ feed.last_check }}" class="form-control" placeholder="Last check" title="" id="id_feed-last_check" disabled>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 col-form-label" for="id_feed-last_id">Last id</label>
<div class="col-md-9">
<textarea class="form-control" placeholder="Last id" id="id_feed-last_id" disabled>{{ feed.last_id }}</textarea>
</div>
</div>
{% endif %} {% endif %}
<hr> <hr>
<h4>Module options</h4> <h4>Module options</h4>

View File

@ -5,14 +5,18 @@ certifi==2018.11.29
chardet==3.0.4 chardet==3.0.4
Django==2.1.5 Django==2.1.5
django-bootstrap4==0.0.7 django-bootstrap4==0.0.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-picklefield==2.0 django-redis==4.10.0
django-yamlfield==1.0.3
enum34==1.1.6
idna==2.8 idna==2.8
kombu==4.2.2.post1 kombu==4.2.2.post1
psycopg2-binary==2.7.6.1 psycopg2-binary==2.7.6.1
pyTelegramBotAPI==3.6.6 pyTelegramBotAPI==3.6.6
pytz==2018.9 pytz==2018.9
PyYAML==3.13
raven==6.10.0 raven==6.10.0
redis==3.0.1 redis==3.0.1
requests==2.21.0 requests==2.21.0
@ -20,4 +24,5 @@ six==1.12.0
urllib3==1.24.1 urllib3==1.24.1
uWSGI==2.0.17.1 uWSGI==2.0.17.1
vine==1.2.0 vine==1.2.0
vk-api==11.3.0
Werkzeug==0.14.1 Werkzeug==0.14.1

View File

@ -58,3 +58,9 @@ html.dark .userbox.show .dropdown-menu a:hover {
html.dark .turbolinks-progress-bar { html.dark .turbolinks-progress-bar {
background-color: #ccc; background-color: #ccc;
} }
html.dark .nav-subtitle {
color: #465162;
padding: 15px;
font-size: 12.8px;
font-size: 0.8rem;
}

View File

@ -61,3 +61,9 @@ html.dark
.turbolinks-progress-bar .turbolinks-progress-bar
background-color #ccc background-color #ccc
.nav-subtitle
color: #465162
padding 15px
font-size 12.8px
font-size 0.8rem