0

Compare commits

..

3 Commits

Author SHA1 Message Date
eleksir
e54144d716 Update TODO 2025-01-02 15:12:09 +03:00
eleksir
2bf30fc346 [WIP] Insert returns in if-s, to stop processing at proper phase, add greet for newcommers 2025-01-02 15:11:50 +03:00
eleksir
abbf2ca145 [WIP] Fix typos 2025-01-02 15:09:42 +03:00
4 changed files with 137 additions and 45 deletions

33
TODO.md
View File

@@ -5,32 +5,45 @@
Для реализации телеграммного фронтэнда нам надо сделать: Для реализации телеграммного фронтэнда нам надо сделать:
0. Парсер конфига. 0. Парсер конфига.
[V] Реализован начальный вариант парсера конфига. [V] Реализован начальный вариант парсера конфига.
1. Разгребальщик апдейтов и формирователь redis-ных сообщений. 1. Разгребальщик апдейтов и формирователь redis-ных сообщений.
[ ] Написана заглушка для парсера апдейтов bot api телеграма [ ] Написана заглушка для парсера апдейтов bot api телеграма
2. Разгребальщик редисных сообщений и формирователь запросов в tg bot api. 2. Разгребальщик редисных сообщений и формирователь запросов в tg bot api.
[ ] Написан черновой вариант рагребателя [ ] Написан черновой вариант рагребателя
3. Обработчик группы команд admin, сохранение настроек в pebbledb. 3. Обработчик группы команд admin, сохранение настроек в pebbledb.
1 цензор сообщений определённого типа. 1 [V] [V] цензор сообщений определённого типа.
2 фортунка каждое утро. (+ добавить время, относительно gmt, когда показывать фортунку). 2 [ ] [V] фортунка каждое утро. (+ добавить время, относительно gmt, когда показывать фортунку).
3 Приветствие новых участников 3 [V] [V] Приветствие новых участников
4 oboobs 4 [V] [ ] Прощание с теми, кто ушёл
5 obutts 4 [ ] [ ] oboobs
6 chan_msg 5 [ ] [ ] obutts
7 user ban 6 [V] [ ] chan_msg
8 user mute 7 [ ] [ ] user ban
4. help 8 [ ] [ ] user mute
5. Readme.txt 4. [V] help
5. [V] help admin
6. [ ] Readme
7. [ ] Поддержать миграцию групп в супергруппы (итд, там меняется id и надо перекидывать настройки на новый id)
8. [ ] Поддержать парсинг ошибок отправки сообщений в телегу
9. [ ] Поддержать leaveChat(), чтобы бот мог легально и самостоятельно покинуть чят.

View File

@@ -33,4 +33,13 @@ var settingsDB = make(map[string]*pebble.DB)
var tg echotron.API var tg echotron.API
// Приветсвенные фразы для новых участников чата.
var introduceGreet = [...]string{
"Дратути",
"Дарована",
"Доброе утро, день или вечер",
"Добро пожаловать в наше скромное коммунити",
"Наше вам с кисточкой тут, на канальчике",
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */ /* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -3,8 +3,10 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/rand/v2"
"regexp" "regexp"
"strconv" "strconv"
"strings"
"github.com/NicoNex/echotron/v3" "github.com/NicoNex/echotron/v3"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
@@ -124,40 +126,13 @@ func telegramMsgParser(msg *echotron.Update) {
if (msg.Message.MigrateFromChatID < 0) && (msg.Message.MigrateToChatID < 0) { //nolint: revive,staticcheck if (msg.Message.MigrateFromChatID < 0) && (msg.Message.MigrateToChatID < 0) { //nolint: revive,staticcheck
// TODO: поддержать миграцию настроек чата на новый chatId. // TODO: поддержать миграцию настроек чата на новый chatId.
// TODO: подумать, что можно сделать с настройками бэкэндов. Кажись, ничего, но надо глянуть. // TODO: подумать, что можно сделать с настройками бэкэндов. Кажись, ничего, но надо глянуть.
}
// Люди пришли в чят.
if msg.Message.NewChatMembers != nil { //nolint: revive,staticcheck
// TODO: проверить, надо ли приветствовать, выбрать одну из приветственных фраз, потянуть время, типа, мы пишем
// текст и поприветствовать вновь прибывшего.
}
// Человек ушёл из чата.
if msg.Message.LeftChatMember != nil {
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GoodbyeMsg") == "1" {
user := ConstructUserFirstLastName(msg.Message.From)
goodbye := fmt.Sprintf("Прощаемся с %s", user)
opts := echotron.MessageOptions{DisableNotification: true, ParseMode: "MarkdownV2"}
if msg.Message.ThreadID != 0 {
opts.MessageThreadID = int64(msg.Message.ThreadID)
}
if res, err := tg.SendMessage(goodbye, msg.Message.Chat.ID, &opts); err != nil {
log.Errorf("Unable to send message to telegram api: %s", err)
} else if !res.Ok {
log.Errorf("Unable to send message to telegram api: %s", res.Description)
}
}
}
// Если сообщение было зацензурено, то дальше его обрабатывать не надо.
if Censor(msg) {
return return
} }
// Здесь начинается парсинг, подразумевающий какие-то сообщения бота в чат, поэтому с этой точки можно/нужно
// получить информацию о самом боте.
// TODO: пораскинуть, можно ли как-то кэшировать эту информацию, чтобы не дёргать api по чём зря.
var ( var (
rmsg rMsg rmsg rMsg
errorOccured bool errorOccured bool
@@ -182,6 +157,100 @@ func telegramMsgParser(msg *echotron.Update) {
return return
} }
// Люди пришли в чят.
if msg.Message.NewChatMembers != nil { //nolint: revive,staticcheck
// TODO: проверить, надо ли приветствовать, выбрать одну из приветственных фраз, потянуть время, типа, мы пишем
// текст и поприветствовать вновь прибывшего.
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GreetMsg") == "1" {
// Пользователи, которых мы приветсвуем, одной строкой.
var users string
if len(msg.Message.NewChatMembers) > 1 {
lastOne := msg.Message.NewChatMembers[len(msg.Message.NewChatMembers)-1]
theRest := msg.Message.NewChatMembers[:len(msg.Message.NewChatMembers)-1]
var usersSlice []string
for _, user := range theRest {
usersSlice = append(usersSlice, ConstructTelegramHighlightName(user))
}
users = strings.Join(usersSlice, ", ")
users += fmt.Sprintf(" and %s", ConstructTelegramHighlightName(lastOne))
} else {
users = ConstructTelegramHighlightName(msg.Message.NewChatMembers[0])
}
phrase := fmt.Sprintf(
"%s, %s. Представьтес, пожалуйста, и расскажите, что вас сюда привело.",
introduceGreet[rand.IntN(len(introduceGreet))],
users,
)
// Потянуть время, изобразить настоящего человека.
resp, err := tg.SendChatAction(
echotron.Typing,
msg.Message.From.ID,
&echotron.ChatActionOptions{MessageThreadID: int(msg.Message.ThreadID)},
)
// TODO: вероятно, ошибку надо засылать в обработчик ошибок, так как в ней может быть миграция чятика или
// что-то, что тоже надо хэндлить.
if err != nil || !resp.Ok {
log.Errorf(
"unable to send message to telegram api: %s\nResponse dump: %s",
err,
spew.Sdump(resp),
)
}
resp1, err := tg.SendMessage(
phrase,
msg.Message.Chat.ID,
&echotron.MessageOptions{ParseMode: "MarkdownV2", MessageThreadID: int64(msg.Message.ThreadID)},
)
// TODO: вероятно, ошибку надо засылать в обработчик ошибок, так как в ней может быть миграция чятика или
// что-то, что тоже надо хэндлить.
if err != nil || !resp1.Ok {
log.Errorf(
"unable to send message to telegram api: %s\nResponse dump: %s",
err,
spew.Sdump(resp1),
)
}
}
return
}
// Человек ушёл из чата.
if msg.Message.LeftChatMember != nil {
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GoodbyeMsg") == "1" {
user := ConstructUserFirstLastName(msg.Message.From)
goodbye := fmt.Sprintf("Прощаемся с %s", user)
opts := echotron.MessageOptions{DisableNotification: true, ParseMode: "MarkdownV2"}
if msg.Message.ThreadID != 0 {
opts.MessageThreadID = int64(msg.Message.ThreadID)
}
if res, err := tg.SendMessage(goodbye, msg.Message.Chat.ID, &opts); err != nil {
log.Errorf("Unable to send message to telegram api: %s", err)
} else if !res.Ok {
log.Errorf("Unable to send message to telegram api: %s", res.Description)
}
}
return
}
// Если сообщение было зацензурено, то дальше его обрабатывать не надо.
if Censor(msg) {
return
}
switch msg.Message.Chat.Type { switch msg.Message.Chat.Type {
case "private": case "private":
// Всё что можно было похэндлить, что не содержало текста, считаем, что обработали. // Всё что можно было похэндлить, что не содержало текста, считаем, что обработали.
@@ -287,9 +356,10 @@ func telegramMsgParser(msg *echotron.Update) {
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "") msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
} }
// TODO: обращение может содержать знаки препинания, пробелы перед, пробелы после. Надо бы это поддержать. // TODO: обращение может содержать знаки препинания, пробелы перед, пробелы после имени бота. Надо бы это поддержать.
// TODO: унести вырезание имени бота в отдельную процедуру.
switch { switch {
// Если у на есть и имя и фамилия бота, то попробуем их слепить вместе, через "1 и более" пробел и вырезать // Если у нас есть и имя и фамилия бота, то попробуем их слепить вместе, через "1 и более" пробел и вырезать
// полученное из входящей фразы. // полученное из входящей фразы.
case quotedBotFirstName != "" && quotedBotLastName != "": case quotedBotFirstName != "" && quotedBotLastName != "":
messageContainsBotName, err := regexp.MatchString( messageContainsBotName, err := regexp.MatchString(
@@ -1090,7 +1160,7 @@ func Admin(msg *echotron.Update) (bool, error) {
answer += "Не будем приветствовать вновьприбывших участников чата" answer += "Не будем приветствовать вновьприбывших участников чата"
default: default:
answer += "Не понимаю о чём ты." answer += "Не понимаю, о чём ты."
} }
} }

View File

@@ -111,7 +111,7 @@ func ConstructPartialChatUsername(c *echotron.Chat) string {
} }
// ConstructUserFirstLastName Пытается найти и вытащить first name и last name пользователя, если не получается, то // ConstructUserFirstLastName Пытается найти и вытащить first name и last name пользователя, если не получается, то
// вначале пытается фоллбэчиться на first name, потом на last name, потом на username. // вначале пытается фоллбэчится на first name, потом на last name, потом на username.
func ConstructUserFirstLastName(u *echotron.User) string { func ConstructUserFirstLastName(u *echotron.User) string {
var user string var user string
@@ -131,7 +131,7 @@ func ConstructUserFirstLastName(u *echotron.User) string {
return user return user
} }
// ConstructTelegramHighlightName генерирует имя пользователя, которое триггерит на стороне клиент ивент меншена // ConstructTelegramHighlightName генерирует имя пользователя, которое триггерит на стороне клиента ивент меншена
// определённого пользователя. // определённого пользователя.
func ConstructTelegramHighlightName(u *echotron.User) string { func ConstructTelegramHighlightName(u *echotron.User) string {
var ( var (