import html
import logging
import requests
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Article
logger = logging.getLogger(__name__)
SITE_URL = 'https://deev.space'
@receiver(post_save, sender=Article)
def publish_to_social_media(sender, instance, created, **kwargs):
"""Автоматическая публикация новой статьи в социальные сети."""
if not created or not instance.is_published or instance.is_achievement:
return
if settings.SOCIAL_AUTOPOST:
if settings.TELEGRAM_BOT_TOKEN and settings.TELEGRAM_CHANNEL_ID:
try:
publish_to_telegram(instance)
logger.info('Статья "%s" опубликована в Telegram', instance.title)
except requests.RequestException:
logger.exception('Ошибка публикации в Telegram')
if settings.VK_ACCESS_TOKEN and settings.VK_GROUP_ID:
try:
publish_to_vk(instance)
logger.info('Статья "%s" опубликована в VK', instance.title)
except requests.RequestException:
logger.exception('Ошибка публикации в VK')
ping_search_engines()
def build_telegram_text(article):
"""Текст поста для Telegram в режиме parse_mode=HTML."""
article_url = f'{SITE_URL}{article.get_absolute_url()}'
text = f'📝 {html.escape(article.title)}\n\n'
if article.excerpt:
excerpt = article.excerpt[:200] + '...' if len(article.excerpt) > 200 else article.excerpt
text += f'{html.escape(excerpt)}\n\n'
text += f'Читать полностью'
return text
def publish_to_telegram(article):
"""Публикация статьи в Telegram-канал."""
api = f'https://api.telegram.org/bot{settings.TELEGRAM_BOT_TOKEN}'
text = build_telegram_text(article)
if article.img:
url = f'{api}/sendPhoto'
data = {
'chat_id': settings.TELEGRAM_CHANNEL_ID,
'photo': f'{SITE_URL}{article.img.url}',
'caption': text,
'parse_mode': 'HTML',
}
else:
url = f'{api}/sendMessage'
data = {
'chat_id': settings.TELEGRAM_CHANNEL_ID,
'text': text,
'parse_mode': 'HTML',
}
response = requests.post(url, data=data, timeout=10)
response.raise_for_status()
def publish_to_vk(article):
"""Публикация статьи в группу VKontakte."""
article_url = f'{SITE_URL}{article.get_absolute_url()}'
message = f'📝 {article.title}\n\n'
if article.excerpt:
excerpt = article.excerpt[:300] + '...' if len(article.excerpt) > 300 else article.excerpt
message += f'{excerpt}\n\n'
message += f'🔗 Читать: {article_url}'
params = {
'owner_id': f'-{settings.VK_GROUP_ID}',
'message': message,
'from_group': 1,
'access_token': settings.VK_ACCESS_TOKEN,
'v': '5.131',
}
if article.img:
params['attachments'] = f'{SITE_URL}{article.img.url}'
response = requests.post('https://api.vk.com/method/wall.post', params=params, timeout=10)
response.raise_for_status()
def ping_search_engines():
"""Уведомление Яндекса об обновлении sitemap (Google ping-эндпоинт отключил в 2023 году)."""
try:
requests.get(f'https://webmaster.yandex.ru/ping?sitemap={SITE_URL}/sitemap.xml', timeout=5)
except requests.RequestException as e:
logger.warning('Ошибка ping Яндекса: %s', e)