diff --git a/src/botutils.go b/src/botutils.go index e4168d8..129f585 100644 --- a/src/botutils.go +++ b/src/botutils.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "time" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" @@ -38,3 +39,7 @@ func FetchMemberFromChat(ctx context.Context, b *bot.Bot, chatID int64, userID i func IsAdmin(member models.ChatMember) bool { return member.Administrator != nil || member.Owner != nil } + +func DeleteAfterSeconds(chatID int64, msgID int, seconds int) error { + return AddMessageToDelete(MessageToDelete{MessageId: msgID, ChatId: chatID, DeleteDate: time.Now().Add(time.Duration(seconds) * time.Second).Unix(), Tries: 0}) +} diff --git a/src/db.go b/src/db.go index 6767ebf..b0885a0 100644 --- a/src/db.go +++ b/src/db.go @@ -27,7 +27,8 @@ create table if not exists messagesToDelete id INTEGER PRIMARY KEY AUTOINCREMENT, message_id INTEGER, chat_id INTEGER, -delete_date INTEGER +delete_date INTEGER, +tries INTEGER ); create table if not exists users @@ -71,6 +72,7 @@ type MessageToDelete struct { MessageId int `db:"message_id"` ChatId int64 `db:"chat_id"` DeleteDate int64 `db:"delete_date"` + Tries int `db:"tries"` } type User struct { @@ -79,6 +81,14 @@ type User struct { Username string `db:"username"` } +type Captcha struct { + Id int64 `db:"id"` + UserID int64 `db:"user_id"` + ChatID int64 `db:"chat_id"` + MessageID int `db:"message_id"` + CorrectAnswer int `db:"correct_answer"` +} + var db *sqlx.DB func InitDb() error { @@ -127,7 +137,7 @@ func NewActivation(code string) error { func UseActivation(code string) bool { exists := false - err := db.Get(&exists, `SELECT exists(SELECT 1 FROM chats WHERE code = $1);`, code) + err := db.Get(&exists, `SELECT exists(SELECT 1 FROM activations WHERE code = $1);`, code) if err != nil || !exists { return false } @@ -141,7 +151,7 @@ func ActivateChat(id int64) error { } func AddMessageToDelete(msg MessageToDelete) error { - _, err := db.NamedExec(`insert into messagesToDelete (message_id, chat_id, delete_date) values (:message_id, :chat_id, :delete_date)`, msg) + _, err := db.NamedExec(`insert into messagesToDelete (message_id, chat_id, delete_date, tries) values (:message_id, :chat_id, :delete_date, 0)`, msg) return err } diff --git a/src/handlers.go b/src/handlers.go index 5620c43..33f798f 100644 --- a/src/handlers.go +++ b/src/handlers.go @@ -2,9 +2,12 @@ package main import ( "context" + "database/sql" + "errors" + "fmt" "log" + "strconv" "strings" - "time" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" @@ -15,6 +18,9 @@ func defaultHandler(ctx context.Context, b *bot.Bot, update *models.Update) { // ChatID: update.Message.Chat.ID, // Text: "hello!", // }) + if update.Message != nil { + log.Println(update.Message.Text) + } log.Println(*update) } @@ -33,7 +39,7 @@ func registerChat(ctx context.Context, b *bot.Bot, update *models.Update) { return } if !UseActivation(args[1]) { - log.Println("register: wrong code") + log.Println("register: wrong code: ", args[1]) return } if err := ActivateChat(msg.Chat.ID); err != nil { @@ -43,7 +49,7 @@ func registerChat(ctx context.Context, b *bot.Bot, update *models.Update) { 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 := AddMessageToDelete(MessageToDelete{MessageId: sent.ID, ChatId: msg.Chat.ID, DeleteDate: time.Now().Add(1 * time.Minute).Unix()}) + err := DeleteAfterSeconds(msg.Chat.ID, sent.ID, 60) if err != nil { log.Println("register: failed to add to delete", err) } @@ -55,10 +61,79 @@ func registerChat(ctx context.Context, b *bot.Bot, update *models.Update) { func handleNewJoined(ctx context.Context, b *bot.Bot, u *models.Update) { for _, user := range u.Message.NewChatMembers { - log.Println(user) + _, err := db.Exec(`INSERT INTO captchas (user_id, chat_id, message_id, correct_answer) values ($1, $2, 0, 0)`, user.ID, u.Message.Chat.ID) + if err != nil { + log.Println("newusers: can't add to db: ", err) + } + b.SendMessage(ctx, &bot.SendMessageParams{ + ChatID: u.Message.Chat.ID, + Text: "Check the capthca!", + 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"}, + }, + }, + }, + }) } } func banUser(ctx context.Context, b *bot.Bot, u *models.Update) { } + +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: " There's no captchas for that chat you came from.", + ChatID: u.Message.Chat.ID, + }) + return + } + } else { + err = db.Get(&captcha, `select * from captchas where user_id = $1 and correct_answer != 0`, userID) + if err != nil { + b.SendMessage(ctx, &bot.SendMessageParams{ + Text: " There's no captchas for that chat you came from.", + ChatID: u.Message.Chat.ID, + }) + return + } + } + + if captcha.CorrectAnswer == 0 { + captcha.CorrectAnswer = 42 + msg, err := b.SendMessage(ctx, &bot.SendMessageParams{ + Text: "Get me the answer!", + ChatID: u.Message.Chat.ID, + }) + if err == nil { + captcha.MessageID = msg.ID + } + _, err = db.NamedExec("update captchas set correct_answer = :correct_answer, message_id = :message_id where id = :id", captcha) + if err != nil { + log.Println("Can't update captcha:", err) + } + } else { + b.SendMessage(ctx, &bot.SendMessageParams{ + Text: fmt.Sprintf("You already have captcha for chat %d", captcha.ChatID), + ChatID: u.Message.Chat.ID, + }) + } +} diff --git a/src/main.go b/src/main.go index cc00375..126ac83 100644 --- a/src/main.go +++ b/src/main.go @@ -2,8 +2,11 @@ package main import ( "context" + "log" "os" "os/signal" + "strings" + "time" _ "github.com/glebarez/go-sqlite" "github.com/go-telegram/bot" @@ -36,5 +39,45 @@ func main() { b.RegisterHandlerMatchFunc(func(update *models.Update) bool { return update.Message != nil && len(update.Message.NewChatMembers) > 0 }, handleNewJoined) + b.RegisterHandlerMatchFunc(func(update *models.Update) bool { + return update.Message != nil && update.Message.Chat.Type == "private" && strings.HasPrefix(update.Message.Text, "/start") + }, handlePrivateStartCaptcha) + + go timedTask(ctx, b) + b.Start(ctx) } + +func timedTask(ctx context.Context, b *bot.Bot) { + timer := time.NewTicker(time.Second * 30) + +task: + for { + select { + case <-timer.C: + deleteOldMessages(ctx, b) + case <-ctx.Done(): + break task + } + } +} + +func deleteOldMessages(ctx context.Context, b *bot.Bot) { + now := time.Now().Unix() + messages := []MessageToDelete{} + err := db.Select(&messages, `SELECT * from messagesToDelete WHERE delete_date < $1`, now) + if err != nil { + log.Println("delete_old: can't get messages: ", err) + } + for _, message := range messages { + success, err := b.DeleteMessage(ctx, &bot.DeleteMessageParams{ChatID: message.ChatId, MessageID: message.MessageId}) + if !success { + log.Println("delete_old, message wasn't deleted: ", message.MessageId, " :: ", err) + db.Exec(`UPDATE messagesToDelete set tries = tries + 1 where id = $1`, message.Id) + if message.Tries < 3 { + continue + } + } + db.Exec(`DELETE FROM messagesToDelete WHERE id = $1`, message.Id) + } +} diff --git a/src/middleware.go b/src/middleware.go index b39c441..1685669 100644 --- a/src/middleware.go +++ b/src/middleware.go @@ -17,6 +17,7 @@ func checkRegistered(next bot.HandlerFunc) bot.HandlerFunc { } chat := update.Message.Chat if chat.Type == "private" { + next(ctx, b, update) return } if !IsChatActive(chat.ID) && !strings.HasPrefix(update.Message.Text, "/register") {