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 878b4580e4 Версия 2.0: код с продакшена deev.space
Перенесено всё, что накопилось на сервере с декабря 2025:
- анонимный посетитель по подписанной cookie (main/middleware.py), лайки и дизлайки
  без регистрации с антинакруткой, уникальные просмотры статей;
- карточка-паспорт, стек в одну строку, блок «В цифрах»;
- миграции 0005–0008, команды load_initial_data и populate_demo, robots.txt;
- обновлённые шаблоны, стили и скрипты.

Безопасность и порядок:
- все секреты только из окружения, значения по умолчанию пустые;
- DEBUG по умолчанию выключен, без DJANGO_SECRET_KEY запуск в бою невозможен;
- ALLOWED_HOSTS, путь к базе и SSL-редирект настраиваются переменными;
- убрана статика админки Django (результат collectstatic) и media из git;
- добавлены .gitignore и .gitattributes (переводы строк — LF).
2026-10-02 11:58:54 +00:00

136 lines
No EOL
4.5 KiB
Python
Raw 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.

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
import requests
import logging
from .models import Article
logger = logging.getLogger(__name__)
@receiver(post_save, sender=Article)
def publish_to_social_media(sender, instance, created, **kwargs):
"""Автоматическая публикация новой статьи в социальные сети."""
if not created:
return
if not instance.is_published:
return
if instance.is_achievement:
return
'''
# Telegram
if settings.TELEGRAM_BOT_TOKEN and settings.TELEGRAM_CHANNEL_ID:
try:
publish_to_telegram(instance)
logger.info(f'Статья "{instance.title}" опубликована в Telegram')
except Exception as e:
logger.error(f'Ошибка публикации в Telegram: {e}')
# VK
if settings.VK_ACCESS_TOKEN and settings.VK_GROUP_ID:
try:
publish_to_vk(instance)
logger.info(f'Статья "{instance.title}" опубликована в VK')
except Exception as e:
logger.error(f'Ошибка публикации в VK: {e}')
'''
try:
ping_search_engines(instance)
logger.info(f'Поисковые системы уведомлены о статье "{instance.title}"')
except Exception as e:
logger.error(f'Ошибка уведомления поисковых систем: {e}')
def publish_to_telegram(article):
"""Публикация статьи в Telegram-канал."""
bot_token = settings.TELEGRAM_BOT_TOKEN
channel_id = settings.TELEGRAM_CHANNEL_ID
article_url = f"https://deev.space{article.get_absolute_url()}"
text = f"📝 *{escape_markdown(article.title)}*\n\n"
if article.excerpt:
excerpt = article.excerpt[:200] + '...' if len(article.excerpt) > 200 else article.excerpt
text += f"{escape_markdown(excerpt)}\n\n"
text += f"[Читать полностью]({article_url})"
if article.img:
url = f"https://api.telegram.org/bot{bot_token}/sendPhoto"
data = {
'chat_id': channel_id,
'photo': f"https://deev.space{article.img.url}",
'caption': text,
'parse_mode': 'Markdown'
}
else:
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
data = {
'chat_id': channel_id,
'text': text,
'parse_mode': 'Markdown',
'disable_web_page_preview': False
}
response = requests.post(url, data=data, timeout=10)
response.raise_for_status()
def publish_to_vk(article):
"""Публикация статьи в группу VKontakte."""
access_token = settings.VK_ACCESS_TOKEN
group_id = settings.VK_GROUP_ID
article_url = f"https://deev.space{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}"
url = "https://api.vk.com/method/wall.post"
params = {
'owner_id': f'-{group_id}',
'message': message,
'from_group': 1,
'access_token': access_token,
'v': '5.131'
}
if article.img:
params['attachments'] = f"https://deev.space{article.img.url}"
response = requests.post(url, params=params, timeout=10)
response.raise_for_status()
def escape_markdown(text):
"""Экранирование специальных символов Markdown."""
escape_chars = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!']
for char in escape_chars:
text = text.replace(char, f'\\{char}')
return text
def ping_search_engines(article):
"""Уведомление поисковых систем о новой статье."""
article_url = f"https://deev.space{article.get_absolute_url()}"
# Google
try:
google_ping_url = f"https://www.google.com/ping?sitemap=https://deev.space/sitemap.xml"
requests.get(google_ping_url, timeout=5)
except Exception as e:
logger.error(f'Ошибка ping Google: {e}')
# Яндекс
try:
yandex_ping_url = f"https://webmaster.yandex.ru/ping?sitemap=https://deev.space/sitemap.xml"
requests.get(yandex_ping_url, timeout=5)
except Exception as e:
logger.error(f'Ошибка ping Яндекс: {e}')