diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2c39b99 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.18.3 as builder +LABEL stage=tgbotbuilder +WORKDIR /src + +COPY go.mod . +COPY go.sum . +RUN go mod download + +COPY . . + +RUN make build +RUN mkdir -p /etc/tgbot && mkdir /data + +FROM scratch +COPY --from=builder /app /app +ADD folders.tar.gz / + +ENTRYPOINT [ "/app" ] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a589b8e --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +.PHONY: default build image run + +default: build + +build: + CGO_ENABLED=1 GOOS=linux go build -o /app -a -ldflags '-linkmode external -extldflags "-static"' cmd/main.go + +image: + docker build -t skillbot:latest . + docker image prune -f --filter label=stage=tgbotbuilder + +run: + go run cmd/main.go \ No newline at end of file diff --git a/README.md b/README.md index 1164b0e..5b1e80b 100644 --- a/README.md +++ b/README.md @@ -1 +1,4 @@ # tg-bot-users 🤖 + +# Список команд: + diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..1d9280b --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "flag" + "log" + "skbot/internal/callbackmsg" + "skbot/internal/chatmembers" + "skbot/internal/comandmsg" + "skbot/internal/config" + "skbot/internal/functions" + "skbot/internal/socialmsg" + "skbot/internal/textmsg" + "skbot/pkg/client/telegram" + "skbot/pkg/logging" +) + +var cfgPath string + +func init() { + flag.StringVar(&cfgPath, "config", "tg-bot-users/conf.yml", "config file path") +} + +func main() { + + log.Print("config initializing") + cfg := config.GetConfig(cfgPath) + + log.Print("logger initializing") + logger := logging.GetLogger(cfg.AppConfig.LogLevel) + + modGroupId := cfg.ModersGroupID.ModeratorsGroup + _, _, err := functions.AddModeratorsGroup(cfg.ModersGroupID.ModeratorsGroup) + _, _, err = functions.AddModeratorsGroup(cfg.ModersGroupID.ModeratorsGroupGolang) + _, _, err = functions.AddModeratorsGroup(cfg.ModersGroupID.ModeratorsGroupJava) + _, _, err = functions.AddModeratorsGroup(cfg.ModersGroupID.ModeratorsGroupPython) + _, _, err = functions.AddModeratorsGroup(cfg.ModersGroupID.ModeratorsGroup1S) + _, _, err = functions.AddModeratorsGroup(cfg.ModersGroupID.ModeratorsGroupCSharp) + if err != nil { + logger.Info(err) + } + + updChan, bot, err := telegram.StartBotByChan(cfg, logger) + if err != nil { + logger.Fatal(err) + } + defer bot.StopReceivingUpdates() + + for { + + update := <-updChan + + // make slice from text message + //if update.Message != nil { + // command := strings.Split(update.Message.Text, " ") + //} else { + // continue + //} + if update.Message != nil { + + // text messages operations + textmsg.WithTextQueryDo(update, bot, logger, modGroupId) + + // social messages from bot in chat + socialmsg.WithSocialTextQueryDo(update, bot, logger) + } else if update.CallbackQuery != nil { + + callbackmsg.WithCallBackDo(update, bot, logger, modGroupId) + + } else if update.Message.Command() != "" { + + //com menu (only moderator's chats) + comandmsg.CommandQueryDo(update, bot, logger) + } else if update.Message.NewChatMembers != nil { + + chatmembers.WithChatMembersDo(update, bot, logger) + } + + // TODO inline help + if update.InlineQuery != nil { + log.Println("response from Inline query") + query := update.InlineQuery.Query + + log.Println(query) + + } + + } + +} diff --git a/conf.yml b/conf.yml new file mode 100755 index 0000000..d4091d4 --- /dev/null +++ b/conf.yml @@ -0,0 +1,23 @@ +--- + + +telegram: + tg_token: + tg_sert: + + + +app: + log_level: trace + +chat_count_config: + test_chat_id_count: + chat_id_count: + +moderators: + moderators_group: + moderators_group_golang: + moderators_group_java: + moderators_group_python: + moderators_group_1s: + moderators_group_csharp: diff --git a/folders.tar.gz b/folders.tar.gz new file mode 100644 index 0000000..1bf6740 Binary files /dev/null and b/folders.tar.gz differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7d922e3 --- /dev/null +++ b/go.mod @@ -0,0 +1,18 @@ +module skbot + +go 1.18 + +require ( + github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 + github.com/ilyakaznacheev/cleanenv v1.3.0 + github.com/mattn/go-sqlite3 v1.14.14 + github.com/sirupsen/logrus v1.8.1 +) + +require ( + github.com/BurntSushi/toml v1.1.0 // indirect + github.com/joho/godotenv v1.4.0 // indirect + golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..220a7ff --- /dev/null +++ b/go.sum @@ -0,0 +1,26 @@ +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= +github.com/ilyakaznacheev/cleanenv v1.3.0 h1:RapuLclPPUbmdd5Bi5UXScwMEZA6+ZNLU5OW9itPjj0= +github.com/ilyakaznacheev/cleanenv v1.3.0/go.mod h1:i0owW+HDxeGKE0/JPREJOdSCPIyOnmh6C0xhWAkF/xA= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 h1:slmdOY3vp8a7KQbHkL+FLbvbkgMqmXojpFUO/jENuqQ= +olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3/go.mod h1:oVgVk4OWVDi43qWBEyGhXgYxt7+ED4iYNpTngSLX2Iw= diff --git a/internal/callbackmsg/callbackmsg.go b/internal/callbackmsg/callbackmsg.go new file mode 100644 index 0000000..cc172b6 --- /dev/null +++ b/internal/callbackmsg/callbackmsg.go @@ -0,0 +1,83 @@ +package callbackmsg + +import ( + "fmt" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "skbot/internal/config" + "skbot/internal/functions" + "skbot/internal/menu" + "skbot/pkg/logging" + "time" +) + +func WithCallBackDo(update tgbotapi.Update, bot *tgbotapi.BotAPI, logger *logging.Logger, modGroupId int64) { + + data := update.CallbackQuery.Data + + switch data { + + case "com_list": + + msg := tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, menu.ComMenu) + msg.ParseMode = "markdown" + delMsg, _ := bot.Send(msg) + + callback := tgbotapi.NewCallback(update.CallbackQuery.ID, "✅") + if _, err := bot.Request(callback); err != nil { + logger.Error(err) + } + + go func() { + time.Sleep(30 * time.Second) + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.CallbackQuery.Message.Chat.ID, delMsg.MessageID)) + }() + + case "jubilee_list": + + var list string + var count = 1 + users, err := functions.GetJubileeUsers() + chatId := update.CallbackQuery.Message.Chat.ID + if err != nil { + logger.Info(err) + } + + moderGroupList, err := functions.GetModeratorsGroup() + if err != nil { + logger.Error(err) + } + + for _, group := range moderGroupList { + + if group.GroupID == chatId { + + for _, user := range users { + // TODO take id from base to number users in list + text := fmt.Sprintf("*№%d* \nГруппа: *%s*\nИмя: *%s* Ник: *@%s*\nНомер: *%d* "+ + "Время: *%s* ", count, user.GroupName, user.UserName, user.UserNick, + user.Serial, user.Time.Format(config.StructDateTimeFormat)) + + list = list + text + "\n\n" + count++ + + } + } + } + msg := tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, "Список юбилейный:\n"+list) + msg.ParseMode = "markdown" + _, _ = bot.Send(msg) + + callback := tgbotapi.NewCallback(update.CallbackQuery.ID, "✅") + if _, err := bot.Request(callback); err != nil { + logger.Error(err) + } + + case "add_mod": + + callback := tgbotapi.NewCallback(update.CallbackQuery.ID, "✅") + if _, err := bot.Request(callback); err != nil { + logger.Error(err) + } + + } +} diff --git a/internal/chatmembers/chatmembers.go b/internal/chatmembers/chatmembers.go new file mode 100644 index 0000000..74a86d9 --- /dev/null +++ b/internal/chatmembers/chatmembers.go @@ -0,0 +1,63 @@ +package chatmembers + +import ( + "fmt" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "skbot/internal/config" + "skbot/internal/functions" + "skbot/pkg/logging" + "time" +) + +func WithChatMembersDo(update tgbotapi.Update, bot *tgbotapi.BotAPI, logger *logging.Logger) { + + newUser := update.Message.NewChatMembers[0] + chatId := update.Message.Chat.ID + groupName := update.Message.Chat.Title + + if !newUser.IsBot { + count, err := bot.GetChatMembersCount(tgbotapi.ChatMemberCountConfig{ + ChatConfig: tgbotapi.ChatConfig{ + ChatID: chatId, + SuperGroupUsername: groupName, + }, + }) + + if count%500 == 0 || count%500 == 1 || count%500 == 2 || count == 4 { + + err = functions.AddNewJubileeUser(&newUser, count, groupName) + if err != nil { + logger.Error(err) + } + + moderGroupList, err := functions.GetModeratorsGroup() + if err != nil { + logger.Error(err) + } + + for _, group := range moderGroupList { + + text := fmt.Sprintf("🎉 В группу: %s вступил юбилейный пользователь\n%s "+ + "(@%s), %d. \nВремя вступления %s", + groupName, newUser.FirstName, newUser.UserName, count, + time.Now().Format(config.StructDateTimeFormat)) + + _, _ = bot.Send(tgbotapi.NewMessage(group.GroupID, text)) + } + + } + + msg := tgbotapi.NewMessage(chatId, fmt.Sprintf("_Рады вас приветствовать_ "+ + "*%s*, _расскажите нам о себе пожалуйста._", newUser.FirstName)) + + msg.ParseMode = "markdown" + ans, _ := bot.Send(msg) + + go func() { + + time.Sleep(20 * time.Second) + _, _ = bot.Send(tgbotapi.NewDeleteMessage(chatId, ans.MessageID)) + }() + } + +} diff --git a/internal/comandmsg/comandmsg.go b/internal/comandmsg/comandmsg.go new file mode 100644 index 0000000..f309aca --- /dev/null +++ b/internal/comandmsg/comandmsg.go @@ -0,0 +1,94 @@ +package comandmsg + +import ( + "fmt" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "skbot/internal/config" + "skbot/internal/functions" + "skbot/internal/menu" + "skbot/pkg/logging" + "time" +) + +func CommandQueryDo(update tgbotapi.Update, bot *tgbotapi.BotAPI, logger *logging.Logger) { + + // com menu (only moderator's chats) ---------------------------- + if update.Message.Command() == "menu" { + + moderGroupList, err := functions.GetModeratorsGroup() + if err != nil { + logger.Error(err) + } + + for _, group := range moderGroupList { + + if group.GroupID == update.Message.Chat.ID { + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, menu.ComMenu) + + del, _ := bot.Send(msg) + + go func() { + time.Sleep(60 * time.Second) + msDel := tgbotapi.NewDeleteMessage(update.Message.Chat.ID, del.MessageID) + _, _ = bot.Send(msDel) + msg.ReplyMarkup = tgbotapi.NewRemoveKeyboard(true) + + }() + + } + } + + } + + // LIST of all jubilee users -------------------------------------- + if update.Message.Command() == "jubileelist" { + + users, err := functions.GetJubileeUsers() + chatId := update.Message.Chat.ID + if err != nil { + logger.Info(err) + } + + moderGroupList, err := functions.GetModeratorsGroup() + if err != nil { + logger.Error(err) + } + for _, group := range moderGroupList { + + if group.GroupID == chatId { + + for _, user := range users { + + text := fmt.Sprintf("*Группа:* _%s_\n*Имя:* %s\n*Ник:* @%s\n*Номер вступления:* %d\n"+ + "*Время вступления:* %s ", user.GroupName, user.UserName, user.UserNick, + user.Serial, user.Time.Format(config.StructDateTimeFormat)) + + msg := tgbotapi.NewMessage(chatId, text) + msg.ParseMode = "markdown" + _, _ = bot.Send(msg) + + } + } + } + + } + + //if update.Message.Command() == "12" { + // + // msg := tgbotapi.NewMessage(update.Message.Chat.ID, "keyboard") + // + // msg.ReplyMarkup = menu.NumericKeyboard + // + // _, err := bot.Send(msg) + // if err != nil { + // logger.Error(err) + // } + // + // go func() { + // time.Sleep(30 * time.Second) + // msg.ReplyMarkup = tgbotapi.NewRemoveKeyboard(true) + // }() + //} + +} diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100755 index 0000000..76e0788 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,55 @@ +package config + +import ( + "github.com/ilyakaznacheev/cleanenv" + "log" + "sync" +) + +type Config struct { + Telegram struct { + Token string `yaml:"tg_token" env:"TG-BOT-TOKEN" env-required:"true"` + Sert string `yaml:"tg_sert"` + } + YouTube struct { + APIURL string `yaml:"api_url"` + AccessToken string `yaml:"access_token"` + } + AppConfig AppConfig `yaml:"app"` + ChatCountConfig ChatCountConfig `yaml:"chat_count_config"` + ModersGroupID ModersGroupID `yaml:"moderators"` +} + +type AppConfig struct { + LogLevel string `yaml:"log_level" env:"TG-BOT-LogLevel" env-default:"error" env-required:"true"` +} + +type ChatCountConfig struct { + TestChatIdCount int64 `yaml:"test_chat_id_count"` + ChatIdCount int64 `yaml:"chat_id_count"` +} + +type ModersGroupID struct { + ModeratorsGroup int64 `yaml:"moderators_group" env:"moderators_group" env-required:"true"` + ModeratorsGroupGolang int64 `yaml:"moderators_group_golang" env:"moderators_group_golang"` + ModeratorsGroupJava int64 `yaml:"moderators_group_java" env:"moderators_group_java"` + ModeratorsGroupPython int64 `yaml:"moderators_group_python" env:"moderators_group_python"` + ModeratorsGroup1S int64 `yaml:"moderators_group_1s" env:"moderators_group_1s"` + ModeratorsGroupCSharp int64 `yaml:"moderators_group_csharp" env:"moderators_group_csharp"` +} + +var instance *Config +var once sync.Once + +func GetConfig(path string) *Config { + once.Do(func() { + log.Printf("read application config from path %s", path) + + instance = &Config{} + + if err := cleanenv.ReadConfig(path, instance); err != nil { + log.Fatal(err) + } + }) + return instance +} diff --git a/internal/config/constants.go b/internal/config/constants.go new file mode 100755 index 0000000..083af3f --- /dev/null +++ b/internal/config/constants.go @@ -0,0 +1,15 @@ +package config + +const StructDateTimeFormat = "2006-01-02 15:04" +const StructDateFormat = "2006-01-02" +const StructTimeFormat = "15:04" +const ( + Jubileelist = "jubileelist" +) + +var SocialMessage bool + +//var SocialChoice = SocialDown +//var SocialUP = "Включено" +//var SocialDown = "Выключено" +//var SocText = fmt.Sprintf("Социальные сообщения: %s", SocialChoice) diff --git a/internal/data/data.go b/internal/data/data.go new file mode 100755 index 0000000..33c793b --- /dev/null +++ b/internal/data/data.go @@ -0,0 +1,28 @@ +package data + +import "time" + +type User struct { + ID int + Name string + Sex string +} + +type BadWords struct { + ID int + Word string +} +type ModeratorsGroup struct { + ID int + GroupID int64 +} + +type JubileeUser struct { + ID int + Serial int + UserID int + UserName string + UserNick string + Time time.Time + GroupName string +} diff --git a/internal/functions/functions.go b/internal/functions/functions.go new file mode 100755 index 0000000..a797d1b --- /dev/null +++ b/internal/functions/functions.go @@ -0,0 +1,263 @@ +package functions + +import ( + "database/sql" + "errors" + "fmt" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + _ "github.com/mattn/go-sqlite3" + "log" + "skbot/internal/data" + "strings" +) + +var ( + qb = "CREATE TABLE IF NOT EXISTS badwords (id INTEGER PRIMARY KEY, word VARCHAR (30) NOT NULL)" + + qbu = "SELECT * FROM badwords" + + mod = "CREATE TABLE IF NOT EXISTS moderators (id INTEGER PRIMARY KEY, groupid INTEGER NOT NULL)" + + modSel = "SELECT * FROM moderators" + + addNewUsersDB = "CREATE TABLE IF NOT EXISTS newJubileeUsers (id INTEGER PRIMARY KEY, serial INTEGER NOT NULL, " + + "user_id INTEGER NOT NULL, user_name VARCHAR (30) NOT NULL, user_nick VARCHAR (50) DEFAULT ('нет ника'), " + + "time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, group_name VARCHAR (50) NOT NULL)" +) + +func TrimSymbolsFromSlice(s []string) (words []string, err error) { + + var messageUpd []string + + for _, k := range s { + + k = strings.Trim(k, "([]{}*).,!") + messageUpd = append(messageUpd, k) + } + + words = messageUpd + + return words, nil +} + +func CheckBadWords(badList []string) (clearList []string, haveBadWords bool, err error) { + + var badWords []data.BadWords + var badWord data.BadWords + haveBadWords = false + + db, err := sql.Open("sqlite3", "./tg-bot-users/internal/sqlitedb/badwords.db") + if err != nil { + return + } + + rows, err := db.Query(qbu) + if err != nil { + return nil, false, err + } + + defer db.Close() + + for rows.Next() { + err = rows.Scan(&badWord.ID, &badWord.Word) + badWords = append(badWords, badWord) + } + + for _, word := range badList { + + for _, bad := range badWords { + + if word == bad.Word { + + log.Println("найдено совпадение матерного слова в базе", word) + haveBadWords = true + } + + } + + } + + return clearList, haveBadWords, err + +} + +func AddBadWord(word string) (bool, error) { + + var badWord data.BadWords + var haveWord = false + + db, err := sql.Open("sqlite3", "./tg-bot-users/internal/sqlitedb/badwords.db") + if err != nil { + return false, err + } + + stat, err := db.Prepare(qb) + if err != nil { + return false, err + } + + _, _ = stat.Exec() + + rows, err := db.Query(qbu) + if err != nil { + } + + defer db.Close() + + for rows.Next() { + err = rows.Scan(&badWord.ID, &badWord.Word) + if badWord.Word == word { + haveWord = true + return true, nil + } + } + + if !haveWord { + + stat, err = db.Prepare(fmt.Sprintf("INSERT INTO badwords (word) VALUES ('%s')", word)) + stat.Exec() + if err != nil { + return false, errors.New("ошибка добавления матерного слова в базу") + + } else { + return true, errors.New("новое матерное слово занесено в базу") + } + } + + return true, errors.New("added") + +} + +func AddModeratorsGroup(group int64) (haveGroup bool, modGroups []data.ModeratorsGroup, err error) { + + var modGroup data.ModeratorsGroup + haveGroup = false + + db, err := sql.Open("sqlite3", "./tg-bot-users/internal/sqlitedb/moderators.db") + if err != nil { + return haveGroup, nil, err + } + + defer db.Close() + + stat, err := db.Prepare(mod) + if err != nil { + log.Println(err) + } + + _, err = stat.Exec() + if err != nil { + return haveGroup, nil, err + } + + rows, err := db.Query(modSel) + if err != nil { + log.Println(err) + } + + for rows.Next() { + err = rows.Scan(&modGroup.ID, &modGroup.GroupID) + modGroups = append(modGroups, modGroup) + } + + for _, grp := range modGroups { + if grp.GroupID == group { + haveGroup = true + return haveGroup, modGroups, errors.New("have group") + } + } + + if !haveGroup && group != 0 { + stat, err = db.Prepare(fmt.Sprintf("INSERT INTO moderators (groupid) VALUES ('%d')", group)) + if err != nil { + log.Println(err) + } + _, _ = stat.Exec() + haveGroup = true + } + return haveGroup, modGroups, nil +} + +func GetModeratorsGroup() (groups []data.ModeratorsGroup, err error) { + + var group data.ModeratorsGroup + + db, err := sql.Open("sqlite3", "./tg-bot-users/internal/sqlitedb/moderators.db") + if err != nil { + return nil, err + } + + defer db.Close() + + rows, err := db.Query(modSel) + if err != nil { + log.Println(err) + } + + for rows.Next() { + err = rows.Scan(&group.ID, &group.GroupID) + groups = append(groups, group) + } + + return + +} + +func AddNewJubileeUser(newUser *tgbotapi.User, serial int, groupName string) error { + + db, err := sql.Open("sqlite3", "./tg-bot-users/internal/sqlitedb/newJubileeUsers.db") + if err != nil { + return err + } + defer db.Close() + + log.Println("создание таблицы") + stat, err := db.Prepare(addNewUsersDB) + if err != nil { + return err + } + _, _ = stat.Exec() + + stat, err = db.Prepare(fmt.Sprintf("INSERT INTO newJubileeUsers (serial, user_id, user_name, user_nick, "+ + "group_name) VALUES ('%d', '%d', '%s', '%s', '%s')", serial, newUser.ID, newUser.FirstName, newUser.UserName, groupName)) + if err != nil { + log.Println(err) + } + _, err = stat.Exec() + if err != nil { + log.Println(err) + } + + return nil +} + +func GetJubileeUsers() (jubUsers []data.JubileeUser, err error) { + + var user data.JubileeUser + var users []data.JubileeUser + + db, err := sql.Open("sqlite3", "./tg-bot-users/internal/sqlitedb/newJubileeUsers.db") + if err != nil { + return nil, err + } + defer db.Close() + + rows, err := db.Query("SELECT * FROM newJubileeUsers") + if err != nil { + return nil, err + } + + for rows.Next() { + err = rows.Scan(&user.ID, &user.Serial, &user.UserID, &user.UserName, &user.UserNick, &user.Time, &user.GroupName) + users = append(users, user) + } + + for _, v := range users { + if v.Serial%500 == 0 || v.Serial%500 == 1 || v.Serial%500 == 2 || v.Serial%4 == 0 { + jubUsers = append(jubUsers, v) + } + } + + return jubUsers, nil + +} diff --git a/internal/menu/menu.go b/internal/menu/menu.go new file mode 100755 index 0000000..d817fda --- /dev/null +++ b/internal/menu/menu.go @@ -0,0 +1,21 @@ +package menu + +import ( + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +const ComMenu = " Список доступных вам команд: 🛠 \n \n" + + "✅ `addmoderatorgroup` + номер _(добавление группы модераторов)._\n" + + "✅ `chatinfo` _(информация о имени и ID группы будет отправлено в админку," + + " сообщение будет удалено из группы пользователей, если бот админ. )_\n" + + "✅ *Мат + слово* _(Слово будет добавлено в базу)._\n" + +var NumericKeyboard = tgbotapi.NewInlineKeyboardMarkup( + tgbotapi.NewInlineKeyboardRow(button1), + tgbotapi.NewInlineKeyboardRow(button2), + tgbotapi.NewInlineKeyboardRow(button3), +) + +var button1 = tgbotapi.NewInlineKeyboardButtonData("Список команд", "com_list") +var button2 = tgbotapi.NewInlineKeyboardButtonData("Список юбилейный", "jubilee_list") +var button3 = tgbotapi.NewInlineKeyboardButtonData("Добавить группу администраторов", "add_mod") diff --git a/internal/socialmsg/socialmsg.go b/internal/socialmsg/socialmsg.go new file mode 100644 index 0000000..5d1999a --- /dev/null +++ b/internal/socialmsg/socialmsg.go @@ -0,0 +1,27 @@ +package socialmsg + +import ( + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "skbot/internal/functions" + "skbot/pkg/logging" + "strings" +) + +func WithSocialTextQueryDo(update tgbotapi.Update, bot *tgbotapi.BotAPI, logger *logging.Logger) { + + // trim symbols and make slice from text message + if len(update.Message.Text) > 0 { + + command, err := functions.TrimSymbolsFromSlice(strings.Split(update.Message.Text, " ")) + if err != nil { + logger.Info("error trim symbols from message") + } + + switch strings.ToLower(command[0]) { + case "": + + default: + + } + } +} diff --git a/internal/sqlitedb/badwords.db b/internal/sqlitedb/badwords.db new file mode 100755 index 0000000..67af319 Binary files /dev/null and b/internal/sqlitedb/badwords.db differ diff --git a/internal/sqlitedb/newJubileeUsers.db b/internal/sqlitedb/newJubileeUsers.db new file mode 100644 index 0000000..4808e37 Binary files /dev/null and b/internal/sqlitedb/newJubileeUsers.db differ diff --git a/internal/textmsg/textmsg.go b/internal/textmsg/textmsg.go new file mode 100644 index 0000000..8e50268 --- /dev/null +++ b/internal/textmsg/textmsg.go @@ -0,0 +1,227 @@ +package textmsg + +import ( + "fmt" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "log" + "skbot/internal/config" + "skbot/internal/functions" + "skbot/internal/menu" + "skbot/pkg/logging" + "strconv" + "strings" + "time" +) + +func WithTextQueryDo(update tgbotapi.Update, bot *tgbotapi.BotAPI, logger *logging.Logger, modGroupId int64) { + + // trim symbols + if len(update.Message.Text) > 0 { + + command, err := functions.TrimSymbolsFromSlice(strings.Split(update.Message.Text, " ")) + if err != nil { + logger.Info("error trim symbols from message") + } + + // menu + //if strings.Contains(strings.ToLower(command[0]), "меню") { + // + // chatMsgDel := update.Message.MessageID + // + // moderGroupList, err := functions.GetModeratorsGroup() + // if err != nil { + // logger.Error(err) + // } + // + // for _, group := range moderGroupList { + // + // if group.GroupID == update.Message.Chat.ID { + // + // del, _ := bot.Send(tgbotapi.NewMessage(update.Message.Chat.ID, menu.ComMenu)) + // + // go func() { + // time.Sleep(20 * time.Second) + // _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, del.MessageID)) + // _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, chatMsgDel)) + // }() + // } + // } + //} + + // check jubilee users ! + if strings.Contains(strings.ToLower(command[0]), "списокюбилейный") { + + users, err := functions.GetJubileeUsers() + chatId := update.Message.Chat.ID + if err != nil { + logger.Info(err) + } + + moderGroupList, err := functions.GetModeratorsGroup() + if err != nil { + logger.Error(err) + } + + for _, group := range moderGroupList { + + if group.GroupID == chatId { + + for _, user := range users { + + text := fmt.Sprintf("Группа: %s\nИмя: %s\nНик: @%s\nНомер вступления: %d\n"+ + "Время вступления: %s ", user.GroupName, user.UserName, user.UserNick, + user.Serial, user.Time.Format(config.StructDateTimeFormat)) + + _, _ = bot.Send(tgbotapi.NewMessage(chatId, text)) + + } + } + } + } + + // add moderator group + if strings.Contains(strings.ToLower(command[0]), "addmoderatorgroup") { + + if update.Message.Chat.ID == modGroupId { + + newModGroup, err := strconv.ParseInt(command[1], 10, 64) + if err != nil { + logger.Error(err) + } + + b, _, err := functions.AddModeratorsGroup(newModGroup) + if err != nil { + logger.Error(err) + } + + if b && err != nil { + + _, _ = bot.Send(tgbotapi.NewMessage(modGroupId, fmt.Sprintf("Такая группа уже есть: %d", newModGroup))) + } + + if b && err == nil { + + _, _ = bot.Send(tgbotapi.NewMessage(modGroupId, fmt.Sprintf("Успешно добавлена: %d", newModGroup))) + + } + } + } + + // new users count + if strings.Contains(strings.ToLower(command[0]), "chatinfo") { + delMes := update.Message.MessageID + chatId := update.Message.Chat.ID + groupName := update.Message.Chat.Title + + go func() { + _, _ = bot.Send(tgbotapi.NewDeleteMessage(chatId, delMes)) + }() + + _, err = bot.Send(tgbotapi.NewMessage(modGroupId, fmt.Sprintf( + "ID группы: %d\nИмя группы: %s", chatId, groupName))) + if err != nil { + logger.Error(err) + } + } + + // add bad words to the base + if strings.Contains(strings.ToLower(command[0]), "мат") { + + if len(command) > 1 { + + go func() { + time.Sleep(5 * time.Second) + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, update.Message.MessageID)) + + }() + + b, err := functions.AddBadWord(command[1]) + if err != nil { + log.Println(err) + } + + if b == true && err == nil { + + del, _ := bot.Send(tgbotapi.NewMessage(update.Message.Chat.ID, "Уже есть.")) + + go func() { + + time.Sleep(5 * time.Second) + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, del.MessageID)) + + }() + + } else if b == true && err != nil { + + del, _ := bot.Send(tgbotapi.NewMessage(update.Message.Chat.ID, "Добавлено.")) + + go func() { + + time.Sleep(5 * time.Second) + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, del.MessageID)) + }() + + } + } + } + + // check bad words in chat messages + _, b, err := functions.CheckBadWords(command) + if err != nil { + logger.Error("bad words error", err) + } + + // message to chat where found bad word, copy to moderator + if b && strings.ToLower(command[0]) != "мат" { + + msgID := update.Message.MessageID + badText := update.Message.Text + + go func() { + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, msgID)) + }() + + badGuyName := update.Message.From.FirstName + badGuyNick := update.Message.From.UserName + badGuyID := update.Message.From.ID + groupName := update.Message.Chat.Title + + modMess := tgbotapi.NewMessage(modGroupId, fmt.Sprintf( + "Замечены нецензурные выражения:\nГруппа: %s\nИмя пользователя: %s\nНик пользователя: "+ + "@%s\nID пользователя: %d\nТекст сообщения: %s\nОригинал сообщения удален из чата.", + groupName, badGuyName, badGuyNick, badGuyID, badText)) + _, _ = bot.Send(modMess) + + cleanAnswer := tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf( + "Уважаемые коллеги, просим вас воздержаться от нецензурных выражений в %s. "+ + "Сообщение удалено, надеемся на ваше понимание.", groupName)) + del, _ := bot.Send(cleanAnswer) + + go func() { + time.Sleep(30 * time.Second) + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, del.MessageID)) + }() + } + + if strings.Contains(strings.ToLower(command[0]), "меню") { + + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, update.Message.MessageID)) + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, "30 seconds") + + msg.ReplyMarkup = menu.NumericKeyboard + + delMes, err := bot.Send(msg) + if err != nil { + logger.Error(err) + } + + go func() { + time.Sleep(30 * time.Second) + _, _ = bot.Send(tgbotapi.NewDeleteMessage(update.Message.Chat.ID, delMes.MessageID)) + }() + } + + } + +} diff --git a/pkg/client/telegram/client.go b/pkg/client/telegram/client.go new file mode 100755 index 0000000..14f6e08 --- /dev/null +++ b/pkg/client/telegram/client.go @@ -0,0 +1,31 @@ +package telegram + +import ( + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "log" + "skbot/internal/config" + "skbot/pkg/logging" + "time" +) + +func StartBotByChan(cfg *config.Config, logger *logging.Logger) (tgbotapi.UpdatesChannel, *tgbotapi.BotAPI, error) { + + bot, err := tgbotapi.NewBotAPI(cfg.Telegram.Token) + if err != nil { + log.Fatal(err) + } + + bot.Debug = false + + logger.Infof("Bot %s started at: %v", bot.Self.UserName, time.Now().Format("2 January 2006 15:04")) + + u := tgbotapi.NewUpdate(0) + u.Timeout = 60 + u.Limit = 0 + u.Offset = 0 + + updates := bot.GetUpdatesChan(u) + + return updates, bot, nil + +} diff --git a/pkg/logging/logging.go b/pkg/logging/logging.go new file mode 100755 index 0000000..c1a5057 --- /dev/null +++ b/pkg/logging/logging.go @@ -0,0 +1,47 @@ +package logging + +import ( + "fmt" + "github.com/sirupsen/logrus" + "log" + "os" + "path" + "runtime" +) + +type Logger struct { + *logrus.Entry +} + +func (s *Logger) ExtraFields(fields map[string]interface{}) *Logger { + return &Logger{s.WithFields(fields)} +} + +var instance Logger + +func GetLogger(level string) *Logger { + + logrusLevel, err := logrus.ParseLevel(level) + if err != nil { + log.Fatal(err) + } + + l := logrus.New() + l.SetReportCaller(true) + l.Formatter = &logrus.TextFormatter{ + CallerPrettyfier: func(f *runtime.Frame) (string, string) { + filename := path.Base(f.File) + return fmt.Sprintf("%s:%d", filename, f.Line), fmt.Sprintf("%s()", f.Function) + }, + DisableColors: false, + FullTimestamp: true, + } + + l.SetOutput(os.Stdout) + l.SetLevel(logrusLevel) + + instance = Logger{logrus.NewEntry(l)} + + return &instance + +}