• XSS.stack #1 – первый литературный журнал от юзеров форума

бот обратной связи на GO с BD

coolmiks

HDD-drive
Пользователь
Регистрация
24.01.2019
Сообщения
25
Реакции
7
с чат GPT накатал бота телеграмм, в него можно писать, отправлять файлы, медиа.

Основной функционал​

  1. Обработка сообщений пользователей:
    • Пользователи могут отправлять сообщения боту.
    • Сообщения от пользователей пересылаются администратору.
    • Бот отвечает пользователям, информируя их о том, что их сообщение было отправлено администратору.
  2. Обработка сообщений администратора:
    • Администратор может отправлять команды боту.
    • Администратор может управлять пользователями (блокировка, разблокировка).
    • Администратор может рассылать сообщения всем пользователям.
  3. Блокировка и разблокировка пользователей:
    • Администратор может блокировать и разблокировать пользователей.
    • Заблокированные пользователи не могут отправлять сообщения бот.
  4. Обработка callback-запросов:
    • Администратор может блокировать, отвечать на сообщения или удалять сообщения через inline-кнопки.
  5. Рассылка сообщений:
    • Администратор может отправлять одно сообщение всем пользователям.(Тут вроде не работает фикция)
  6. Логирование действий:
    • Бот ведет лог сообщений и действий в базе данных.

Команды для администратора​

  1. /banlist
    • Описание: Отправляет список всех заблокированных пользователей администратору.
    • Результат: Бот возвращает сообщение с перечислением всех заблокированных пользователей или уведомление, если заблокированных пользователей нет.
  2. /chat
    • Описание: Переводит бота в режим рассылки сообщений.
    • Результат: Администратор получает запрос на ввод сообщения, которое будет разослано всем пользователям.
  3. /unban
    • Описание: Переводит бота в режим разблокировки пользователей.
    • Результат: Администратор получает запрос на ввод ID пользователя для разблокировки. После ввода ID пользователь будет разблокирован.

Логирование​

  • Логирование сообщений: Все сообщения пользователей и администратора сохраняются в базе данных.
  • Логирование действий: Действия, такие как блокировка пользователей, также сохраняются в базе данных.
  • если кто-то допилит до идеала буду рад)
Код:
package main

import (
    "fmt"
    "log"
    "strconv"
    "strings"
    "time"

    "github.com/go-telegram-bot-api/telegram-bot-api/v5"
    "github.com/tidwall/buntdb"
)

var (
    botToken      = "ТОКЕН"
    adminChatID   = int64(64834138) // ID администратора
    dbFile        = "bot_logs.db"    // Файл базы данных
    replyingTo    = make(map[int64]int64) // Контекст ответа: админ -> пользователь
    broadcastMode = false                  // Режим рассылки
    unbanMode     = false                  // Режим разблокировки
)

func main() {
    bot, err := tgbotapi.NewBotAPI(botToken)
    if err != nil {
        log.Panic(err)
    }

    // Открытие или создание базы данных
    db, err := buntdb.Open(dbFile)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    log.Printf("Authorized on account %s", bot.Self.UserName)

    u := tgbotapi.NewUpdate(0)
    u.Timeout = 60
    updates := bot.GetUpdatesChan(u)

    for update := range updates {
        if update.Message != nil {
            if update.Message.From.ID == adminChatID {
                handleAdminMessage(bot, update, db)
            } else {
                handleUserMessage(bot, update, db)
            }
        }
        if update.CallbackQuery != nil {
            handleCallback(bot, update.CallbackQuery, db)
        }
    }
}

// Обработка сообщений от пользователей
func handleUserMessage(bot *tgbotapi.BotAPI, update tgbotapi.Update, db *buntdb.DB) {
    userID := update.Message.From.ID
    userMessage := update.Message.Text
    chatID := update.Message.Chat.ID

    if isUserBlocked(db, userID) {
        return
    }

    logMessage(db, userID, userMessage, "User")
    forwardMessageToAdmin(bot, update, adminChatID, userID)
    response := tgbotapi.NewMessage(chatID, "Ваше сообщение отправлено администратору.")
    bot.Send(response)
}

// Обработка сообщений от администратора
func handleAdminMessage(bot *tgbotapi.BotAPI, update tgbotapi.Update, db *buntdb.DB) {
    adminID := update.Message.From.ID
    message := update.Message.Text

    if userID, ok := replyingTo[adminID]; ok {
        replyToUser(bot, userID, message)
        delete(replyingTo, adminID)
        return
    }

    switch message {
    case "/banlist":
        sendBanList(bot, adminID, db)
    case "/chat":
        broadcastMode = true
        msg := tgbotapi.NewMessage(adminID, "Введите сообщение для рассылки всем пользователям.")
        bot.Send(msg)
    case "/unban":
        unbanMode = true
        msg := tgbotapi.NewMessage(adminID, "Введите ID пользователя для разблокировки.")
        bot.Send(msg)
    default:
        if broadcastMode {
            broadcastMessage(bot, message, db)
            broadcastMode = false
        }
        if unbanMode {
            userID, err := strconv.ParseInt(message, 10, 64)
            if err != nil {
                msg := tgbotapi.NewMessage(adminID, "Некорректный ID пользователя.")
                bot.Send(msg)
                return
            }
            unblockUser(db, userID)
            msg := tgbotapi.NewMessage(adminID, fmt.Sprintf("Пользователь %d разблокирован.", userID))
            bot.Send(msg)
            unbanMode = false
        } else {
            msg := tgbotapi.NewMessage(adminID, "Используйте кнопки для управления.")
            bot.Send(msg)
        }
    }
}

// Обработка callback-запросов
func handleCallback(bot *tgbotapi.BotAPI, callback *tgbotapi.CallbackQuery, db *buntdb.DB) {
    data := strings.Split(callback.Data, ":")
    action := data[0]
    userID, _ := strconv.ParseInt(data[1], 10, 64)

    switch action {
    case "block":
        blockUser(bot, userID, callback, db)
    case "reply":
        prepareReply(bot, userID, callback)
    case "delete":
        deleteMessage(bot, callback)
    }
}

// Блокировка пользователя
func blockUser(bot *tgbotapi.BotAPI, userID int64, callback *tgbotapi.CallbackQuery, db *buntdb.DB) {
    logAction(db, "Blocked", userID)
    msg := tgbotapi.NewMessage(callback.Message.Chat.ID, fmt.Sprintf("Пользователь %d заблокирован.", userID))
    bot.Send(msg)
}

// Разблокировка пользователя
func unblockUser(db *buntdb.DB, userID int64) {
    db.Update(func(tx *buntdb.Tx) error {
        tx.Delete(fmt.Sprintf("blocked:%d", userID))
        return nil
    })
}

// Подготовка ответа пользователю
func prepareReply(bot *tgbotapi.BotAPI, userID int64, callback *tgbotapi.CallbackQuery) {
    replyingTo[callback.Message.Chat.ID] = userID
    msg := tgbotapi.NewMessage(callback.Message.Chat.ID, "Введите сообщение для отправки пользователю.")
    bot.Send(msg)
}

// Удаление сообщения у админа
func deleteMessage(bot *tgbotapi.BotAPI, callback *tgbotapi.CallbackQuery) {
    del := tgbotapi.NewDeleteMessage(callback.Message.Chat.ID, callback.Message.MessageID)
    bot.Send(del)

    msg := tgbotapi.NewMessage(callback.Message.Chat.ID, "Сообщение удалено.")
    bot.Send(msg)
}

// Логирование сообщений и действий
func logMessage(db *buntdb.DB, userID int64, message string, sender string) {
    db.Update(func(tx *buntdb.Tx) error {
        key := fmt.Sprintf("%d:%s", time.Now().Unix(), sender)
        tx.Set(key, fmt.Sprintf("User: %d, Message: %s", userID, message), nil)
        return nil
    })
}

// Логирование действий
func logAction(db *buntdb.DB, action string, userID int64) {
    db.Update(func(tx *buntdb.Tx) error {
        tx.Set(fmt.Sprintf("blocked:%d", userID), "true", nil)
        return nil
    })
}

// Проверка на блокировку
func isUserBlocked(db *buntdb.DB, userID int64) bool {
    blocked := false
    db.View(func(tx *buntdb.Tx) error {
        _, err := tx.Get(fmt.Sprintf("blocked:%d", userID))
        if err == nil {
            blocked = true
        }
        return nil
    })
    return blocked
}

// Рассылка сообщений всем пользователям
func broadcastMessage(bot *tgbotapi.BotAPI, message string, db *buntdb.DB) {
    db.View(func(tx *buntdb.Tx) error {
        tx.AscendKeys("user:*", func(key, value string) bool {
            userID, _ := strconv.ParseInt(strings.TrimPrefix(key, "user:"), 10, 64)
            msg := tgbotapi.NewMessage(userID, message)
            bot.Send(msg)
            return true
        })
        return nil
    })
}

// Отправка списка заблокированных пользователей
func sendBanList(bot *tgbotapi.BotAPI, chatID int64, db *buntdb.DB) {
    var banList []string
    db.View(func(tx *buntdb.Tx) error {
        tx.AscendKeys("blocked:*", func(key, _ string) bool {
            userID := strings.TrimPrefix(key, "blocked:")
            banList = append(banList, userID)
            return true
        })
        return nil
    })

    if len(banList) == 0 {
        msg := tgbotapi.NewMessage(chatID, "Нет заблокированных пользователей.")
        bot.Send(msg)
    } else {
        msg := tgbotapi.NewMessage(chatID, "Заблокированные пользователи:\n" + strings.Join(banList, "\n"))
        bot.Send(msg)
    }
}

// Пересылка сообщения администратору
func forwardMessageToAdmin(bot *tgbotapi.BotAPI, update tgbotapi.Update, adminID int64, userID int64) {
    var msg tgbotapi.Chattable
    if update.Message.Document != nil {
        msg = tgbotapi.NewDocument(adminID, tgbotapi.FileID(update.Message.Document.FileID))
    } else if len(update.Message.Photo) > 0 {
        msg = tgbotapi.NewPhoto(adminID, tgbotapi.FileID(update.Message.Photo[0].FileID))
    } else if update.Message.Video != nil {
        msg = tgbotapi.NewVideo(adminID, tgbotapi.FileID(update.Message.Video.FileID))
    } else if update.Message.Audio != nil {
        msg = tgbotapi.NewAudio(adminID, tgbotapi.FileID(update.Message.Audio.FileID))
    } else {
        msg = tgbotapi.NewMessage(adminID, update.Message.Text)
    }

    if msg != nil {
        bot.Send(msg)
    }

    // Добавляем кнопки
    buttons := []tgbotapi.InlineKeyboardButton{
        tgbotapi.NewInlineKeyboardButtonData("Блокировать", fmt.Sprintf("block:%d", userID)),
        tgbotapi.NewInlineKeyboardButtonData("Ответить", fmt.Sprintf("reply:%d", userID)),
        tgbotapi.NewInlineKeyboardButtonData("Удалить", fmt.Sprintf("delete:%d", userID)),
    }
    inlineKeyboard := tgbotapi.NewInlineKeyboardMarkup(buttons)
    msgWithButtons := tgbotapi.NewMessage(adminID, fmt.Sprintf("Сообщение от пользователя %d", userID))
    msgWithButtons.ReplyMarkup = inlineKeyboard

    bot.Send(msgWithButtons)
}

// Отправка сообщения пользователю от администратора
func replyToUser(bot *tgbotapi.BotAPI, userID int64, message string) {
    msg := tgbotapi.NewMessage(userID, message)
    bot.Send(msg)
}
 

Вложения

  • Снимок экрана 2024-08-30 085847.jpg
    Снимок экрана 2024-08-30 085847.jpg
    45.4 КБ · Просмотры: 41
  • Снимок экрана 2024-08-30 085926.jpg
    Снимок экрана 2024-08-30 085926.jpg
    24.3 КБ · Просмотры: 40
Пожалуйста, обратите внимание, что пользователь заблокирован
Код:
package main

import (
    "fmt"
    "log"
    "strconv"
    "strings"
    "time"

    "github.com/go-telegram-bot-api/telegram-bot-api/v5"
    "github.com/tidwall/buntdb"
)

type BotHandler struct {
    bot           *tgbotapi.BotAPI
    adminChatID   int64
    db            *buntdb.DB
    replyingTo    map[int64]int64
    broadcastMode bool
    unbanMode     bool
}

func main() {
    botToken := "ТОКЕН"
    adminChatID := int64(64834138)
    dbFile := "bot_logs.db"

    bot, err := tgbotapi.NewBotAPI(botToken)
    if err != nil {
        log.Panic(err)
    }

    db, err := buntdb.Open(dbFile)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    handler := &BotHandler{
        bot:           bot,
        adminChatID:   adminChatID,
        db:            db,
        replyingTo:    make(map[int64]int64),
        broadcastMode: false,
        unbanMode:     false,
    }

    log.Printf("Authorized on account %s", bot.Self.UserName)

    u := tgbotapi.NewUpdate(0)
    u.Timeout = 60
    updates := bot.GetUpdatesChan(u)

    for update := range updates {
        if update.Message != nil {
            handler.handleMessage(update)
        } else if update.CallbackQuery != nil {
            handler.handleCallback(update.CallbackQuery)
        }
    }
}

func (h *BotHandler) handleMessage(update tgbotapi.Update) {
    if update.Message.From.ID == h.adminChatID {
        h.handleAdminMessage(update)
    } else {
        h.handleUserMessage(update)
    }
}

// Обработка сообщений от пользователей
func (h *BotHandler) handleUserMessage(update tgbotapi.Update) {
    userID := update.Message.From.ID
    userMessage := update.Message.Text
    chatID := update.Message.Chat.ID

    if h.isUserBlocked(userID) {
        return
    }

    h.logMessage(userID, userMessage, "User")
    h.forwardMessageToAdmin(update, userID)
    response := tgbotapi.NewMessage(chatID, "Ваше сообщение отправлено администратору.")
    h.bot.Send(response)
}

// Обработка сообщений от администратора
func (h *BotHandler) handleAdminMessage(update tgbotapi.Update) {
    message := update.Message.Text

    if userID, ok := h.replyingTo[h.adminChatID]; ok {
        h.replyToUser(userID, message)
        delete(h.replyingTo, h.adminChatID)
        return
    }

    switch message {
    case "/banlist":
        h.sendBanList()
    case "/chat":
        h.broadcastMode = true
        msg := tgbotapi.NewMessage(h.adminChatID, "Введите сообщение для рассылки всем пользователям.")
        h.bot.Send(msg)
    case "/unban":
        h.unbanMode = true
        msg := tgbotapi.NewMessage(h.adminChatID, "Введите ID пользователя для разблокировки.")
        h.bot.Send(msg)
    default:
        if h.broadcastMode {
            h.broadcastMessage(message)
            h.broadcastMode = false
        } else if h.unbanMode {
            h.handleUnban(message)
        } else {
            msg := tgbotapi.NewMessage(h.adminChatID, "Используйте кнопки для управления.")
            h.bot.Send(msg)
        }
    }
}

func (h *BotHandler) handleCallback(callback *tgbotapi.CallbackQuery) {
    data := strings.Split(callback.Data, ":")
    action := data[0]
    userID, _ := strconv.ParseInt(data[1], 10, 64)

    switch action {
    case "block":
        h.blockUser(userID, callback)
    case "reply":
        h.prepareReply(userID, callback)
    case "delete":
        h.deleteMessage(callback)
    }
}

// Блокировка пользователя
func (h *BotHandler) blockUser(userID int64, callback *tgbotapi.CallbackQuery) {
    h.logAction("Blocked", userID)
    msg := tgbotapi.NewMessage(callback.Message.Chat.ID, fmt.Sprintf("Пользователь %d заблокирован.", userID))
    h.bot.Send(msg)
}

// Разблокировка пользователя
func (h *BotHandler) unblockUser(userID int64) {
    h.db.Update(func(tx *buntdb.Tx) error {
        tx.Delete(fmt.Sprintf("blocked:%d", userID))
        return nil
    })
}

// Подготовка ответа пользователю
func (h *BotHandler) prepareReply(userID int64, callback *tgbotapi.CallbackQuery) {
    h.replyingTo[callback.Message.Chat.ID] = userID
    msg := tgbotapi.NewMessage(callback.Message.Chat.ID, "Введите сообщение для отправки пользователю.")
    h.bot.Send(msg)
}

// Удаление сообщения у админа
func (h *BotHandler) deleteMessage(callback *tgbotapi.CallbackQuery) {
    del := tgbotapi.NewDeleteMessage(callback.Message.Chat.ID, callback.Message.MessageID)
    h.bot.Send(del)

    msg := tgbotapi.NewMessage(callback.Message.Chat.ID, "Сообщение удалено.")
    h.bot.Send(msg)
}

// Логирование сообщений и действий
func (h *BotHandler) logMessage(userID int64, message string, sender string) {
    h.db.Update(func(tx *buntdb.Tx) error {
        key := fmt.Sprintf("%d:%s", time.Now().Unix(), sender)
        tx.Set(key, fmt.Sprintf("User: %d, Message: %s", userID, message), nil)
        return nil
    })
}

func (h *BotHandler) logAction(action string, userID int64) {
    h.db.Update(func(tx *buntdb.Tx) error {
        tx.Set(fmt.Sprintf("blocked:%d", userID), "true", nil)
        return nil
    })
}

// Проверка на блокировку
func (h *BotHandler) isUserBlocked(userID int64) bool {
    blocked := false
    h.db.View(func(tx *buntdb.Tx) error {
        _, err := tx.Get(fmt.Sprintf("blocked:%d", userID))
        if err == nil {
            blocked = true
        }
        return nil
    })
    return blocked
}

// Рассылка сообщений всем пользователям
func (h *BotHandler) broadcastMessage(message string) {
    h.db.View(func(tx *buntdb.Tx) error {
        tx.AscendKeys("user:*", func(key, value string) bool {
            userID, _ := strconv.ParseInt(strings.TrimPrefix(key, "user:"), 10, 64)
            msg := tgbotapi.NewMessage(userID, message)
            h.bot.Send(msg)
            return true
        })
        return nil
    })
}

// Отправка списка заблокированных пользователей
func (h *BotHandler) sendBanList() {
    var banList []string
    h.db.View(func(tx *buntdb.Tx) error {
        tx.AscendKeys("blocked:*", func(key, _ string) bool {
            userID := strings.TrimPrefix(key, "blocked:")
            banList = append(banList, userID)
            return true
        })
        return nil
    })

    if len(banList) == 0 {
        msg := tgbotapi.NewMessage(h.adminChatID, "Нет заблокированных пользователей.")
        h.bot.Send(msg)
    } else {
        msg := tgbotapi.NewMessage(h.adminChatID, "Заблокированные пользователи:\n" + strings.Join(banList, "\n"))
        h.bot.Send(msg)
    }
}

// Пересылка сообщения администратору
func (h *BotHandler) forwardMessageToAdmin(update tgbotapi.Update, userID int64) {
    var msg tgbotapi.Chattable
    if update.Message.Document != nil {
        msg = tgbotapi.NewDocument(h.adminChatID, tgbotapi.FileID(update.Message.Document.FileID))
    } else if len(update.Message.Photo) > 0 {
        msg = tgbotapi.NewPhoto(h.adminChatID, tgbotapi.FileID(update.Message.Photo[0].FileID))
    } else if update.Message.Video != nil {
        msg = tgbotapi.NewVideo(h.adminChatID, tgbotapi.FileID(update.Message.Video.FileID))
    } else if update.Message.Audio != nil {
        msg = tgbotapi.NewAudio(h.adminChatID, tgbotapi.FileID(update.Message.Audio.FileID))
    } else {
        msg = tgbotapi.NewMessage(h.adminChatID, update.Message.Text)
    }

    if msg != nil {
        h.bot.Send(msg)
    }

    // Добавляем кнопки
    buttons := tgbotapi.NewInlineKeyboardMarkup(
        tgbotapi.NewInlineKeyboardButtonData("Блокировать", fmt.Sprintf("block:%d", userID)),
        tgbotapi.NewInlineKeyboardButtonData("Ответить", fmt.Sprintf("reply:%d", userID)),
        tgbotapi.NewInlineKeyboardButtonData("Удалить", fmt.Sprintf("delete:%d", userID)),
    )
    msgWithButtons := tgbotapi.NewMessage(h.adminChatID, fmt.Sprintf("Сообщение от пользователя %d", userID))
    msgWithButtons.ReplyMarkup = buttons

    h.bot.Send(msgWithButtons)
}

// Отправка сообщения пользователю от администратора
func (h *BotHandler) replyToUser(userID int64, message string) {
    msg := tgbotapi.NewMessage(userID, message)
    h.bot.Send(msg)
}

// Разблокировка пользователя по ID
func (h *BotHandler) handleUnban(message string) {
    userID, err := strconv.ParseInt(message, 10, 64)
    if err != nil {
        msg := tgbotapi.NewMessage(h.adminChatID, "Некорректный ID пользователя.")
        h.bot.Send(msg)
        return
    }
    h.unblockUser(userID)
    msg := tgbotapi.NewMessage(h.adminChatID, fmt.Sprintf("Пользователь %d разблокирован.", userID))
    h.bot.Send(msg)
    h.unbanMode = false
}
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх