package main import ( "bytes" "context" "database/sql" "errors" "fmt" "log" "strconv" "strings" "time" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" ) func defaultHandler(ctx context.Context, b *bot.Bot, update *models.Update) { // b.SendMessage(ctx, &bot.SendMessageParams{ // ChatID: update.Message.Chat.ID, // Text: "hello!", // }) if update.Message != nil { log.Println(update.Message.Text) } log.Println(*update) } func registerChat(ctx context.Context, b *bot.Bot, update *models.Update) { msg := update.Message log.Println("registering", msg.Chat.ID) m, err := FetchMemberFromChat(ctx, b, msg.Chat.ID, msg.From.ID) if err == nil { if !IsMemberAdmin(*m) { log.Println("register: user is not admin") return } args := strings.Split(msg.Text, " ") if len(args) == 1 { log.Println("register: there's no code") return } if !UseActivation(args[1]) { log.Println("register: wrong code: ", args[1]) return } if err := ActivateChat(msg.Chat.ID, msg.MessageThreadID); err != nil { log.Println("Error activating chat: ", err) return } b.DeleteMessage(ctx, &bot.DeleteMessageParams{ ChatID: msg.Chat.ID, MessageID: msg.ID, }) sent, err := b.SendMessage(ctx, &bot.SendMessageParams{ ChatID: msg.Chat.ID, Text: "Чат зарегистрирован", MessageThreadID: msg.MessageThreadID, }) if err == nil { err := DeleteAfterSeconds(msg.Chat.ID, sent.ID, 60) if err != nil { log.Println("register: failed to add to delete", err) } } } else { log.Println("register: error", err) } } func unregisterChat(ctx context.Context, b *bot.Bot, update *models.Update) { msg := update.Message log.Println("unregistering", msg.Chat.ID) m, err := FetchMemberFromChat(ctx, b, msg.Chat.ID, msg.From.ID) if err == nil { if !IsMemberAdmin(*m) { log.Println("register: user is not admin") return } b.DeleteMessage(ctx, &bot.DeleteMessageParams{ ChatID: msg.Chat.ID, MessageID: msg.ID, }) db.Exec("update chats set active = 0 where id = $1", msg.Chat.ID) sent, err := b.SendMessage(ctx, &bot.SendMessageParams{ ChatID: msg.Chat.ID, Text: "Чат удалён", MessageThreadID: msg.MessageThreadID, }) if err == nil { err := DeleteAfterSeconds(msg.Chat.ID, sent.ID, 60) if err != nil { log.Println("register: failed to add to delete", err) } } } else { log.Println("register: error", err) } } var NewUserTemplate = ` Приветствую тебя, *%s*\! Ты не можешь писать ничего в данном чате, пока не пройдешь капчу, которую я тебе пришлю в личку\. Нужно только нажать на кнопку ниже\. ` func handleNewJoined(ctx context.Context, b *bot.Bot, u *models.Update) { var chat Chat err := db.Get(&chat, "select * from chats where id = $1 and active = 1", u.Message.Chat.ID) if err != nil { log.Println("can't get chat for new joined: ", err) } for _, user := range u.Message.NewChatMembers { text := fmt.Sprintf(NewUserTemplate, Mention(user.FirstName, user.ID)) msg, err := b.SendMessage(ctx, &bot.SendMessageParams{ ChatID: chat.Id, MessageThreadID: int(chat.Topic), Text: text, ParseMode: models.ParseModeMarkdown, ReplyMarkup: models.InlineKeyboardMarkup{ InlineKeyboard: [][]models.InlineKeyboardButton{ { {URL: fmt.Sprintf("https://t.me/nefrace_php_test_bot?start=cap_%d", u.Message.Chat.ID), Text: "Check"}, }, }, }, }) if err != nil { log.Println("Can't send message: ", err, "\n", text) } _, err = db.Exec(`INSERT INTO captchas (user_id, chat_id, message_id) values ($1, $2, $3)`, user.ID, u.Message.Chat.ID, msg.ID) if err != nil { log.Println("newusers: can't add to db: ", err) return } _, err = b.RestrictChatMember(ctx, &bot.RestrictChatMemberParams{ ChatID: u.Message.Chat.ID, UserID: user.ID, Permissions: &models.ChatPermissions{ CanSendMessages: false, CanSendAudios: false, CanSendDocuments: false, CanSendPhotos: false, CanSendVideos: false, CanSendVideoNotes: false, CanSendVoiceNotes: false, CanSendPolls: false, CanSendOtherMessages: false, CanAddWebPagePreviews: false, CanChangeInfo: false, CanInviteUsers: false, CanPinMessages: false, CanManageTopics: false, }, }) if err != nil { log.Println("Can't restrict new user: ", err) } } } func banUser(ctx context.Context, b *bot.Bot, u *models.Update) { msg := u.Message if msg.ReplyToMessage == nil { newMsg, err := b.SendMessage(ctx, &bot.SendMessageParams{ Text: "Хочешь себя забанить? 🙃", ReplyParameters: &models.ReplyParameters{ ChatID: msg.Chat.ID, MessageID: msg.ID, }, }) if err == nil { AddMessageToDelete(MessageToDelete{MessageId: msg.ID, ChatId: msg.Chat.ID, DeleteDate: time.Now().Add(10 * time.Second).Unix()}) AddMessageToDelete(MessageToDelete{MessageId: newMsg.ID, ChatId: msg.Chat.ID, DeleteDate: time.Now().Add(10 * time.Second).Unix()}) } return } reply := msg.ReplyToMessage chatID := msg.Chat.ID sender := msg.From banned := reply.From log.Println("banning user", banned.FirstName, "from", msg.Chat.ID) m, err := FetchMemberFromChat(ctx, b, chatID, sender.ID) if err == nil { if !IsMemberAdmin(*m) { log.Println("register: user is not admin") return } text := reply.Text if text == "" { text = reply.Caption } reason := "" days := 0 args := strings.SplitN(msg.Text, " ", 2) if len(args) > 1 { num, err := strconv.Atoi(args[1]) if err != nil { reason = args[1] } else { if days > 0 { days = num } if len(args) > 2 { reason = args[2] } } } unbanDate := time.Now().Add(time.Duration(days) * time.Hour * 24).Unix() b.DeleteMessage(ctx, &bot.DeleteMessageParams{ ChatID: msg.Chat.ID, MessageID: msg.ID, }) _, err := b.BanChatMember(ctx, &bot.BanChatMemberParams{ ChatID: chatID, UserID: banned.ID, UntilDate: int(unbanDate), }) if err != nil { log.Println("can't ban user: ", err) return } newText := "Пользователь *%s* был забанен %s\\." daysText := "навсегда" if days > 0 { daysText = fmt.Sprintf("на %d %s", days, pluralRu(days, "день", "дня", "дней")) } sent, err := b.SendMessage(ctx, &bot.SendMessageParams{ ChatID: msg.Chat.ID, Text: fmt.Sprintf(newText, Mention(banned.FirstName, banned.ID), daysText), MessageThreadID: msg.MessageThreadID, }) db.Exec( "insert into bans (chat_id, user_id, text, reason, ban_date, unban_date) values ($1, $2, $3, $4, $5, $6)", chatID, banned.ID, text, reason, time.Now().Unix(), unbanDate, ) if err == nil { err := DeleteAfterSeconds(msg.Chat.ID, sent.ID, 60) if err != nil { log.Println("register: failed to add to delete", err) } } } else { log.Println("register: error", err) } } var NewCaptchaTemplate = ` *%s*, тебе необходимо пройти капчу для чата *%s*\. Для этого посмотри на картинку, найди логотип движка, который относится к вышеуказанному чату, а потом введи сюда код, который расположен над или под ним\. Время у тебя неограничено, я буду ждать\! ` func handlePrivateStartCaptcha(ctx context.Context, b *bot.Bot, u *models.Update) { args := strings.Split(u.Message.Text, " ") userID := u.Message.From.ID chatID := 0 if len(args) > 1 { chat_str := strings.TrimPrefix(args[1], "cap_") id, err := strconv.Atoi(chat_str) if err == nil { chatID = id } } captcha := Captcha{} var err error if chatID != 0 { err = db.Get(&captcha, `select * from captchas where user_id = $1 and chat_id = $2`, userID, chatID) if errors.Is(err, sql.ErrNoRows) { b.SendMessage(ctx, &bot.SendMessageParams{ Text: "В чате, откуда ты пришёл, у тебя нет активных капч. Приходи в другой раз.", ChatID: u.Message.Chat.ID, }) return } } else { err = db.Get(&captcha, `select * from captchas where user_id = $1 and correct_answer != ''`, userID) if err != nil { b.SendMessage(ctx, &bot.SendMessageParams{ Text: "У тебя нет активных капч ни в одном чате. Приходи в другой раз.", ChatID: u.Message.Chat.ID, }) return } } type UserChatCaptcha struct { Id int64 `db:"id"` UserID int64 `db:"user_id"` UserName string `db:"user_name"` ChatID int64 `db:"chat_id"` ChatName string `db:"chat_name"` } var userchat UserChatCaptcha err = db.Get(&userchat, ` SELECT U.id AS user_id, C.id as chat_id, U.name as user_name, C.name as chat_name FROM captchas JOIN users AS U ON U.id = captchas.user_id JOIN chats AS C ON C.id = captchas.chat_id WHERE captchas.id = $1`, captcha.Id) if err != nil { log.Println("Can't get user and chat names: ", err) } if captcha.CorrectAnswer == "" { img, answer := GenCaptcha() captcha.CorrectAnswer = answer if _, err := b.SendPhoto(ctx, &bot.SendPhotoParams{ Caption: fmt.Sprintf(NewCaptchaTemplate, userchat.UserName, userchat.ChatName), Photo: &models.InputFileUpload{Filename: "captcha.png", Data: bytes.NewReader(img)}, ChatID: u.Message.Chat.ID, ParseMode: models.ParseModeMarkdown, }); err != nil { log.Println("can't send private captcha: ", err) } _, err = db.NamedExec("update captchas set correct_answer = :correct_answer where id = :id", captcha) if err != nil { log.Println("Can't update captcha:", err) } } else { b.SendMessage(ctx, &bot.SendMessageParams{ Text: fmt.Sprintf("Я тебе уже выдавал капчу для %d", captcha.ChatID), ChatID: u.Message.Chat.ID, }) } } func handlePrivateCaptcha(ctx context.Context, b *bot.Bot, u *models.Update) { msg := u.Message captcha := Captcha{} err := db.Get(&captcha, "select * from captchas where user_id = $1 and correct_answer != 0", msg.From.ID) if err != nil { log.Println("Can't solve user captcha: ", err) return } now := time.Now().Unix() if captcha.BlockedUntil > now { log.Println("User needs to try again next time: ", msg.From.ID, msg.From.Username, msg.From.FirstName) return } ban_minutes := 0 text := "" if msg.Text != captcha.CorrectAnswer { text = "That's the wrong answer. Try again in 1 hour." ban_minutes = 60 } if ban_minutes > 0 { b.SendMessage(ctx, &bot.SendMessageParams{ChatID: msg.From.ID, Text: text}) _, err := db.Exec("update captchas set blocked_until = $2 where id = $1", captcha.Id, time.Now().Add(time.Minute*time.Duration(ban_minutes)).Unix()) if err != nil { log.Println("Can't block user from captcha: ", err) } return } _, err = b.RestrictChatMember(ctx, &bot.RestrictChatMemberParams{ChatID: captcha.ChatID, UserID: captcha.UserID, Permissions: &models.ChatPermissions{ CanSendMessages: true, CanSendAudios: true, CanSendDocuments: true, CanSendPhotos: true, CanSendVideos: true, CanSendVideoNotes: true, CanSendVoiceNotes: true, CanSendPolls: true, CanSendOtherMessages: true, CanAddWebPagePreviews: true, CanChangeInfo: true, CanInviteUsers: true, CanPinMessages: true, CanManageTopics: true, }}) if err != nil { log.Println("Can't unrestrict user: ", err) } log.Println("Deleting message: ", captcha.ChatID, captcha.MessageID) result, err := b.DeleteMessage(ctx, &bot.DeleteMessageParams{ ChatID: captcha.ChatID, MessageID: captcha.MessageID, }) log.Println("Deleting message:", result, err) db.Exec("delete from captchas where id = $1", captcha.Id) b.SendMessage(ctx, &bot.SendMessageParams{ Text: "Капча решена! Поздравляю! Теперь можешь вернуться в чат, я вернул тебе возможность отправлять там сообщения.\n\nСоветую ознакомиться с местными правилами, прежде чем что-либо писать!", ChatID: msg.From.ID, }) }