mirror of
https://github.com/EDeev/deev.space.git
synced 2026-10-07 20:49:59 +03:00
Перенесено всё, что накопилось на сервере с декабря 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).
136 lines
No EOL
4.5 KiB
Python
136 lines
No EOL
4.5 KiB
Python
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}') |