diff --git a/services/scheduler.py b/services/scheduler.py index 7e0f5d8..3b2d477 100644 --- a/services/scheduler.py +++ b/services/scheduler.py @@ -111,15 +111,15 @@ class Scheduler: ) logger.info('✅ Добавлена задача проверки запланированных постов') - # Еженедельная генерация дайджеста (воскресенье 09:00) + # Еженедельная генерация дайджеста (воскресенье 15:00 UTC = 19:00 Ульяновск) self.scheduler.add_job( self.weekly_digest_generation, - CronTrigger.from_crontab('0 9 * * 0'), # Каждое воскресенье в 09:00 + CronTrigger.from_crontab('0 15 * * 0'), # Каждое воскресенье в 15:00 UTC (19:00 local) id='weekly_digest', name='Генерация еженедельного дайджеста', replace_existing=True ) - logger.info('✅ Добавлена задача генерации дайджеста') + logger.info('✅ Добавлена задача генерации дайджеста (воскресенье 19:00 Ульяновск)') def stop(self): """Остановка планировщика""" diff --git a/web/app.py b/web/app.py index d53ccc1..5bffb3c 100644 --- a/web/app.py +++ b/web/app.py @@ -1227,6 +1227,81 @@ async def api_get_broadcast_non_readers(broadcast_id: int, username: str = Depen # V3.1 - ДАЙДЖЕСТЫ # ============================================================================ +@app.post("/api/digest/generate") +async def api_generate_digest(username: str = Depends(get_current_admin)): + """Сгенерировать дайджест прямо сейчас (из веб-панели)""" + from services.digest_service import DigestService + from database.models import Digest + from datetime import date + + try: + async with AsyncSessionLocal() as session: + service = DigestService(session) + + # Генерируем + digest_data = await service.generate_weekly_digest() + + if not digest_data: + return JSONResponse({ + "success": False, + "error": "Не удалось сгенерировать дайджест. Проверьте логи." + }, status_code=500) + + # Проверяем нет ли уже за эту неделю + check_stmt = select(Digest).where( + Digest.week_number == digest_data['week_number'], + Digest.year == digest_data['year'] + ) + result = await session.execute(check_stmt) + existing = result.scalar_one_or_none() + + if existing: + return JSONResponse({ + "success": True, + "message": f"Дайджест за неделю #{digest_data['week_number']}/{digest_data['year']} уже существует (ID: #{existing.id}). Вы можете отправить его в разделе 'Архив'.", + "digest_id": existing.id, + "already_exists": True + }) + + # Сохраняем + digest_id = await service.save_digest(digest_data, status='pending_approval') + + # Отправляем превью админу в личку + from bot_instance import get_bot + from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + + bot = get_bot() + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="🌐 Утвердить в веб-панели", url="http://localhost:8000/digests")], + ]) + + await bot.send_message( + config.ADMIN_USER_ID, + f"📰 Дайджест за неделю готов!\n\n" + f"Неделя #{digest_data['week_number']}/{digest_data['year']}\n" + f"Период: {digest_data['period_start'].strftime('%d.%m')} - {digest_data['period_end'].strftime('%d.%m.%Y')}\n\n" + f"Зайдите в веб-панель для утверждения:\n" + f"http://localhost:8000/digests", + parse_mode='HTML', + reply_markup=keyboard + ) + + return JSONResponse({ + "success": True, + "message": f"✅ Дайджест #{digest_id} сгенерирован! Превью отправлено вам в Telegram.", + "digest_id": digest_id + }) + + except Exception as e: + import traceback + logger.error(f"Ошибка генерации дайджеста: {e}") + traceback.print_exc() + return JSONResponse({ + "success": False, + "error": f"Критическая ошибка: {str(e)}" + }, status_code=500) + + @app.get("/digests", response_class=HTMLResponse) async def digests_page(request: Request, username: str = Depends(get_current_admin)): """Страница дайджестов""" diff --git a/web/templates/digests.html b/web/templates/digests.html index 81167e0..1dbf166 100644 --- a/web/templates/digests.html +++ b/web/templates/digests.html @@ -245,8 +245,28 @@ } } - function generateNow() { - alert('Генерация дайджеста запущена! Проверьте Telegram - бот отправит превью.'); + async function generateNow() { + const btn = event.target; + btn.disabled = true; + btn.textContent = '⏳ Генерация...'; + + try { + const r = await fetch('/api/digest/generate', { method: 'POST' }); + const result = await r.json(); + + if (result.success) { + alert('✅ ' + result.message); + location.reload(); + } else { + alert('❌ Ошибка: ' + (result.error || 'Неизвестная')); + btn.disabled = false; + btn.textContent = '🔄 Сгенерировать сейчас'; + } + } catch (err) { + alert('❌ Ошибка: ' + err.message); + btn.disabled = false; + btn.textContent = '🔄 Сгенерировать сейчас'; + } } {% endblock %}