Compare commits
	
		
			11 Commits
		
	
	
		
			tongo
			...
			70385fd500
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 70385fd500 | |||
| 15d5321704 | |||
| d3e1c99442 | |||
| a0e8b8d190 | |||
| e0972d8a2a | |||
| c6abbbef1d | |||
| 4afbc2564b | |||
| a3e12f3c45 | |||
| 82f49079ab | |||
| 09d7496c93 | |||
| 833a23ba77 | 
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@ -2,6 +2,13 @@
 | 
			
		||||
 | 
			
		||||
Бот, генерирующий капчу в виде картинки с набором логотипов игровых движков. Проверяемому необходимо выбрать правильный и написать ответ цифрой. Если ответ неверный: бот банит пользователя.
 | 
			
		||||
 | 
			
		||||
## Основные команды админа
 | 
			
		||||
`/settopic` - устанавливает выбранный топик в качестве "полигона" для капчи. Все сообщения с капчей пойдут туда, все сообщения пользователей, не связанные с капчей, будут удаляться.
 | 
			
		||||
 | 
			
		||||
`/admin` - устанавливает выбранный топик как "админский" и запрещает другим пользователям туда писать, удаляя все их сообщения. Отменяет данное действие команда `/unadmin`.
 | 
			
		||||
 | 
			
		||||
`/mute [дни=1] [сообщение]` - даёт пользователю, на чьё сообщение был ответ, молчанку. По-умолчанию один день, а в качестве сообщения указывается текст оригинала. Информация о молчанке сохраняется в базе до момента её окончания, но пока нет никакого способа посмотреть на неё, помимо прямого доступа к базе.
 | 
			
		||||
 | 
			
		||||
## Модули
 | 
			
		||||
 | 
			
		||||
### Kicker
 | 
			
		||||
@ -29,10 +36,6 @@ MONGO_URI=mongodb://mongo:27017
 | 
			
		||||
```
 | 
			
		||||
MONGO_INITDB_ROOT_USERNAME=<логин для базы>
 | 
			
		||||
MONGO_INITDB_ROOT_PASSWORD=<пароль для базы>
 | 
			
		||||
 | 
			
		||||
ME_CONFIG_MONGODB_ADMINUSERNAME=<логин для базы>
 | 
			
		||||
ME_CONFIG_MONGODB_ADMINPASSWORD=<пароль для базы>
 | 
			
		||||
ME_CONFIG_MONGODB_URL=mongodb://<логин>:<пароль>@mongo:27017/
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Затем запустить команду `docker-compose up -d --build`, чтобы собрать образ бота и запустить контейнеры в стэке.
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,14 @@ type Chat struct {
 | 
			
		||||
 | 
			
		||||
func (Chat) Coll() string { return "chats" }
 | 
			
		||||
 | 
			
		||||
type AdminTopic struct {
 | 
			
		||||
	tongo.Item `bson:",inline"`
 | 
			
		||||
	ChatId     int64 `bson:"chat_id"`
 | 
			
		||||
	TopicId    int64 `bson:"topic_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (AdminTopic) Coll() string { return "admin_topics" }
 | 
			
		||||
 | 
			
		||||
type User struct {
 | 
			
		||||
	tongo.Item       `bson:",inline"`
 | 
			
		||||
	UserId           int64     `bson:"user_id"`
 | 
			
		||||
@ -33,3 +41,15 @@ type User struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (User) Coll() string { return "users" }
 | 
			
		||||
 | 
			
		||||
type Mute struct {
 | 
			
		||||
	tongo.Item  `bson:",inline"`
 | 
			
		||||
	UserId      int64     `bson:"user_id"`
 | 
			
		||||
	ChatId      int64     `bson:"chat_id"`
 | 
			
		||||
	Message     string    `bson:"message"`
 | 
			
		||||
	Date        time.Time `bson:"date"`
 | 
			
		||||
	Until       time.Time `bson:"until"`
 | 
			
		||||
	MessageLink string    `bson:"link"` //https://t.me/c/1402723647/279354/363305
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (Mute) Coll() string { return "mutes" }
 | 
			
		||||
 | 
			
		||||
@ -10,24 +10,16 @@ services:
 | 
			
		||||
    env_file:
 | 
			
		||||
      - bot.env
 | 
			
		||||
  mongo:
 | 
			
		||||
    image: mongo
 | 
			
		||||
    image: mongo:4
 | 
			
		||||
    restart: always
 | 
			
		||||
    env_file:
 | 
			
		||||
      - mongo.env
 | 
			
		||||
    ports:
 | 
			
		||||
      - ${HOST}:28003:27017
 | 
			
		||||
      - 27017
 | 
			
		||||
    volumes:
 | 
			
		||||
      - mongodata:/data/db
 | 
			
		||||
      - mongoconfig:/data/configdb
 | 
			
		||||
 | 
			
		||||
  mongo-express:
 | 
			
		||||
    image: mongo-express
 | 
			
		||||
    restart: always
 | 
			
		||||
    ports:
 | 
			
		||||
      - ${HOST}:8090:8081
 | 
			
		||||
    env_file:
 | 
			
		||||
      - mongo.env
 | 
			
		||||
 | 
			
		||||
volumes:
 | 
			
		||||
  mongodata:
 | 
			
		||||
  mongoconfig:
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"kickerbot/db"
 | 
			
		||||
	"log"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"git.nefrace.ru/nefrace/tongo"
 | 
			
		||||
@ -21,6 +22,10 @@ func userJoined(b *bot, update *echotron.Update) error {
 | 
			
		||||
	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 {
 | 
			
		||||
@ -46,10 +51,6 @@ func userJoined(b *bot, update *echotron.Update) error {
 | 
			
		||||
	if captcha == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	// _, err := b.DeleteMessage(update.Message.Chat.ID, update.Message.ID)
 | 
			
		||||
	// if err != nil {
 | 
			
		||||
	// 	log.Printf("Can't delete message: %v", err)
 | 
			
		||||
	// }
 | 
			
		||||
	bytes, err := captcha.ToBytes()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Error creating captcha bytes: %v", bytes)
 | 
			
		||||
@ -86,6 +87,68 @@ func userLeft(b *bot, update *echotron.Update) error {
 | 
			
		||||
	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),
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	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 userBanned(b *bot, update *echotron.Update) error {
 | 
			
		||||
	m := update.ChatMember
 | 
			
		||||
	c := m.Chat
 | 
			
		||||
@ -107,20 +170,19 @@ func checkCaptcha(b *bot, update *echotron.Update) error {
 | 
			
		||||
	// 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 {
 | 
			
		||||
		chat, err := chatStore.GetOne(ctx, tongo.E("chat_id", message.Chat.ID))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if message.Chat.IsForum {
 | 
			
		||||
			if message.ThreadID != int(chat.TopicId) {
 | 
			
		||||
				b.DeleteMessage(message.Chat.ID, message.ID)
 | 
			
		||||
				text := fmt.Sprintf("*%s*, сначала пройди капчу\\!", UserMention(sender))
 | 
			
		||||
				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
 | 
			
		||||
@ -152,7 +214,7 @@ func checkCaptcha(b *bot, update *echotron.Update) error {
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Printf("Can't send welcome message: %s", err)
 | 
			
		||||
				}
 | 
			
		||||
				go waitAndDelete(&b.API, res.Result, timeout*time.Second)
 | 
			
		||||
				go waitAndDelete(&b.API, res.Result, timeout)
 | 
			
		||||
				// time.Sleep(time.Second * 10)
 | 
			
		||||
				// _, err = b.DeleteMessage(message.Chat.ID, res.Result.ID)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
@ -167,6 +229,69 @@ func checkCaptcha(b *bot, update *echotron.Update) error {
 | 
			
		||||
			b.BanChatMember(message.Chat.ID, sender.ID, nil)
 | 
			
		||||
			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
 | 
			
		||||
}
 | 
			
		||||
@ -195,12 +320,6 @@ func botAdded(b *bot, update *echotron.Update) error {
 | 
			
		||||
 | 
			
		||||
func setTopic(b *bot, update *echotron.Update) error {
 | 
			
		||||
	m := update.Message
 | 
			
		||||
	if res, err := b.GetChatMember(m.Chat.ID, m.From.ID); err == nil {
 | 
			
		||||
		m := res.Result
 | 
			
		||||
		if !(m.Status == "administrator" || m.Status == "creator") {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 | 
			
		||||
	defer cancel()
 | 
			
		||||
	store := tongo.NewStore[db.Chat](Client)
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ import (
 | 
			
		||||
	"kickerbot/db"
 | 
			
		||||
	"log"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@ -38,12 +39,32 @@ func (b *bot) Update(update *echotron.Update) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if update.Message.Text != "" {
 | 
			
		||||
			if update.Message.Text == "/settopic" {
 | 
			
		||||
				setTopic(b, update)
 | 
			
		||||
			res, err := b.GetChatMember(update.ChatID(), update.Message.From.ID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Kicker 44: can't get user member: ", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if res.Result.Status == "administrator" || res.Result.Status == "creator" {
 | 
			
		||||
				if update.Message.Text == "/settopic" {
 | 
			
		||||
					setTopic(b, update)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				if update.Message.Text == "/admin" {
 | 
			
		||||
					setAdminTopic(b, update, true)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				if update.Message.Text == "/unadmin" {
 | 
			
		||||
					setAdminTopic(b, update, false)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				if strings.HasPrefix(update.Message.Text, "/mute") {
 | 
			
		||||
					muteUser(b, update)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			checkCaptcha(b, update)
 | 
			
		||||
		}
 | 
			
		||||
		checkAdminTopics(b, update)
 | 
			
		||||
	}
 | 
			
		||||
	if update.ChatMember != nil {
 | 
			
		||||
		m := update.ChatMember.NewChatMember
 | 
			
		||||
@ -164,3 +185,25 @@ func UserMention(u *echotron.User) string {
 | 
			
		||||
func UserMentionDB(u *db.User) string {
 | 
			
		||||
	return Mention(u.FirstName, u.UserId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pluralRu(n int, single string, double string, five string) string {
 | 
			
		||||
	switch n {
 | 
			
		||||
	case 10, 11, 12, 13, 14, 15, 16, 17, 18, 19:
 | 
			
		||||
		return five
 | 
			
		||||
	default:
 | 
			
		||||
		s := []rune(strconv.Itoa(n))
 | 
			
		||||
		switch s[len(s)-1] {
 | 
			
		||||
		case '1':
 | 
			
		||||
			return single
 | 
			
		||||
		case '2', '3', '4':
 | 
			
		||||
			return double
 | 
			
		||||
		default:
 | 
			
		||||
			return five
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func transformChatID(id int64) int64 {
 | 
			
		||||
	return -id - 1000000000000
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,10 @@ func TaskKickOldUsers(b *echotron.API) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		log.Printf("User %s was banned", user.FirstName)
 | 
			
		||||
		_, err = b.DeleteMessage(user.ChatId, user.CaptchaMessage)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println("ERR: Captcha message not deleted: ", err)
 | 
			
		||||
		}
 | 
			
		||||
		store.DeleteByID(ctx, user.Id)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -46,7 +50,6 @@ func TaskNotifyUsers(b *echotron.API) {
 | 
			
		||||
	for _, user := range users {
 | 
			
		||||
		if time.Since(user.LastNotification) > 2*time.Minute {
 | 
			
		||||
			user.LastNotification = time.Now()
 | 
			
		||||
			text := fmt.Sprintf("*%s*, напоминаю, что тебе необходимо пройти капчу\\!", UserMentionDB(user))
 | 
			
		||||
			store.ReplaceItem(ctx, *user, false)
 | 
			
		||||
			chat, err := chatStore.GetOne(ctx, tongo.E("chat_id", user.ChatId))
 | 
			
		||||
			var topic int64 = 0
 | 
			
		||||
@ -56,6 +59,7 @@ func TaskNotifyUsers(b *echotron.API) {
 | 
			
		||||
			} else {
 | 
			
		||||
				topic = chat.TopicId
 | 
			
		||||
			}
 | 
			
		||||
			text := fmt.Sprintf("*%s*, напоминаю, что тебе необходимо пройти [капчу](https://t.me/c/%d/%d/%d)\\!", UserMentionDB(user), transformChatID(user.ChatId), chat.TopicId, user.CaptchaMessage)
 | 
			
		||||
			res, err := b.SendMessage(text, user.ChatId, &echotron.MessageOptions{MessageThreadID: topic, ParseMode: echotron.MarkdownV2, ReplyToMessageID: user.CaptchaMessage})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Printf("Can't send notification to user: %s", err)
 | 
			
		||||
@ -64,3 +68,15 @@ func TaskNotifyUsers(b *echotron.API) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TaskRemoveOldMutes(b *echotron.API) {
 | 
			
		||||
	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
 | 
			
		||||
	defer cancel()
 | 
			
		||||
	store := tongo.NewStore[db.Mute](Client)
 | 
			
		||||
	mutes, _ := store.GetMany(ctx)
 | 
			
		||||
	for _, mute := range mutes {
 | 
			
		||||
		if time.Now().After(mute.Until) {
 | 
			
		||||
			store.DeleteByID(ctx, mute.Id)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								main.go
									
									
									
									
									
								
							@ -38,6 +38,7 @@ func main() {
 | 
			
		||||
	tasker := echotron.NewAPI(token)
 | 
			
		||||
	scheduler.Every(30).Seconds().Do(func() { kicker.TaskKickOldUsers(&tasker) })
 | 
			
		||||
	scheduler.Every(30).Seconds().Do(func() { kicker.TaskNotifyUsers(&tasker) })
 | 
			
		||||
	scheduler.Every(2).Minutes().Do(func() { kicker.TaskRemoveOldMutes(&tasker) })
 | 
			
		||||
	scheduler.StartAsync()
 | 
			
		||||
	Bot.Start()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user