427 lines
14 KiB
Go
427 lines
14 KiB
Go
package kicker
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"kickerbot/captchagen"
|
|
"kickerbot/db"
|
|
"log"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.nefrace.ru/nefrace/tongo"
|
|
"github.com/NicoNex/echotron/v3"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
)
|
|
|
|
func userJoined(b *bot, update *echotron.Update) error {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
store := tongo.NewStore[db.User](Client)
|
|
usr := update.Message.NewChatMembers[0]
|
|
message := update.Message
|
|
_, err := b.DeleteMessage(message.Chat.ID, message.ID)
|
|
if err != nil {
|
|
log.Printf("Can't delete message: %v", err)
|
|
}
|
|
user, err := store.GetOne(ctx, tongo.E("chat_id", update.ChatID()), tongo.E("user_id", usr.ID))
|
|
var captcha *captchagen.Captcha
|
|
if err != nil {
|
|
if errors.Is(err, mongo.ErrNoDocuments) {
|
|
captcha = captchagen.GenCaptcha()
|
|
user = &db.User{
|
|
Item: tongo.NewID(),
|
|
UserId: usr.ID,
|
|
Username: usr.Username,
|
|
FirstName: usr.FirstName,
|
|
LastName: usr.LastName,
|
|
IsJoined: false,
|
|
ChatId: message.Chat.ID,
|
|
JoinedMessage: message.ID,
|
|
CorrectAnswer: int8(captcha.CorrectAnswer),
|
|
DateJoined: time.Now(),
|
|
LastNotification: time.Now(),
|
|
}
|
|
} else {
|
|
log.Printf("Can't find user: %v", err)
|
|
}
|
|
}
|
|
if captcha == nil {
|
|
return nil
|
|
}
|
|
bytes, err := captcha.ToBytes()
|
|
if err != nil {
|
|
log.Printf("Error creating captcha bytes: %v", bytes)
|
|
b.SendMessage("Не могу создать капчу, @nefrace, проверь логи.", update.Message.Chat.ID, &echotron.MessageOptions{MessageThreadID: int64(update.Message.ThreadID)})
|
|
}
|
|
msg := fmt.Sprintf("Приветствую тебя, *%s*\\!\nДля подтверждения, что ты человек, выбери логотип движка, которому посвящен данный чат, и отправь его номер сюда\\.\n*_Я дам тебе десять минут на это\\._*", UserMention(usr))
|
|
options := echotron.PhotoOptions{
|
|
Caption: msg,
|
|
ParseMode: echotron.MarkdownV2,
|
|
}
|
|
if message.Chat.IsForum {
|
|
options.MessageThreadID = int(b.CaptchaTopic)
|
|
}
|
|
result, err := b.SendPhoto(echotron.NewInputFileBytes("logos.png", *bytes), message.Chat.ID, &options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
user.CaptchaMessage = result.Result.ID
|
|
store.InsertOne(ctx, user)
|
|
return nil
|
|
}
|
|
|
|
func userLeft(b *bot, update *echotron.Update) error {
|
|
message := update.Message
|
|
sender := message.From
|
|
store := tongo.NewStore[db.User](Client)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
if user, err := store.GetOne(ctx, tongo.E("user_id", sender.ID), tongo.E("chat_id", message.Chat.ID), tongo.E("is_joined", false)); err == nil { //d.GetUser(ctx, db.User{UserId: sender.ID, ChatId: message.Chat.ID}); err == nil {
|
|
store.DeleteByID(ctx, user.Id)
|
|
b.DeleteMessage(message.Chat.ID, message.ID)
|
|
b.DeleteMessage(message.Chat.ID, user.CaptchaMessage)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var muted = echotron.ChatPermissions{
|
|
CanSendMessages: false,
|
|
CanSendAudios: false,
|
|
CanSendDocuments: false,
|
|
CanSendPhotos: false,
|
|
CanSendVideos: false,
|
|
CanSendVideoNotes: false,
|
|
CanSendVoiceNotes: false,
|
|
CanSendPolls: false,
|
|
CanSendOtherMessages: false,
|
|
}
|
|
|
|
func muteUser(b *bot, update *echotron.Update) error {
|
|
message := update.Message
|
|
|
|
if message.ReplyToMessage == nil {
|
|
return nil
|
|
}
|
|
reply := message.ReplyToMessage
|
|
items := strings.SplitN(message.Text, " ", 3)
|
|
days, msg := 1, reply.Text
|
|
var err error
|
|
if len(items) > 1 {
|
|
days, err = strconv.Atoi(items[1])
|
|
if err != nil || days < 1 {
|
|
res, _ := b.SendMessage("Неверно указано количество дней", message.Chat.ID, &echotron.MessageOptions{ReplyToMessageID: message.ID})
|
|
go waitAndDelete(&b.API, res.Result, 10*time.Second)
|
|
return err
|
|
}
|
|
}
|
|
if len(items) > 2 {
|
|
msg = fmt.Sprintf("%s: \"%s\"", reply.From.FirstName, items[2])
|
|
}
|
|
store := tongo.NewStore[db.Mute](Client)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
until := time.Now().AddDate(0, 0, days)
|
|
_, err = b.RestrictChatMember(message.Chat.ID, reply.From.ID, muted, &echotron.RestrictOptions{UntilDate: int(until.Unix())})
|
|
if err != nil {
|
|
b.SendMessage(fmt.Sprintf("Не могу дать молчанку юзеру: %v", err), b.chatID, &echotron.MessageOptions{ReplyToMessageID: message.ID})
|
|
return err
|
|
}
|
|
b.SendMessage(
|
|
fmt.Sprintf("Пользователю *%s* выдана \"молчанка\" на %d %s\\.", UserMention(reply.From), days, pluralRu(days, "день", "дня", "дней")),
|
|
message.Chat.ID,
|
|
&echotron.MessageOptions{
|
|
ParseMode: echotron.MarkdownV2,
|
|
MessageThreadID: int64(message.ThreadID),
|
|
},
|
|
)
|
|
|
|
logstore := tongo.NewStore[db.LogChannel](Client)
|
|
logchat, _ := logstore.GetOne(ctx)
|
|
if logchat != nil {
|
|
msg := fmt.Sprintf("Пользователю %s выдана молчанка админом *%s* \\#muted\n\nПричина: %s\\.", MentionWithData(reply.From), UserMention(message.From), EscapeText(echotron.MarkdownV2, msg))
|
|
if _, err := b.SendMessage(
|
|
msg,
|
|
logchat.ChatId,
|
|
&echotron.MessageOptions{
|
|
ParseMode: echotron.MarkdownV2,
|
|
},
|
|
); err != nil {
|
|
log.Printf("Can't log muted message with reason: %v", err)
|
|
log.Println(msg)
|
|
}
|
|
b.ForwardMessage(logchat.ChatId, message.Chat.ID, reply.ID, &echotron.ForwardOptions{})
|
|
}
|
|
|
|
store.InsertOne(ctx, &db.Mute{
|
|
Item: tongo.NewID(),
|
|
UserId: reply.From.ID,
|
|
ChatId: message.Chat.ID,
|
|
Message: msg,
|
|
Date: time.Now(),
|
|
Until: until,
|
|
MessageLink: fmt.Sprintf("https://t.me/c/%d/%d/%d", transformChatID(update.ChatID()), message.ThreadID, message.ID),
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func banUser(b *bot, update *echotron.Update) error {
|
|
message := update.Message
|
|
|
|
if message.ReplyToMessage == nil {
|
|
return nil
|
|
}
|
|
reply := message.ReplyToMessage
|
|
items := strings.SplitN(message.Text, " ", 2)
|
|
reason := ""
|
|
if len(items) == 2 {
|
|
reason = items[1]
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
_, err := b.BanChatMember(message.Chat.ID, reply.From.ID, &echotron.BanOptions{})
|
|
if err != nil {
|
|
b.SendMessage(fmt.Sprintf("Не могу забанить юзера: %v", err), b.chatID, &echotron.MessageOptions{ReplyToMessageID: message.ID})
|
|
return err
|
|
}
|
|
opts := echotron.MessageOptions{
|
|
ParseMode: echotron.MarkdownV2,
|
|
}
|
|
|
|
if message.ThreadID != 0 {
|
|
opts.MessageThreadID = int64(message.ThreadID)
|
|
}
|
|
if _, err := b.SendMessage(
|
|
fmt.Sprintf("Пользователь %s забанен\\.", UserMention(reply.From)),
|
|
message.Chat.ID,
|
|
&opts,
|
|
); err != nil {
|
|
log.Printf("Can't send ban message: %v", err)
|
|
}
|
|
logstore := tongo.NewStore[db.LogChannel](Client)
|
|
logchat, _ := logstore.GetOne(ctx)
|
|
if logchat != nil {
|
|
msg := fmt.Sprintf("Пользователь %s забанен админом *%s* \\#banned\n\nПричина: %s\\.", MentionWithData(reply.From), UserMention(message.From), EscapeText(echotron.MarkdownV2, reason))
|
|
if _, err := b.SendMessage(
|
|
msg,
|
|
logchat.ChatId,
|
|
&echotron.MessageOptions{
|
|
ParseMode: echotron.MarkdownV2,
|
|
},
|
|
); err != nil {
|
|
log.Printf("Can't log banned message with reason: %v", err)
|
|
log.Println(msg)
|
|
}
|
|
b.ForwardMessage(logchat.ChatId, message.Chat.ID, reply.ID, &echotron.ForwardOptions{})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func userBanned(b *bot, update *echotron.Update) error {
|
|
m := update.ChatMember
|
|
c := m.Chat
|
|
u := m.NewChatMember.User
|
|
store := tongo.NewStore[db.User](Client)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
if user, err := store.GetOne(ctx, tongo.E("user_id", u.ID), tongo.E("chat_id", c.ID)); err == nil { //d.GetUser(ctx, db.User{UserId: sender.ID, ChatId: message.Chat.ID}); err == nil {
|
|
store.DeleteByID(ctx, user.Id)
|
|
}
|
|
logstore := tongo.NewStore[db.LogChannel](Client)
|
|
logchat, _ := logstore.GetOne(ctx)
|
|
if logchat != nil && m.From.ID != b.Me.ID {
|
|
b.SendMessage(
|
|
fmt.Sprintf("Пользователь %s забанен админом *%s* \\#banned\\.", MentionWithData(u), UserMention(&m.From)),
|
|
logchat.ChatId,
|
|
&echotron.MessageOptions{
|
|
ParseMode: echotron.MarkdownV2,
|
|
},
|
|
)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func checkCaptcha(b *bot, update *echotron.Update) error {
|
|
message := update.Message
|
|
sender := message.From
|
|
store := tongo.NewStore[db.User](Client)
|
|
chatStore := tongo.NewStore[db.Chat](Client)
|
|
// d := db.GetDatabase()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
chat, err := chatStore.GetOne(ctx, tongo.E("chat_id", message.Chat.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if user, err := store.GetOne(ctx,
|
|
tongo.E("user_id", sender.ID),
|
|
tongo.E("chat_id", message.Chat.ID),
|
|
tongo.E("is_joined", false),
|
|
); err == nil { //d.GetUser(ctx, db.User{UserId: sender.ID, ChatId: message.Chat.ID}); err == nil {
|
|
if message.Chat.IsForum {
|
|
if message.ThreadID != int(chat.TopicId) {
|
|
b.DeleteMessage(message.Chat.ID, message.ID)
|
|
text := fmt.Sprintf("*%s*, сначала пройди [капчу](https://t.me/c/%d/%d/%d)\\!", UserMention(sender), transformChatID(b.chatID), chat.TopicId, user.CaptchaMessage)
|
|
res, _ := b.SendMessage(text, message.Chat.ID, &echotron.MessageOptions{ParseMode: echotron.MarkdownV2, MessageThreadID: int64(message.ThreadID)})
|
|
go waitAndDelete(&b.API, res.Result, 10*time.Second)
|
|
return nil
|
|
}
|
|
}
|
|
text_runes := []rune(message.Text)
|
|
guess := string(text_runes[0])
|
|
solved := false
|
|
if num, err := strconv.Atoi(guess); err == nil {
|
|
if num == int(user.CorrectAnswer) {
|
|
user.IsJoined = true
|
|
store.ReplaceItem(ctx, *user, true)
|
|
solved = true
|
|
b.DeleteMessage(message.Chat.ID, message.ID)
|
|
b.DeleteMessage(message.Chat.ID, user.CaptchaMessage)
|
|
msg := fmt.Sprintf("Капча успешно пройдена пользователем *%s*", UserMention(sender))
|
|
timeout := 10 * time.Second
|
|
if chat.Greet != "" {
|
|
msg = fmt.Sprintf(chat.Greet, UserMention(sender))
|
|
timeout = 2 * time.Minute
|
|
}
|
|
options := echotron.MessageOptions{
|
|
ParseMode: echotron.MarkdownV2,
|
|
}
|
|
if message.Chat.IsForum {
|
|
options.MessageThreadID = b.CaptchaTopic
|
|
}
|
|
res, err := b.SendMessage(msg, message.Chat.ID, &options)
|
|
if err != nil {
|
|
log.Printf("Can't send welcome message: %s", err)
|
|
}
|
|
go waitAndDelete(&b.API, res.Result, timeout)
|
|
// time.Sleep(time.Second * 10)
|
|
// _, err = b.DeleteMessage(message.Chat.ID, res.Result.ID)
|
|
if err != nil {
|
|
log.Printf("Can't delete welcome message: %s", err)
|
|
}
|
|
}
|
|
}
|
|
if !solved {
|
|
logstore := tongo.NewStore[db.LogChannel](Client)
|
|
|
|
b.DeleteMessage(message.Chat.ID, message.ID)
|
|
b.DeleteMessage(message.Chat.ID, user.CaptchaMessage)
|
|
b.DeleteMessage(message.Chat.ID, user.JoinedMessage)
|
|
b.BanChatMember(message.Chat.ID, sender.ID, nil)
|
|
if logchat, _ := logstore.GetOne(ctx); logchat != nil {
|
|
b.SendMessage(fmt.Sprintf("Пользователь %s провалил капчу \\#banned \\#captcha", MentionWithData(sender)), logchat.ChatId, &echotron.MessageOptions{ParseMode: echotron.MarkdownV2})
|
|
}
|
|
store.DeleteByID(ctx, user.Id)
|
|
}
|
|
} else if message.Chat.IsForum && message.ThreadID == int(chat.TopicId) {
|
|
res, err := b.GetChatMember(update.ChatID(), sender.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res.Result.Status == "administrator" || res.Result.Status == "creator" {
|
|
return nil
|
|
}
|
|
b.DeleteMessage(b.chatID, message.ID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setAdminTopic(b *bot, update *echotron.Update, set bool) error {
|
|
message := update.Message
|
|
chatID := update.ChatID()
|
|
store := tongo.NewStore[db.AdminTopic](Client)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
topic, err := store.GetOne(ctx, tongo.E("chat_id", chatID), tongo.E("topic_id", message.ThreadID))
|
|
if set {
|
|
if err != nil || topic == nil {
|
|
_, err := store.InsertOne(ctx, &db.AdminTopic{
|
|
Item: tongo.NewID(),
|
|
ChatId: chatID,
|
|
TopicId: int64(message.ThreadID),
|
|
})
|
|
if err != nil {
|
|
log.Println("Can't set admintopic: ", err)
|
|
return err
|
|
}
|
|
b.SendMessage("Данный топик теперь только для админов.", chatID, &echotron.MessageOptions{MessageThreadID: int64(message.ThreadID)})
|
|
}
|
|
return nil
|
|
} else {
|
|
if err == nil {
|
|
if err := store.DeleteByID(ctx, topic.Id); err != nil {
|
|
log.Println("Can't unset admintopic: ", err)
|
|
return err
|
|
}
|
|
b.SendMessage("Данный топик теперь доступен всем!", chatID, &echotron.MessageOptions{MessageThreadID: int64(message.ThreadID)})
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func checkAdminTopics(b *bot, update *echotron.Update) error {
|
|
message := update.Message
|
|
chatID := update.ChatID()
|
|
sender := message.From
|
|
res, err := b.GetChatMember(message.Chat.ID, sender.ID)
|
|
if err != nil {
|
|
log.Println("muteUser: Can't get member: ", err)
|
|
return err
|
|
}
|
|
if res.Result.Status == "administrator" || res.Result.Status == "creator" {
|
|
return nil
|
|
}
|
|
store := tongo.NewStore[db.AdminTopic](Client)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
if _, err := store.GetOne(ctx, tongo.E("chat_id", chatID), tongo.E("topic_id", message.ThreadID)); err == nil {
|
|
b.DeleteMessage(chatID, message.ID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func botAdded(b *bot, update *echotron.Update) error {
|
|
m := update.Message
|
|
store := tongo.NewStore[db.Chat](Client)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
chat, err := store.GetOne(ctx, tongo.E("chat_id", m.Chat.ID))
|
|
if err != nil {
|
|
chat = &db.Chat{
|
|
Item: tongo.NewID(),
|
|
ChatId: m.Chat.ID,
|
|
Title: m.Chat.Title,
|
|
TopicId: 0,
|
|
}
|
|
}
|
|
|
|
_, err = store.InsertOne(ctx, chat)
|
|
if err != nil {
|
|
log.Print(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setTopic(b *bot, update *echotron.Update) error {
|
|
m := update.Message
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
store := tongo.NewStore[db.Chat](Client)
|
|
chat, err := store.GetOne(ctx, tongo.E("chat_id", m.Chat.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
chat.TopicId = int64(m.ThreadID)
|
|
// upd := bson.D{{Key: "$set", Value: bson.D{{Key: "topic_id", Value: m.ThreadID}}}}
|
|
b.CaptchaTopic = int64(m.ThreadID)
|
|
err = store.ReplaceItem(ctx, *chat, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.DeleteMessage(m.Chat.ID, m.ID)
|
|
b.SendMessage("Данный топик выбран в качестве проверочного для пользователей", m.Chat.ID, &echotron.MessageOptions{MessageThreadID: int64(m.ThreadID)})
|
|
return nil
|
|
}
|