396 lines
12 KiB
Go
396 lines
12 KiB
Go
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,
|
|
})
|
|
}
|