1
0
Fork 0
mirror of https://github.com/EDeev/deev.space.git synced 2026-10-07 20:49:59 +03:00
deev.space/main/signals.py
Egor Deev 1320562734 Исправления безопасности и чистка кода
- render_tech_badge: format_html вместо mark_safe с непроверенной подстановкой (XSS);
- превью ссылок статьи: только публичные http(s)-адреса, без запросов во внутреннюю
  сеть сервера (SSRF); ошибки логируются вместо except: pass;
- автопостинг в Telegram переведён на parse_mode=HTML с html.escape (раньше в канал
  уходили видимые обратные слэши), включается переменной SOCIAL_AUTOPOST;
- убран ping Google (эндпоинт отключён в 2023 году);
- ошибка отправки письма с формы обратной связи больше не глушится;
- whitenoise и DJANGO_SERVE_MEDIA для запуска без nginx;
- импорты упорядочены, неиспользуемые удалены (ruff).
2026-10-02 11:59:07 +00:00

105 lines
3.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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'📝 <b>{html.escape(article.title)}</b>\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'<a href="{html.escape(article_url, quote=True)}">Читать полностью</a>'
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)