Telegram Webhookによるボット操作機能を追加(課題の追加・完了・一覧・スヌーズ対応)
This commit is contained in:
@@ -50,40 +50,92 @@ func (s *NotificationService) UpdateUserSettings(userID uint, settings *models.U
|
||||
settings.ID = existing.ID
|
||||
return database.GetDB().Save(settings).Error
|
||||
}
|
||||
func (s *NotificationService) SendTelegramNotification(chatID, message string) error {
|
||||
// InlineKeyboardMarkup represents a Telegram inline keyboard attached to a message.
|
||||
type InlineKeyboardMarkup struct {
|
||||
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
|
||||
}
|
||||
|
||||
// InlineKeyboardButton is a single button in an inline keyboard row.
|
||||
type InlineKeyboardButton struct {
|
||||
Text string `json:"text"`
|
||||
CallbackData string `json:"callback_data"`
|
||||
}
|
||||
|
||||
func (s *NotificationService) sendTelegramRequest(endpoint string, payload interface{}) error {
|
||||
if s.telegramBotToken == "" {
|
||||
return fmt.Errorf("telegram bot token is not configured")
|
||||
}
|
||||
if chatID == "" {
|
||||
return fmt.Errorf("telegram chat ID is empty")
|
||||
}
|
||||
|
||||
apiURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", s.telegramBotToken)
|
||||
|
||||
payload := map[string]string{
|
||||
"chat_id": chatID,
|
||||
"text": message,
|
||||
"parse_mode": "HTML",
|
||||
}
|
||||
|
||||
apiURL := fmt.Sprintf("https://api.telegram.org/bot%s/%s", s.telegramBotToken, endpoint)
|
||||
jsonPayload, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := http.Post(apiURL, "application/json", bytes.NewBuffer(jsonPayload))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("telegram API returned status %d", resp.StatusCode)
|
||||
return fmt.Errorf("telegram API %s returned status %d", endpoint, resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *NotificationService) SendTelegramNotification(chatID, message string) error {
|
||||
if chatID == "" {
|
||||
return fmt.Errorf("telegram chat ID is empty")
|
||||
}
|
||||
return s.SendMessageWithKeyboard(chatID, message, nil)
|
||||
}
|
||||
|
||||
// SendMessageWithKeyboard sends a Telegram message with an optional inline keyboard.
|
||||
func (s *NotificationService) SendMessageWithKeyboard(chatID, text string, keyboard *InlineKeyboardMarkup) error {
|
||||
if chatID == "" {
|
||||
return fmt.Errorf("telegram chat ID is empty")
|
||||
}
|
||||
payload := map[string]interface{}{
|
||||
"chat_id": chatID,
|
||||
"text": text,
|
||||
"parse_mode": "HTML",
|
||||
}
|
||||
if keyboard != nil {
|
||||
payload["reply_markup"] = keyboard
|
||||
}
|
||||
return s.sendTelegramRequest("sendMessage", payload)
|
||||
}
|
||||
|
||||
// AnswerCallbackQuery acknowledges a Telegram inline button press.
|
||||
func (s *NotificationService) AnswerCallbackQuery(callbackID, text string) error {
|
||||
payload := map[string]interface{}{
|
||||
"callback_query_id": callbackID,
|
||||
"show_alert": false,
|
||||
}
|
||||
if text != "" {
|
||||
payload["text"] = text
|
||||
}
|
||||
return s.sendTelegramRequest("answerCallbackQuery", payload)
|
||||
}
|
||||
|
||||
// EditMessageRemoveKeyboard removes the inline keyboard from an existing message.
|
||||
func (s *NotificationService) EditMessageRemoveKeyboard(chatID string, messageID int64) error {
|
||||
payload := map[string]interface{}{
|
||||
"chat_id": chatID,
|
||||
"message_id": messageID,
|
||||
"reply_markup": map[string]interface{}{"inline_keyboard": []interface{}{}},
|
||||
}
|
||||
return s.sendTelegramRequest("editMessageReplyMarkup", payload)
|
||||
}
|
||||
|
||||
// FindUserIDByChatID looks up a UserID by Telegram chat ID.
|
||||
func (s *NotificationService) FindUserIDByChatID(chatID string) (uint, error) {
|
||||
var settings models.UserNotificationSettings
|
||||
result := database.GetDB().Where("telegram_chat_id = ? AND telegram_enabled = ?", chatID, true).First(&settings)
|
||||
if result.Error != nil {
|
||||
return 0, fmt.Errorf("user not found for chat ID %s", chatID)
|
||||
}
|
||||
return settings.UserID, nil
|
||||
}
|
||||
|
||||
func (s *NotificationService) SendAssignmentReminder(userID uint, assignment *models.Assignment) error {
|
||||
settings, err := s.GetUserSettings(userID)
|
||||
if err != nil {
|
||||
@@ -201,10 +253,20 @@ func (s *NotificationService) SendUrgentReminder(userID uint, assignment *models
|
||||
assignment.DueDate.Format("2006/01/02 15:04"),
|
||||
)
|
||||
|
||||
keyboard := &InlineKeyboardMarkup{
|
||||
InlineKeyboard: [][]InlineKeyboardButton{
|
||||
{
|
||||
{Text: "✅ 完了", CallbackData: fmt.Sprintf("done:%d", assignment.ID)},
|
||||
{Text: "⏰ 15分後", CallbackData: fmt.Sprintf("snooze15:%d", assignment.ID)},
|
||||
{Text: "💬 今やってる", CallbackData: fmt.Sprintf("working:%d", assignment.ID)},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var errors []string
|
||||
|
||||
if settings.TelegramEnabled && settings.TelegramChatID != "" {
|
||||
if err := s.SendTelegramNotification(settings.TelegramChatID, message); err != nil {
|
||||
if err := s.SendMessageWithKeyboard(settings.TelegramChatID, message, keyboard); err != nil {
|
||||
errors = append(errors, fmt.Sprintf("Telegram: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user