diff --git a/.env.bak b/.env.bak new file mode 100644 index 0000000..855e3e0 --- /dev/null +++ b/.env.bak @@ -0,0 +1,63 @@ +# ============================================ +# Единый файл конфигурации для всех проектов +# Backend и Play-Life-Web +# ============================================ + +# ============================================ +# Database Configuration +# ============================================ +DB_HOST=localhost +DB_PORT=5432 +DB_USER=playeng +DB_PASSWORD=playeng +DB_NAME=playeng + +# ============================================ +# Backend Server Configuration +# ============================================ +# Порт для backend сервера (по умолчанию: 8080) +# В production всегда используется порт 8080 внутри контейнера +PORT=8080 + +# ============================================ +# Play Life Web Configuration +# ============================================ +# Порт для frontend приложения play-life-web +WEB_PORT=3001 + +# ============================================ +# Telegram Bot Configuration (optional) +# ============================================ +# Get token from @BotFather in Telegram: https://t.me/botfather +# To get chat ID: send a message to your bot, then visit: https://api.telegram.org/bot/getUpdates +# Look for "chat":{"id":123456789} - that number is your chat ID +TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here +TELEGRAM_CHAT_ID=123456789 +# Base URL для автоматической настройки webhook +# Примеры: +# - Для production с HTTPS: https://your-domain.com +# - Для локальной разработки с ngrok: https://abc123.ngrok.io +# - Для прямого доступа на нестандартном порту: http://your-server:8080 +# Webhook будет настроен автоматически при старте сервера на: /webhook/telegram +# Если не указан, webhook нужно настраивать вручную +TELEGRAM_WEBHOOK_BASE_URL=https://your-domain.com + +# ============================================ +# Todoist Webhook Configuration (optional) +# ============================================ +# Секрет для проверки подлинности webhook от Todoist +# Если задан, все запросы должны содержать заголовок X-Todoist-Webhook-Secret с этим значением +# Оставьте пустым, если не хотите использовать проверку секрета +TODOIST_WEBHOOK_SECRET= + +# ============================================ +# Scheduler Configuration +# ============================================ +# Часовой пояс для планировщика задач (например: Europe/Moscow, America/New_York, UTC) +# Используется для: +# - Автоматической фиксации целей на неделю каждый понедельник в 6:00 +# - Отправки ежедневного отчёта в 23:59 +# ВАЖНО: Укажите правильный часовой пояс, иначе задачи будут срабатывать в UTC! +# Список доступных часовых поясов: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +TIMEZONE=Europe/Moscow + diff --git a/VERSION b/VERSION index 653f458..5d99e49 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ -1.1.0 +1.1.1 diff --git a/play-life-backend/main.go b/play-life-backend/main.go index 2ede70a..c4c60c7 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -182,8 +182,9 @@ type TelegramWebhook struct { // TelegramUpdate - структура для Telegram webhook (обычно это Update объект) type TelegramUpdate struct { - UpdateID int `json:"update_id"` - Message TelegramMessage `json:"message"` + UpdateID int `json:"update_id"` + Message *TelegramMessage `json:"message,omitempty"` + EditedMessage *TelegramMessage `json:"edited_message,omitempty"` } type App struct { @@ -2374,20 +2375,22 @@ func main() { } // Пытаемся настроить webhook автоматически при старте, если есть base URL и bot token в БД - // Это опционально - основная регистрация происходит при сохранении токена через UI webhookBaseURL := getEnv("WEBHOOK_BASE_URL", "") if webhookBaseURL != "" { integration, err := app.getTelegramIntegration() if err == nil && integration.BotToken != nil && *integration.BotToken != "" { webhookURL := strings.TrimRight(webhookBaseURL, "/") + "/webhook/telegram" + log.Printf("Attempting to setup Telegram webhook at startup. WEBHOOK_BASE_URL='%s'", webhookBaseURL) if err := setupTelegramWebhook(*integration.BotToken, webhookURL); err != nil { log.Printf("Warning: Failed to setup Telegram webhook at startup: %v. Webhook will be configured when user saves bot token.", err) } else { - log.Printf("Telegram webhook configured successfully at startup: %s", webhookURL) + log.Printf("SUCCESS: Telegram webhook configured successfully at startup: %s", webhookURL) } } else { log.Printf("Telegram bot token not found in database. Webhook will be configured when user saves bot token.") } + } else { + log.Printf("WEBHOOK_BASE_URL not set. Webhook will be configured when user saves bot token.") } // Инициализируем БД для play-life проекта @@ -2469,6 +2472,7 @@ func getMapKeys(m map[string]interface{}) []string { // setupTelegramWebhook настраивает webhook для Telegram бота func setupTelegramWebhook(botToken, webhookURL string) error { apiURL := fmt.Sprintf("https://api.telegram.org/bot%s/setWebhook", botToken) + log.Printf("Setting up Telegram webhook: apiURL=%s, webhookURL=%s", apiURL, webhookURL) payload := map[string]string{ "url": webhookURL, @@ -2486,12 +2490,15 @@ func setupTelegramWebhook(botToken, webhookURL string) error { resp, err := client.Post(apiURL, "application/json", bytes.NewBuffer(jsonData)) if err != nil { + log.Printf("ERROR: Failed to send webhook setup request: %v", err) return fmt.Errorf("failed to send webhook setup request: %w", err) } defer resp.Body.Close() + bodyBytes, _ := io.ReadAll(resp.Body) + log.Printf("Telegram API response: status=%d, body=%s", resp.StatusCode, string(bodyBytes)) + if resp.StatusCode != http.StatusOK { - bodyBytes, _ := io.ReadAll(resp.Body) return fmt.Errorf("telegram API returned status %d: %s", resp.StatusCode, string(bodyBytes)) } @@ -4100,24 +4107,51 @@ func (a *App) telegramWebhookHandler(w http.ResponseWriter, r *http.Request) { return } - // Сохраняем chat_id при первом сообщении - if update.Message.Chat.ID != 0 { - chatIDStr := strconv.FormatInt(update.Message.Chat.ID, 10) + // Определяем, какое сообщение использовать (message или edited_message) + var message *TelegramMessage + if update.Message != nil { + message = update.Message + log.Printf("Telegram webhook received: update_id=%d, message type=message", update.UpdateID) + } else if update.EditedMessage != nil { + message = update.EditedMessage + log.Printf("Telegram webhook received: update_id=%d, message type=edited_message", update.UpdateID) + } else { + log.Printf("Telegram webhook received: update_id=%d, but no message or edited_message found", update.UpdateID) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]string{ + "message": "No message found in update", + }) + return + } + + log.Printf("Telegram webhook: message present, chat_id=%d", message.Chat.ID) + + // Сохраняем chat_id при первом сообщении (даже если нет текста) + if message.Chat.ID != 0 { + chatIDStr := strconv.FormatInt(message.Chat.ID, 10) + log.Printf("Processing chat_id: %s", chatIDStr) integration, err := a.getTelegramIntegration() - if err == nil { + if err != nil { + log.Printf("Error getting telegram integration: %v", err) + } else { // Сохраняем chat_id, если его еще нет if integration.ChatID == nil || *integration.ChatID == "" { + log.Printf("Attempting to save chat_id: %s", chatIDStr) if err := a.saveTelegramChatID(chatIDStr); err != nil { log.Printf("Warning: Failed to save chat_id: %v", err) } else { - log.Printf("Saved chat_id from first message: %s", chatIDStr) + log.Printf("Successfully saved chat_id from first message: %s", chatIDStr) } + } else { + log.Printf("Chat_id already exists in database: %s", *integration.ChatID) } } + } else { + log.Printf("Warning: message.Chat.ID is 0, cannot save chat_id") } - // Проверяем, что есть message - if update.Message.Text == "" { + // Проверяем, что есть текст в сообщении + if message.Text == "" { log.Printf("Telegram webhook: no text in message") w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ @@ -4126,8 +4160,8 @@ func (a *App) telegramWebhookHandler(w http.ResponseWriter, r *http.Request) { return } - fullText := update.Message.Text - entities := update.Message.Entities + fullText := message.Text + entities := message.Entities if entities == nil { entities = []TelegramEntity{} } @@ -4278,16 +4312,18 @@ func (a *App) updateTelegramIntegrationHandler(w http.ResponseWriter, r *http.Re // Настраиваем webhook автоматически при сохранении токена webhookBaseURL := getEnv("WEBHOOK_BASE_URL", "") + log.Printf("Attempting to setup Telegram webhook. WEBHOOK_BASE_URL='%s'", webhookBaseURL) if webhookBaseURL != "" { webhookURL := strings.TrimRight(webhookBaseURL, "/") + "/webhook/telegram" + log.Printf("Setting up Telegram webhook: URL=%s", webhookURL) if err := setupTelegramWebhook(req.BotToken, webhookURL); err != nil { - log.Printf("Warning: Failed to setup Telegram webhook: %v", err) + log.Printf("ERROR: Failed to setup Telegram webhook: %v", err) // Не возвращаем ошибку, так как токен уже сохранен } else { - log.Printf("Telegram webhook configured successfully: %s", webhookURL) + log.Printf("SUCCESS: Telegram webhook configured successfully: %s", webhookURL) } } else { - log.Printf("Warning: WEBHOOK_BASE_URL not set. Webhook will not be configured automatically.") + log.Printf("WARNING: WEBHOOK_BASE_URL not set. Webhook will not be configured automatically.") } integration, err := a.getTelegramIntegration() diff --git a/play-life-web/package.json b/play-life-web/package.json index c3203e5..e486bed 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "1.1.0", + "version": "1.1.1", "type": "module", "scripts": { "dev": "vite",