package main import ( "context" "fmt" "log" "os" "os/signal" "strings" _ "github.com/glebarez/go-sqlite" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" "github.com/jmoiron/sqlx" ) var BUILD_TIME string var db *sqlx.DB type Godette struct { *bot.Bot ctx context.Context update *models.Update } func MakeHandler(handler func(g Godette)) func(ctx context.Context, b *bot.Bot, update *models.Update) { return func(ctx context.Context, b *bot.Bot, update *models.Update) { if update.Message.Caption != "" && update.Message.Text == "" { update.Message.Text = update.Message.Caption } handler(Godette{b, ctx, update}) } } func (g *Godette) ReplyWithText(text string) (*models.Message, error) { return g.Bot.SendMessage(g.ctx, &bot.SendMessageParams{ Text: text, ChatID: g.update.Message.Chat.ID, MessageThreadID: g.update.Message.MessageThreadID, ReplyParameters: &models.ReplyParameters{ ChatID: g.update.Message.Chat.ID, MessageID: g.update.Message.ID, }, }) } func (g *Godette) AnswerWithMarkdown(text string) (*models.Message, error) { return g.Bot.SendMessage(g.ctx, &bot.SendMessageParams{ Text: text, ChatID: g.update.Message.Chat.ID, MessageThreadID: g.update.Message.MessageThreadID, ParseMode: models.ParseModeMarkdown, }) } func (g *Godette) ReplyWithMarkdown(text string) (*models.Message, error) { return g.Bot.SendMessage(g.ctx, &bot.SendMessageParams{ Text: text, ChatID: g.update.Message.Chat.ID, MessageThreadID: g.update.Message.MessageThreadID, ParseMode: models.ParseModeMarkdown, ReplyParameters: &models.ReplyParameters{ ChatID: g.update.Message.Chat.ID, MessageID: g.update.Message.ID, }, }) } func main() { token := os.Getenv("TOKEN") if token == "" { panic("No token was provided") } ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() if err := InitDb(); err != nil { log.Fatalln(err) } opts := []bot.Option{ bot.WithDefaultHandler(defHandler), bot.WithMiddlewares(writeUsersToDB), bot.WithAllowedUpdates(bot.AllowedUpdates{ "message", "callback_query", "message_reaction", }), } b, _ := bot.New(token, opts...) b.RegisterHandler(bot.HandlerTypeMessageText, "/me ", bot.MatchTypePrefix, HandleMe) b.RegisterHandler(bot.HandlerTypeMessageText, "/help", bot.MatchTypePrefix, MakeHandler(HandleHelp)) b.RegisterHandler(bot.HandlerTypeMessageText, "/docs ", bot.MatchTypePrefix, MakeHandler(HandleDocRequest)) b.RegisterHandler(bot.HandlerTypeMessageText, "/docs_ru ", bot.MatchTypePrefix, MakeHandler(HandleDocRequestRu)) b.RegisterHandler(bot.HandlerTypeMessageText, "/top", bot.MatchTypePrefix, MakeHandler(HandleUsersTop)) b.RegisterHandler(bot.HandlerTypeMessageText, "/bottom", bot.MatchTypePrefix, MakeHandler(HandleUsersBottom)) b.RegisterHandler(bot.HandlerTypeMessageText, "/stats", bot.MatchTypePrefix, MakeHandler(HandleStats)) b.RegisterHandler(bot.HandlerTypeMessageText, "+", bot.MatchTypePrefix, KarmaGoUp) b.RegisterHandler(bot.HandlerTypeMessageText, "Спасибо", bot.MatchTypePrefix, KarmaGoUp) b.RegisterHandler(bot.HandlerTypeMessageText, "спасибо", bot.MatchTypePrefix, KarmaGoUp) b.RegisterHandler(bot.HandlerTypeMessageText, "СПАСИБО", bot.MatchTypePrefix, KarmaGoUp) b.RegisterHandler(bot.HandlerTypeMessageText, "-", bot.MatchTypePrefix, KarmaGoDown) b.RegisterHandlerMatchFunc(func(update *models.Update) bool { return update.MessageReaction != nil }, HandleReactions) b.SetMyCommands(context.Background(), &bot.SetMyCommandsParams{ Commands: commands, Scope: &models.BotCommandScopeDefault{}, }) b.Start(ctx) } func InitDb() error { newdb, err := sqlx.Connect("sqlite", "./bot.db?_time_format=sqlite") if err != nil { return err } db = newdb return nil } func defHandler(ctx context.Context, b *bot.Bot, update *models.Update) { } func HandleMe(ctx context.Context, b *bot.Bot, update *models.Update) { g := Godette{b, ctx, update} g.AnswerWithMarkdown(fmt.Sprintf( "_*%s* %s_", bot.EscapeMarkdown(update.Message.From.FirstName), bot.EscapeMarkdown(strings.TrimPrefix(update.Message.Text, "/me ")), )) b.DeleteMessage(ctx, &bot.DeleteMessageParams{ ChatID: update.Message.Chat.ID, MessageID: update.Message.ID, }) } var commands = []models.BotCommand{ {Command: "/help", Description: "Показать данное сообщение"}, {Command: "/me", Description: "Написать своё сообщение от третьего лица"}, {Command: "/top", Description: "Вывод ТОП-10 пользователей"}, {Command: "/bottom", Description: "Отрицательный ТОП-10"}, {Command: "/stats", Description: "Информация о пользователе"}, {Command: "/docs", Description: "Поиск по документации"}, {Command: "/docs_ru", Description: "Поиск по русскоязычной документации"}, } func HandleHelp(g Godette) { commands_text := "" for _, command := range commands { commands_text += fmt.Sprintf("`%s` \\- %s\n", bot.EscapeMarkdown(command.Command), bot.EscapeMarkdown(command.Description)) } log.Println(g.ReplyWithMarkdown(fmt.Sprintf( ` Мои команды: %s Дата сборки бота: %s `, commands_text, bot.EscapeMarkdown(BUILD_TIME), ))) } func GetRandomTemplateByTag(tag string) (string, error) { var msg string err := db.Get( &msg, `SELECT text FROM message_templates WHERE tag=$1 ORDER BY RANDOM() LIMIT 1;`, tag, ) return msg, err } func writeUsersToDB(next bot.HandlerFunc) bot.HandlerFunc { return func(ctx context.Context, bot *bot.Bot, update *models.Update) { if update.Message != nil { user := update.Message.From chat := update.Message.Chat _, err := db.Exec( ` INSERT INTO users(id, name, username) VALUES($1, $2, $3) ON CONFLICT(id) DO UPDATE SET name=$2, username=$3, message_count=message_count+1; INSERT INTO chats(id, name, username) VALUES($4, $5, $6) ON CONFLICT(id) DO UPDATE SET name=$5, username=$6; `, user.ID, strings.TrimSpace(fmt.Sprintf("%s %s", user.FirstName, user.LastName)), user.Username, chat.ID, chat.FirstName, chat.Username, ) if err != nil { log.Println(err) } } next(ctx, bot, update) } }