vk feed module
This commit is contained in:
		@@ -1,7 +1,8 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import environ
 | 
					import environ
 | 
				
			||||||
import raven
 | 
					import sentry_sdk
 | 
				
			||||||
 | 
					from sentry_sdk.integrations.django import DjangoIntegration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BASE_DIR = environ.Path(__file__) - 2
 | 
					BASE_DIR = environ.Path(__file__) - 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,7 +24,6 @@ INSTALLED_APPS = [
 | 
				
			|||||||
    'django.contrib.messages',
 | 
					    'django.contrib.messages',
 | 
				
			||||||
    'django.contrib.staticfiles',
 | 
					    'django.contrib.staticfiles',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'raven.contrib.django.raven_compat',
 | 
					 | 
				
			||||||
    'django_extensions',
 | 
					    'django_extensions',
 | 
				
			||||||
    'bootstrap4',
 | 
					    'bootstrap4',
 | 
				
			||||||
    'djconfig',
 | 
					    'djconfig',
 | 
				
			||||||
@@ -109,7 +109,7 @@ LOGIN_URL = 'cabinet:login'
 | 
				
			|||||||
LOGIN_REDIRECT_URL = 'cabinet:index'
 | 
					LOGIN_REDIRECT_URL = 'cabinet:index'
 | 
				
			||||||
LOGOUT_REDIRECT_URL = LOGIN_URL
 | 
					LOGOUT_REDIRECT_URL = LOGIN_URL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RAVEN_CONFIG = {
 | 
					sentry_sdk.init(
 | 
				
			||||||
    'dsn': env.str('SENTRY_DSN', None),
 | 
					    dsn=env.str('SENTRY_DSN', None),
 | 
				
			||||||
    'release': raven.fetch_git_sha(str(BASE_DIR)),
 | 
					    integrations=[DjangoIntegration()],
 | 
				
			||||||
}
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,3 +30,4 @@ class FeedsAppConfigForm(ConfigForm):
 | 
				
			|||||||
    feed_bot_token = forms.CharField(required=True)
 | 
					    feed_bot_token = forms.CharField(required=True)
 | 
				
			||||||
    vk_username = forms.CharField(required=True)
 | 
					    vk_username = forms.CharField(required=True)
 | 
				
			||||||
    vk_password = forms.CharField(required=True)
 | 
					    vk_password = forms.CharField(required=True)
 | 
				
			||||||
 | 
					    vk_auth = forms.CharField(required=False, widget=forms.Textarea())
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								feeds/migrations/0002_vkfeedmoduleconfig.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								feeds/migrations/0002_vkfeedmoduleconfig.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					# Generated by Django 2.1.5 on 2019-01-25 16:06
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('feeds', '0001_initial'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='VKFeedModuleConfig',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('owner_id', models.IntegerField()),
 | 
				
			||||||
 | 
					                ('send_text', models.BooleanField(default=True)),
 | 
				
			||||||
 | 
					                ('send_links', models.BooleanField(default=True)),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            options={
 | 
				
			||||||
 | 
					                'abstract': False,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -28,8 +28,8 @@ class Feed(models.Model):
 | 
				
			|||||||
        if self.last_check and timezone.now() < self.last_check + self.check_interval:
 | 
					        if self.last_check and timezone.now() < self.last_check + self.check_interval:
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.lock = True
 | 
					        # self.lock = True
 | 
				
			||||||
        self.save()
 | 
					        # self.save()
 | 
				
			||||||
        execute_feed.delay(self.pk)
 | 
					        execute_feed.delay(self.pk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
from .echo import EchoFeedModuleConfig
 | 
					from .echo import EchoFeedModuleConfig
 | 
				
			||||||
 | 
					from .vk_feed import VKFeedModuleConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FEED_MODULES = [EchoFeedModuleConfig]
 | 
					FEED_MODULES = [EchoFeedModuleConfig, VKFeedModuleConfig]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										77
									
								
								feeds/modules/vk_feed.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								feeds/modules/vk_feed.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					import tempfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					import sentry_sdk
 | 
				
			||||||
 | 
					from django.db import models
 | 
				
			||||||
 | 
					from djconfig import config
 | 
				
			||||||
 | 
					from telebot import TeleBot
 | 
				
			||||||
 | 
					from telebot.types import InputMediaPhoto
 | 
				
			||||||
 | 
					from vk_api import VkApi
 | 
				
			||||||
 | 
					from vk_api.audio import VkAudio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from feeds.models import FeedModuleConfig
 | 
				
			||||||
 | 
					from feeds.utils import DatabaseConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_vk_photo(attachment):
 | 
				
			||||||
 | 
					    for size in (2560, 1280, 807, 604, 130, 75):
 | 
				
			||||||
 | 
					        if f'photo_{size}' in attachment:
 | 
				
			||||||
 | 
					            return attachment[f'photo_{size}']
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_file(url):
 | 
				
			||||||
 | 
					    fname = '?'.join(url.split('?')[:-1])
 | 
				
			||||||
 | 
					    extension = os.path.basename(fname).split('.')[-1]
 | 
				
			||||||
 | 
					    f = tempfile.NamedTemporaryFile(suffix=f'.{extension}' if extension else None)
 | 
				
			||||||
 | 
					    r = requests.get(url, stream=True)
 | 
				
			||||||
 | 
					    for chunk in r.iter_content(1024 * 1024):
 | 
				
			||||||
 | 
					        if chunk:
 | 
				
			||||||
 | 
					            f.write(chunk)
 | 
				
			||||||
 | 
					    f.seek(0)
 | 
				
			||||||
 | 
					    return f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VKFeedModuleConfig(FeedModuleConfig):
 | 
				
			||||||
 | 
					    owner_id = models.IntegerField()
 | 
				
			||||||
 | 
					    send_text = models.BooleanField(default=True)
 | 
				
			||||||
 | 
					    send_links = models.BooleanField(default=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MODULE_NAME = 'VK feed'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self, bot: TeleBot, chat_id, last_id):
 | 
				
			||||||
 | 
					        config._reload_maybe()
 | 
				
			||||||
 | 
					        vk_session = VkApi(login=config.vk_username, password=config.vk_password, config=DatabaseConfig,
 | 
				
			||||||
 | 
					                           api_version='5.60')
 | 
				
			||||||
 | 
					        vk_session.auth()
 | 
				
			||||||
 | 
					        vk_audio = VkAudio(vk_session)
 | 
				
			||||||
 | 
					        vk = vk_session.get_api()
 | 
				
			||||||
 | 
					        wall_data = vk.wall.get(owner_id=self.owner_id)
 | 
				
			||||||
 | 
					        for post in reversed(wall_data['items']):
 | 
				
			||||||
 | 
					            if post['id'] > last_id:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    if self.send_text and post['text']:
 | 
				
			||||||
 | 
					                        bot.send_message(chat_id, post['text'])
 | 
				
			||||||
 | 
					                    if 'attachments' in post:
 | 
				
			||||||
 | 
					                        photos = []
 | 
				
			||||||
 | 
					                        for image in filter(lambda a: 'photo' in a, post['attachments']):
 | 
				
			||||||
 | 
					                            url = get_vk_photo(image['photo'])
 | 
				
			||||||
 | 
					                            if url:
 | 
				
			||||||
 | 
					                                photos.append(url.replace('\\', ''))
 | 
				
			||||||
 | 
					                        if len(photos) == 1:
 | 
				
			||||||
 | 
					                            bot.send_photo(chat_id, photos[0])
 | 
				
			||||||
 | 
					                        elif len(photos) > 1:
 | 
				
			||||||
 | 
					                            bot.send_media_group(chat_id, [InputMediaPhoto(photo) for photo in photos])
 | 
				
			||||||
 | 
					                        for a in post['attachments']:
 | 
				
			||||||
 | 
					                            if 'audio' in a:
 | 
				
			||||||
 | 
					                                f = get_file(vk_audio.get_audio_by_id(a['audio']['owner_id'], a['audio']['id']))
 | 
				
			||||||
 | 
					                                bot.send_audio(chat_id, f, a['audio'].get('duration'),
 | 
				
			||||||
 | 
					                                               a['audio'].get('artist'), a['audio'].get('title'))
 | 
				
			||||||
 | 
					                    if self.send_links:
 | 
				
			||||||
 | 
					                        bot.send_message(chat_id, f"https://vk.com/wall{post['owner_id']}_{post['id']}",
 | 
				
			||||||
 | 
					                                         disable_web_page_preview=True)
 | 
				
			||||||
 | 
					                except Exception as e:
 | 
				
			||||||
 | 
					                    sentry_sdk.capture_exception(e)
 | 
				
			||||||
 | 
					                last_id = post['id']
 | 
				
			||||||
 | 
					        return last_id
 | 
				
			||||||
@@ -1,3 +1,6 @@
 | 
				
			|||||||
 | 
					from pprint import pprint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
from django.utils import timezone
 | 
					from django.utils import timezone
 | 
				
			||||||
from telebot import TeleBot
 | 
					from telebot import TeleBot
 | 
				
			||||||
from djconfig import config
 | 
					from djconfig import config
 | 
				
			||||||
@@ -7,8 +10,13 @@ from config.celery import app
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@app.task()
 | 
					@app.task()
 | 
				
			||||||
def execute_feed(feed_pk):
 | 
					def execute_feed(feed_pk):
 | 
				
			||||||
    config._reload_maybe()
 | 
					 | 
				
			||||||
    from feeds.models import Feed
 | 
					    from feeds.models import Feed
 | 
				
			||||||
 | 
					    from django.db import connections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c = connections['default'].cursor()
 | 
				
			||||||
 | 
					    print(c.db.__dict__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # config._reload_maybe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        feed = Feed.objects.get(pk=feed_pk)
 | 
					        feed = Feed.objects.get(pk=feed_pk)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,11 @@
 | 
				
			|||||||
 | 
					import yaml
 | 
				
			||||||
from django.views.generic import TemplateView
 | 
					from django.views.generic import TemplateView
 | 
				
			||||||
 | 
					from djconfig import config
 | 
				
			||||||
 | 
					from jconfig.base import BaseConfig
 | 
				
			||||||
 | 
					from yaml.parser import ParserError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from cabinet.utils import CabinetViewMixin
 | 
					from cabinet.utils import CabinetViewMixin
 | 
				
			||||||
from feeds.forms import FeedForm, get_config_form
 | 
					from feeds.forms import FeedForm, get_config_form, FeedsAppConfigForm
 | 
				
			||||||
from feeds.models import Feed
 | 
					from feeds.models import Feed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,3 +40,19 @@ class BaseFeedConfigView(CabinetViewMixin, TemplateView):
 | 
				
			|||||||
        ctx['feed_form'], ctx['config_form'] = self.get_forms() if forms is None else forms
 | 
					        ctx['feed_form'], ctx['config_form'] = self.get_forms() if forms is None else forms
 | 
				
			||||||
        ctx['feed_module'] = self.get_content_type().model_class()
 | 
					        ctx['feed_module'] = self.get_content_type().model_class()
 | 
				
			||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DatabaseConfig(BaseConfig):
 | 
				
			||||||
 | 
					    __slots__ = ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load(self, **kwargs):
 | 
				
			||||||
 | 
					        config._reload_maybe()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            settings = yaml.load(config.vk_auth)
 | 
				
			||||||
 | 
					        except (ParserError, AttributeError):
 | 
				
			||||||
 | 
					            settings = {}
 | 
				
			||||||
 | 
					        settings.setdefault(self.section_name, {})
 | 
				
			||||||
 | 
					        return settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self):
 | 
				
			||||||
 | 
					        FeedsAppConfigForm(data={'vk_auth': yaml.dump(self._settings)}).save()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
amqp==2.3.2
 | 
					amqp==2.3.2
 | 
				
			||||||
 | 
					beautifulsoup4==4.7.1
 | 
				
			||||||
billiard==3.5.0.5
 | 
					billiard==3.5.0.5
 | 
				
			||||||
celery==4.2.1
 | 
					celery==4.2.1
 | 
				
			||||||
certifi==2018.11.29
 | 
					certifi==2018.11.29
 | 
				
			||||||
@@ -17,12 +18,13 @@ psycopg2-binary==2.7.6.1
 | 
				
			|||||||
pyTelegramBotAPI==3.6.6
 | 
					pyTelegramBotAPI==3.6.6
 | 
				
			||||||
pytz==2018.9
 | 
					pytz==2018.9
 | 
				
			||||||
PyYAML==3.13
 | 
					PyYAML==3.13
 | 
				
			||||||
raven==6.10.0
 | 
					 | 
				
			||||||
redis==3.0.1
 | 
					redis==3.0.1
 | 
				
			||||||
requests==2.21.0
 | 
					requests==2.21.0
 | 
				
			||||||
 | 
					sentry-sdk==0.6.9
 | 
				
			||||||
six==1.12.0
 | 
					six==1.12.0
 | 
				
			||||||
 | 
					soupsieve==1.7.3
 | 
				
			||||||
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
 | 
					-e git+https://github.com/python273/vk_api@442281c9392109945dd6ed85a423d2fe8d068e7d#egg=vk_api
 | 
				
			||||||
Werkzeug==0.14.1
 | 
					Werkzeug==0.14.1
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user