From 53a99b0ff355749126034f6fb4511ba1c003582b Mon Sep 17 00:00:00 2001 From: Vladimir Hodakov Date: Sun, 26 Nov 2017 15:28:55 +0400 Subject: [PATCH] Some work on ordering. Special user behaviour See #10 --- cmd/i2_bot/i2_bot.go | 2 + lib/appcontext/appcontext.go | 8 ++ lib/dbmapping/orders.go | 21 +++++ lib/migrations/24_create_orders.go | 51 ++++++++++ lib/migrations/25_remove_reusable.go | 29 ++++++ lib/migrations/migrations.go | 2 + lib/orders/exported.go | 28 ++++++ lib/orders/getters.go | 34 +++++++ lib/orders/orders.go | 94 +++++++++++++++++++ lib/orders/ordersinterface/ordersinterface.go | 21 +++++ lib/orders/responders.go | 44 +++++++++ lib/router/inline.go | 66 +++++++++---- lib/router/private_request.go | 19 ++++ lib/squader/getters.go | 39 ++++++++ .../squaderinterface/squaderinterface.go | 1 + lib/talkers/help.go | 1 + lib/users/getters.go | 2 + lib/users/parsers.go | 8 ++ lib/welcomer/responders.go | 11 +++ .../welcomerinterface/welcomerinterface.go | 1 + 20 files changed, 466 insertions(+), 16 deletions(-) create mode 100644 lib/dbmapping/orders.go create mode 100644 lib/migrations/24_create_orders.go create mode 100644 lib/migrations/25_remove_reusable.go create mode 100644 lib/orders/exported.go create mode 100644 lib/orders/getters.go create mode 100644 lib/orders/orders.go create mode 100644 lib/orders/ordersinterface/ordersinterface.go create mode 100644 lib/orders/responders.go diff --git a/cmd/i2_bot/i2_bot.go b/cmd/i2_bot/i2_bot.go index 3950325..829091e 100644 --- a/cmd/i2_bot/i2_bot.go +++ b/cmd/i2_bot/i2_bot.go @@ -10,6 +10,7 @@ import ( "lab.pztrn.name/fat0troll/i2_bot/lib/chatter" "lab.pztrn.name/fat0troll/i2_bot/lib/forwarder" "lab.pztrn.name/fat0troll/i2_bot/lib/migrations" + "lab.pztrn.name/fat0troll/i2_bot/lib/orders" "lab.pztrn.name/fat0troll/i2_bot/lib/pinner" "lab.pztrn.name/fat0troll/i2_bot/lib/pokedexer" "lab.pztrn.name/fat0troll/i2_bot/lib/router" @@ -42,6 +43,7 @@ func main() { squader.New(c) users.New(c) statistics.New(c) + orders.New(c) c.Log.Info("=======================") c.Log.Info("= i2_bot initialized. =") diff --git a/lib/appcontext/appcontext.go b/lib/appcontext/appcontext.go index 9569709..ae7fbfb 100644 --- a/lib/appcontext/appcontext.go +++ b/lib/appcontext/appcontext.go @@ -13,6 +13,7 @@ import ( "lab.pztrn.name/fat0troll/i2_bot/lib/connections" "lab.pztrn.name/fat0troll/i2_bot/lib/forwarder/forwarderinterface" "lab.pztrn.name/fat0troll/i2_bot/lib/migrations/migrationsinterface" + "lab.pztrn.name/fat0troll/i2_bot/lib/orders/ordersinterface" "lab.pztrn.name/fat0troll/i2_bot/lib/pinner/pinnerinterface" "lab.pztrn.name/fat0troll/i2_bot/lib/pokedexer/pokedexerinterface" "lab.pztrn.name/fat0troll/i2_bot/lib/router/routerinterface" @@ -46,6 +47,7 @@ type Context struct { Squader squaderinterface.SquaderInterface Users usersinterface.UsersInterface Statistics statisticsinterface.StatisticsInterface + Orders ordersinterface.OrdersInterface } // Init is a initialization function for context @@ -153,6 +155,12 @@ func (c *Context) RegisterSquaderInterface(si squaderinterface.SquaderInterface) c.Squader.Init() } +// RegisterOrdersInterface registers orders interface in application +func (c *Context) RegisterOrdersInterface(oi ordersinterface.OrdersInterface) { + c.Orders = oi + c.Orders.Init() +} + // RegisterUsersInterface registers users interface in application func (c *Context) RegisterUsersInterface(ui usersinterface.UsersInterface) { c.Users = ui diff --git a/lib/dbmapping/orders.go b/lib/dbmapping/orders.go new file mode 100644 index 0000000..1d2000f --- /dev/null +++ b/lib/dbmapping/orders.go @@ -0,0 +1,21 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmapping + +import ( + "github.com/go-sql-driver/mysql" + "time" +) + +// Order is a struct, which represents `orders` table item in databse. +type Order struct { + ID int `db:"id"` + Target string `db:"target"` + TargetSquads string `db:"target_squads"` + Scheduled bool `db:"scheduled"` + ScheduledAt mysql.NullTime `db:"scheduled_at"` + Status string `db:"status"` + AuthorID int `db:"author_id"` + CreatedAt time.Time `db:"created_at"` +} diff --git a/lib/migrations/24_create_orders.go b/lib/migrations/24_create_orders.go new file mode 100644 index 0000000..397dcba --- /dev/null +++ b/lib/migrations/24_create_orders.go @@ -0,0 +1,51 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + "database/sql" +) + +// CreateOrdersUp creates `orders` table +func CreateOrdersUp(tx *sql.Tx) error { + request := "CREATE TABLE `orders` (" + request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID приказа'," + request += "`target` varchar(191) NOT NULL COMMENT 'Цель приказа'," + request += "`target_squads` varchar(191) NOT NULL COMMENT 'Отряды, для которых этот приказ действителен'," + request += "`scheduled` bool NOT NULL DEFAULT false COMMENT 'Является ли запланированным'," + request += "`scheduled_at` datetime COMMENT 'Время запланированного пина'," + request += "`reusable` bool NOT NULL DEFAULT true COMMENT 'Можно ли повторить приказ'," + request += "`status` varchar(191) NOT NULL DEFAULT 'new' COMMENT 'Статус приказа'," + request += "`author_id` int(11) NOT NULL COMMENT 'ID автора приказа'," + request += "`created_at` datetime NOT NULL COMMENT 'Добавлен в базу'," + request += "PRIMARY KEY (`id`)," + request += "UNIQUE KEY `id` (`id`)," + request += "KEY `orders_created_at` (`created_at`)" + request += ") ENGINE=InnoDB AUTO_INCREMENT=4201 DEFAULT CHARSET=utf8mb4 COMMENT='Приказы'" + _, err := tx.Exec(request) + if err != nil { + return err + } + + // Fill some default templates to send + _, err = tx.Exec("INSERT INTO `orders` VALUES(NULL, 'M', 'all', false, NULL, true, 'new', 1, NOW())") + if err != nil { + return err + } + _, err = tx.Exec("INSERT INTO `orders` VALUES(NULL, 'O', 'all', false, NULL, true, 'new', 1, NOW())") + if err != nil { + return err + } + + return nil +} + +// CreateOrdersDown drops `chats` table +func CreateOrdersDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `orders`") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/25_remove_reusable.go b/lib/migrations/25_remove_reusable.go new file mode 100644 index 0000000..31930cd --- /dev/null +++ b/lib/migrations/25_remove_reusable.go @@ -0,0 +1,29 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +// RemoveReusableUp removes `reusable` field in `orders` table +func RemoveReusableUp(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE `orders` DROP COLUMN `reusable`") + if err != nil { + return err + } + + return nil +} + +// RemoveReusableDown reverts `reusable` column +func RemoveReusableDown(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE `orders` ADD COLUMN `reusable` bool NOT NULL DEFAULT true COMMENT 'Можно ли повторить приказ' AFTER `scheduled_at") + if err != nil { + return err + } + + return nil +} diff --git a/lib/migrations/migrations.go b/lib/migrations/migrations.go index 695970b..2d1710d 100644 --- a/lib/migrations/migrations.go +++ b/lib/migrations/migrations.go @@ -34,6 +34,8 @@ func (m *Migrations) Init() { goose.AddNamedMigration("21_change_telegram_id_column.go", ChangeTelegramIDColumnUp, ChangeTelegramIDColumnDown) goose.AddNamedMigration("22_add_flood_chat_id.go", AddFloodChatIDUp, AddFloodChatIDDown) goose.AddNamedMigration("23_add_user_type.go", AddUserTypeUp, AddUserTypeDown) + goose.AddNamedMigration("24_create_orders.go", CreateOrdersUp, CreateOrdersDown) + goose.AddNamedMigration("25_remove_reusable.go", RemoveReusableUp, RemoveReusableDown) } // Migrate migrates database to current version diff --git a/lib/orders/exported.go b/lib/orders/exported.go new file mode 100644 index 0000000..b4bfb26 --- /dev/null +++ b/lib/orders/exported.go @@ -0,0 +1,28 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package orders + +import ( + "lab.pztrn.name/fat0troll/i2_bot/lib/appcontext" + "lab.pztrn.name/fat0troll/i2_bot/lib/orders/ordersinterface" +) + +var ( + c *appcontext.Context +) + +// Orders is a function-handling struct for package orders. +type Orders struct{} + +// New is an initialization function for appcontext +func New(ac *appcontext.Context) { + c = ac + o := &Orders{} + c.RegisterOrdersInterface(ordersinterface.OrdersInterface(o)) +} + +// Init is a initialization function for package +func (o *Orders) Init() { + c.Log.Info("Initializing Orders...") +} diff --git a/lib/orders/getters.go b/lib/orders/getters.go new file mode 100644 index 0000000..e3cbace --- /dev/null +++ b/lib/orders/getters.go @@ -0,0 +1,34 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package orders + +import ( + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" +) + +// GetAllOrders returns all orders in database +func (o *Orders) GetAllOrders() ([]dbmapping.Order, bool) { + orders := []dbmapping.Order{} + + err := c.Db.Select(&orders, "SELECT * FROM orders ORDER BY created_at asc") + if err != nil { + c.Log.Error(err) + return orders, false + } + + return orders, true +} + +// GetOrderByID returns single order by ID +func (o *Orders) GetOrderByID(orderID int) (dbmapping.Order, bool) { + order := dbmapping.Order{} + + err := c.Db.Get(&order, c.Db.Rebind("SELECT * FROM orders WHERE id=?"), orderID) + if err != nil { + c.Log.Error(err.Error()) + return order, false + } + + return order, true +} diff --git a/lib/orders/orders.go b/lib/orders/orders.go new file mode 100644 index 0000000..22b8810 --- /dev/null +++ b/lib/orders/orders.go @@ -0,0 +1,94 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package orders + +import ( + "github.com/go-telegram-bot-api/telegram-bot-api" + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" + "strconv" + "strings" +) + +// Internal functions + +func (o *Orders) getOrderByID(orderID int) (dbmapping.Order, bool) { + order := dbmapping.Order{} + + err := c.Db.Get(&order, c.Db.Rebind("SELECT * FROM orders WHERE id=?"), orderID) + if err != nil { + c.Log.Error(err.Error()) + return order, false + } + + return order, true +} + +func (o *Orders) sendOrder(order *dbmapping.Order) string { + targetChats := []dbmapping.Chat{} + ok := false + + if order.TargetSquads == "all" { + targetChats, ok = c.Squader.GetAllSquadChats() + if !ok { + return "fail" + } + } else { + targetChats, ok = c.Squader.GetSquadChatsBySquadsIDs(order.TargetSquads) + if !ok { + return "fail" + } + } + + for i := range targetChats { + message := "Поступил приказ:" + + msg := tgbotapi.NewMessage(targetChats[i].TelegramID, message) + keyboard := tgbotapi.InlineKeyboardMarkup{} + var row []tgbotapi.InlineKeyboardButton + btn := tgbotapi.NewInlineKeyboardButtonSwitch("В атаку!", strconv.Itoa(order.ID)) + row = append(row, btn) + keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, row) + + msg.ReplyMarkup = keyboard + msg.ParseMode = "Markdown" + + pinnableMessage, err := c.Bot.Send(msg) + if err != nil { + c.Log.Error(err.Error()) + } else { + pinChatMessageConfig := tgbotapi.PinChatMessageConfig{ + ChatID: pinnableMessage.Chat.ID, + MessageID: pinnableMessage.MessageID, + DisableNotification: true, + } + + _, err = c.Bot.PinChatMessage(pinChatMessageConfig) + if err != nil { + c.Log.Error(err.Error()) + } + } + } + + return "ok" +} + +// External functions + +// SendOrder sends order to selected or all squads +func (o *Orders) SendOrder(update *tgbotapi.Update) string { + command := update.Message.Command() + orderNumber := strings.TrimPrefix(command, "send_order") + orderID, _ := strconv.Atoi(orderNumber) + + if orderID == 0 { + return "fail" + } + + order, ok := o.getOrderByID(orderID) + if !ok { + return "fail" + } + + return o.sendOrder(&order) +} diff --git a/lib/orders/ordersinterface/ordersinterface.go b/lib/orders/ordersinterface/ordersinterface.go new file mode 100644 index 0000000..7af8853 --- /dev/null +++ b/lib/orders/ordersinterface/ordersinterface.go @@ -0,0 +1,21 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package ordersinterface + +import ( + "github.com/go-telegram-bot-api/telegram-bot-api" + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" +) + +// OrdersInterface implements Orders for importing via appcontext. +type OrdersInterface interface { + Init() + + GetAllOrders() ([]dbmapping.Order, bool) + GetOrderByID(orderID int) (dbmapping.Order, bool) + + ListAllOrders(update *tgbotapi.Update) string + + SendOrder(update *tgbotapi.Update) string +} diff --git a/lib/orders/responders.go b/lib/orders/responders.go new file mode 100644 index 0000000..3001340 --- /dev/null +++ b/lib/orders/responders.go @@ -0,0 +1,44 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package orders + +import ( + "github.com/go-telegram-bot-api/telegram-bot-api" + "strconv" +) + +// ListAllOrders returns to user all orders in database +func (o *Orders) ListAllOrders(update *tgbotapi.Update) string { + orders, ok := o.GetAllOrders() + if !ok { + return "fail" + } + + message := "*Приказы на атаку*\n" + for i := range orders { + message += "\\[" + strconv.Itoa(orders[i].ID) + "] " + orders[i].TargetSquads + " → " + if orders[i].Target == "M" { + message += "🈳 МИСТИКА " + } else { + message += "🈵 ОТВАГА " + } + if orders[i].Scheduled { + message += "запланировано на " + message += orders[i].ScheduledAt.Time.Format("02.01.2006 15:04:05") + } + if orders[i].Status == "sent" { + message += "\nПросмотреть выполнение приказа: /show\\_order" + strconv.Itoa(orders[i].ID) + } else { + message += "\nОтправить приказ прямо сейчас: /send\\_order" + strconv.Itoa(orders[i].ID) + } + message += "\n" + } + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) + + return "ok" +} diff --git a/lib/router/inline.go b/lib/router/inline.go index d037a32..a330e01 100644 --- a/lib/router/inline.go +++ b/lib/router/inline.go @@ -5,31 +5,65 @@ package router import ( "github.com/go-telegram-bot-api/telegram-bot-api" + "strconv" "strings" ) // RouteInline routes inline requests to bot func (r *Router) RouteInline(update *tgbotapi.Update) string { - availableCommands := make(map[string]string) - availableCommands["0"] = "🌲Лес" - availableCommands["1"] = "⛰Горы" - availableCommands["2"] = "🚣Озеро" - availableCommands["3"] = "🏙Город" - availableCommands["4"] = "🏛Катакомбы" - availableCommands["5"] = "⛪️Кладбище" - outputCommands := make(map[string]string) - for i, value := range availableCommands { - if strings.Contains(value, update.InlineQuery.Query) { - outputCommands[i] = value - } + playerRaw, ok := c.Users.GetOrCreatePlayer(update.InlineQuery.From.ID) + if !ok { + return "fail" } results := make([]interface{}, 0) - for i, value := range outputCommands { - article := tgbotapi.NewInlineQueryResultArticle(i, "Команда боту @PokememBroBot:", value) - article.Description = value + + if playerRaw.LeagueID != 1 { + article := tgbotapi.NewInlineQueryResultArticle("0", "Команда боту @PokememBroBot:", "👤Герой") + article.Description = "👤Герой" results = append(results, article) + } else { + orderNumber, _ := strconv.Atoi(update.InlineQuery.Query) + if orderNumber != 0 { + order, ok := c.Orders.GetOrderByID(orderNumber) + if !ok { + return "fail" + } + + attackTarget := "" + if order.Target == "M" { + attackTarget = "⚔ 🈳 МИСТИКА" + } else { + attackTarget = "⚔ 🈵 ОТВАГА" + } + + article := tgbotapi.NewInlineQueryResultArticle(strconv.Itoa(orderNumber), "Выполнить приказ отряда:", attackTarget) + article.Description = attackTarget + + results = append(results, article) + } else { + availableCommands := make(map[string]string) + availableCommands["10"] = "🌲Лес" + availableCommands["11"] = "⛰Горы" + availableCommands["12"] = "🚣Озеро" + availableCommands["13"] = "🏙Город" + availableCommands["14"] = "🏛Катакомбы" + availableCommands["15"] = "⛪️Кладбище" + outputCommands := make(map[string]string) + for i, value := range availableCommands { + if strings.Contains(value, update.InlineQuery.Query) { + outputCommands[i] = value + } + } + + for i, value := range outputCommands { + article := tgbotapi.NewInlineQueryResultArticle(i, "Команда боту @PokememBroBot:", value) + article.Description = value + + results = append(results, article) + } + } } inlineConf := tgbotapi.InlineConfig{ @@ -44,5 +78,5 @@ func (r *Router) RouteInline(update *tgbotapi.Update) string { c.Log.Error(err.Error()) } - return "fail" + return "ok" } diff --git a/lib/router/private_request.go b/lib/router/private_request.go index 848041c..1b41d2d 100644 --- a/lib/router/private_request.go +++ b/lib/router/private_request.go @@ -17,6 +17,7 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi var pokememeInfoMsg = regexp.MustCompile("/pk(\\d+)") var usersMsg = regexp.MustCompile("/users\\d?\\z") var squadInfoMsg = regexp.MustCompile("/show_squad(\\d+)\\z") + var orderSendMsg = regexp.MustCompile("/send_order(\\d+)\\z") if update.Message.ForwardFrom != nil { if update.Message.ForwardFrom.ID != 360402625 { @@ -34,6 +35,11 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi switch { case update.Message.Command() == "start": if playerRaw.LeagueID != 0 { + if playerRaw.Status == "special" { + c.Welcomer.PrivateWelcomeMessageSpecial(update, playerRaw) + return "ok" + } + c.Welcomer.PrivateWelcomeMessageAuthorized(update, playerRaw) return "ok" } @@ -108,6 +114,19 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi return c.Talkers.AnyMessageUnauthorized(update) + case update.Message.Command() == "orders": + if c.Users.PlayerBetterThan(playerRaw, "admin") { + return c.Orders.ListAllOrders(update) + } + + return c.Talkers.AnyMessageUnauthorized(update) + case orderSendMsg.MatchString(text): + if c.Users.PlayerBetterThan(playerRaw, "admin") { + return c.Orders.SendOrder(update) + } + + return c.Talkers.AnyMessageUnauthorized(update) + case usersMsg.MatchString(text): if c.Users.PlayerBetterThan(playerRaw, "admin") { return c.Users.UsersList(update) diff --git a/lib/squader/getters.go b/lib/squader/getters.go index 00e46c6..2514b1e 100644 --- a/lib/squader/getters.go +++ b/lib/squader/getters.go @@ -5,6 +5,8 @@ package squader import ( "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" + "strconv" + "strings" ) // GetSquadByID returns squad will all support information @@ -77,6 +79,43 @@ func (s *Squader) GetAllSquadFloodChats() ([]dbmapping.Chat, bool) { return groupChats, true } +// GetSquadChatsBySquadsIDs returns main squad chats for given squads IDs +func (s *Squader) GetSquadChatsBySquadsIDs(squadsIDs string) ([]dbmapping.Chat, bool) { + groupChats := []dbmapping.Chat{} + + squadsIDsArray := strings.Split(squadsIDs, ",") + if len(squadsIDsArray) < 1 { + return groupChats, false + } + + sIDs := make([]int, 0) + for i := range squadsIDsArray { + sID, _ := strconv.Atoi(squadsIDsArray[i]) + if sID != 0 { + sIDs = append(sIDs, sID) + } + } + if len(sIDs) < 1 { + return groupChats, false + } + + queryLine := "" + for i := range sIDs { + queryLine += strconv.Itoa(sIDs[i]) + if i < len(sIDs)-1 { + queryLine += "," + } + } + + err := c.Db.Select(&groupChats, "SELECT ch.* FROM chats ch, squads s WHERE s.chat_id=ch.id AND s.id IN ("+queryLine+")") + if err != nil { + c.Log.Error(err) + return groupChats, false + } + + return groupChats, true +} + // GetUserRolesInSquads lists all user roles func (s *Squader) GetUserRolesInSquads(playerRaw *dbmapping.Player) ([]dbmapping.SquadPlayerFull, bool) { userRoles := []dbmapping.SquadPlayerFull{} diff --git a/lib/squader/squaderinterface/squaderinterface.go b/lib/squader/squaderinterface/squaderinterface.go index eda5ab5..492f6d6 100644 --- a/lib/squader/squaderinterface/squaderinterface.go +++ b/lib/squader/squaderinterface/squaderinterface.go @@ -16,6 +16,7 @@ type SquaderInterface interface { GetAllSquadFloodChats() ([]dbmapping.Chat, bool) GetAvailableSquadChatsForUser(playerRaw *dbmapping.Player) ([]dbmapping.Chat, bool) GetSquadByID(squadID int) (dbmapping.SquadChat, bool) + GetSquadChatsBySquadsIDs(squadsID string) ([]dbmapping.Chat, bool) GetUserRolesInSquads(playerRaw *dbmapping.Player) ([]dbmapping.SquadPlayerFull, bool) IsChatASquadEnabled(chatRaw *dbmapping.Chat) string diff --git a/lib/talkers/help.go b/lib/talkers/help.go index f4efaae..9965ac0 100644 --- a/lib/talkers/help.go +++ b/lib/talkers/help.go @@ -24,6 +24,7 @@ func (t *Talkers) HelpMessage(update *tgbotapi.Update, playerRaw *dbmapping.Play message += "+ /squads — получить список отрядов.\n" message += "+ /pin _номера чатов_ _текст_ — отправить сообщение в чаты с номерами. Сообщение будет автоматичекси запинено. Пример: \"/pin 2,3,5 привет мир\". Внимание: между номерами чатов ставятся запятые без пробелов! Всё, что идёт после второго пробела в команде — сообщение\n" message += "+ /pin\\_all _текст_ — отправить сообщение во все группы, где находится бот. Сообщение будет автоматически запинено.\n" + message += "+ /orders — просмотреть приказы на атаку\n" message += "+ /users — просмотреть зарегистрированных пользователей бота\n" } message += "+ /help – выводит данное сообщение\n" diff --git a/lib/users/getters.go b/lib/users/getters.go index 2defd16..ff7b8c3 100644 --- a/lib/users/getters.go +++ b/lib/users/getters.go @@ -64,6 +64,8 @@ func (u *Users) GetOrCreatePlayer(telegramID int) (dbmapping.Player, bool) { func (u *Users) PlayerBetterThan(playerRaw *dbmapping.Player, powerLevel string) bool { var isBetter = false switch playerRaw.Status { + case "special": + isBetter = true case "owner": isBetter = true case "admin": diff --git a/lib/users/parsers.go b/lib/users/parsers.go index aef2417..3acf049 100644 --- a/lib/users/parsers.go +++ b/lib/users/parsers.go @@ -87,6 +87,14 @@ func (u *Users) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Playe } } } + if strings.HasPrefix(currentString, "id: ") { + realUserID := strings.TrimPrefix(currentString, "id: ") + c.Log.Debug("Profile user ID: " + realUserID) + realUID, _ := strconv.Atoi(realUserID) + if realUID != playerRaw.TelegramID { + return "fail" + } + } if strings.HasPrefix(currentString, "👤Уровень:") { levelRx := regexp.MustCompile("\\d+") levelArray := levelRx.FindAllString(currentString, -1) diff --git a/lib/welcomer/responders.go b/lib/welcomer/responders.go index 0f67341..aa703d3 100644 --- a/lib/welcomer/responders.go +++ b/lib/welcomer/responders.go @@ -32,6 +32,17 @@ func (w *Welcomer) PrivateWelcomeMessageAuthorized(update *tgbotapi.Update, play c.Bot.Send(msg) } +// PrivateWelcomeMessageSpecial greets existing user with `special` access +func (w *Welcomer) PrivateWelcomeMessageSpecial(update *tgbotapi.Update, playerRaw *dbmapping.Player) { + message := "*Бот Инстинкта приветствует тебя. Снова.*\n\n" + message += "Привет, " + update.Message.From.FirstName + " " + update.Message.From.LastName + "!\n" + message += "\nБудь аккуратен, суперюзер!" + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) +} + // GroupWelcomeMessage welcomes new user on group or bot itself func (w *Welcomer) GroupWelcomeMessage(update *tgbotapi.Update) string { newUsers := *update.Message.NewChatMembers diff --git a/lib/welcomer/welcomerinterface/welcomerinterface.go b/lib/welcomer/welcomerinterface/welcomerinterface.go index 9d60e75..aff9e43 100644 --- a/lib/welcomer/welcomerinterface/welcomerinterface.go +++ b/lib/welcomer/welcomerinterface/welcomerinterface.go @@ -14,5 +14,6 @@ type WelcomerInterface interface { PrivateWelcomeMessageUnauthorized(update *tgbotapi.Update) PrivateWelcomeMessageAuthorized(update *tgbotapi.Update, playerRaw *dbmapping.Player) + PrivateWelcomeMessageSpecial(update *tgbotapi.Update, playerRaw *dbmapping.Player) GroupWelcomeMessage(update *tgbotapi.Update) string }