diff --git a/lib/chatter/responders.go b/lib/chatter/responders.go index 834e68b..410ec64 100644 --- a/lib/chatter/responders.go +++ b/lib/chatter/responders.go @@ -23,7 +23,7 @@ func (ct *Chatter) GroupsList(update *tgbotapi.Update) string { message += "Telegram ID: " + strconv.FormatInt(groupChats[i].Chat.TelegramID, 10) + "\n" if groupChats[i].ChatRole == "squad" { message += "Статистика отряда:\n" - message += c.Squader.SquadStatictics(groupChats[i].Squad.ID) + message += c.Statistics.SquadStatictics(groupChats[i].Squad.ID) } else if groupChats[i].ChatRole == "flood" { message += "Является флудочатом отряда №" + strconv.Itoa(groupChats[i].Squad.ID) + "\n" } else { diff --git a/lib/config/config.go b/lib/config/config.go index c56ab2a..850f1f5 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -11,7 +11,7 @@ import ( ) // VERSION is the urrent bot's version -const VERSION = "0.51" +const VERSION = "0.6" // DatabaseConnection handles database connection settings in config.yaml type DatabaseConnection struct { diff --git a/lib/dbmapping/players.go b/lib/dbmapping/players.go index fac87bc..8a9ba3f 100644 --- a/lib/dbmapping/players.go +++ b/lib/dbmapping/players.go @@ -16,3 +16,11 @@ type Player struct { CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` } + +// PlayerProfile is a struch which handles all user information +type PlayerProfile struct { + Player Player + Profile Profile + League League + HaveProfile bool +} diff --git a/lib/dbmapping/squads_players.go b/lib/dbmapping/squads_players.go index e849051..3f6d98e 100644 --- a/lib/dbmapping/squads_players.go +++ b/lib/dbmapping/squads_players.go @@ -12,13 +12,15 @@ type SquadPlayer struct { ID int `db:"id"` SquadID int `db:"squad_id"` PlayerID int `db:"player_id"` + UserType string `db:"user_type"` AuthorID int `db:"author_id"` CreatedAt time.Time `db:"created_at"` } // SquadPlayerFull is a struct, which handles all related information type SquadPlayerFull struct { - Squad Squad - Player Player - Profile Profile + Squad SquadChat + Player Player + Profile Profile + UserRole string } diff --git a/lib/migrations/23_add_user_type.go b/lib/migrations/23_add_user_type.go new file mode 100644 index 0000000..5503a37 --- /dev/null +++ b/lib/migrations/23_add_user_type.go @@ -0,0 +1,29 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +// AddUserTypeUp creates `user_type` column in `squads_players` table +func AddUserTypeUp(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE `squads_players` ADD COLUMN `user_type` varchar(191) NOT NULL DEFAULT 'common' COMMENT 'Уровень игрока' AFTER `player_id`;") + if err != nil { + return err + } + + return nil +} + +// AddUserTypeDown destroys `user_type` column +func AddUserTypeDown(tx *sql.Tx) error { + _, err := tx.Exec("ALTER TABLE `squads_players` DROP COLUMN `user_type`;") + if err != nil { + return err + } + + return nil +} diff --git a/lib/migrations/migrations.go b/lib/migrations/migrations.go index 6b5e9d2..695970b 100644 --- a/lib/migrations/migrations.go +++ b/lib/migrations/migrations.go @@ -33,6 +33,7 @@ func (m *Migrations) Init() { goose.AddNamedMigration("20_create_squads.go", CreateSquadsUp, CreateSquadsDown) 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) } // Migrate migrates database to current version diff --git a/lib/router/private_request.go b/lib/router/private_request.go index 47c3937..fef6e4a 100644 --- a/lib/router/private_request.go +++ b/lib/router/private_request.go @@ -15,6 +15,8 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi // Commands with regexps var pokedexMsg = regexp.MustCompile("/pokede(x|ks)\\d?\\z") var pokememeInfoMsg = regexp.MustCompile("/pk(\\d+)") + var usersMsg = regexp.MustCompile("/users\\d?\\z") + var squadInfoMsg = regexp.MustCompile("/show_squad(\\d+)\\z") if update.Message.ForwardFrom != nil { if update.Message.ForwardFrom.ID != 360402625 { @@ -42,7 +44,6 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi case update.Message.Command() == "help": c.Talkers.HelpMessage(update, playerRaw) return "ok" - // Pokememes info case pokedexMsg.MatchString(text): c.Pokedexer.PokememesList(update) return "ok" @@ -85,13 +86,7 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi c.Talkers.AnyMessageUnauthorized(update) return "fail" case update.Message.Command() == "squads": - if c.Users.PlayerBetterThan(playerRaw, "admin") { - c.Squader.SquadsList(update) - return "ok" - } - - c.Talkers.AnyMessageUnauthorized(update) - return "fail" + return c.Squader.SquadsList(update, playerRaw) case update.Message.Command() == "make_squad": if c.Users.PlayerBetterThan(playerRaw, "admin") { return c.Squader.CreateSquad(update) @@ -106,6 +101,22 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi c.Talkers.AnyMessageUnauthorized(update) return "fail" + + case usersMsg.MatchString(text): + if c.Users.PlayerBetterThan(playerRaw, "admin") { + return c.Users.UsersList(update) + } + + c.Talkers.AnyMessageUnauthorized(update) + return "fail" + + case update.Message.Command() == "squad_add_user": + return c.Squader.AddUserToSquad(update, playerRaw) + case update.Message.Command() == "squad_add_commander": + return c.Squader.AddUserToSquad(update, playerRaw) + + case squadInfoMsg.MatchString(text): + return c.Squader.SquadInfo(update, playerRaw) } } } diff --git a/lib/squader/getters.go b/lib/squader/getters.go new file mode 100644 index 0000000..b750aec --- /dev/null +++ b/lib/squader/getters.go @@ -0,0 +1,67 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package squader + +import ( + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" +) + +// GetSquadByID returns squad will all support information +func (s *Squader) GetSquadByID(squadID int) (dbmapping.SquadChat, bool) { + squadFull := dbmapping.SquadChat{} + squad := dbmapping.Squad{} + chat := dbmapping.Chat{} + floodChat := dbmapping.Chat{} + + err := c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE id=?"), squadID) + if err != nil { + c.Log.Error(err) + return squadFull, false + } + + err = c.Db.Get(&chat, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), squad.ChatID) + if err != nil { + c.Log.Error(err) + return squadFull, false + } + err = c.Db.Get(&floodChat, c.Db.Rebind("SELECT * FROM chats WHERE id=?"), squad.FloodChatID) + if err != nil { + c.Log.Error(err) + return squadFull, false + } + + squadFull.Squad = squad + squadFull.Chat = chat + squadFull.FloodChat = floodChat + + return squadFull, true +} + +// GetUserRolesInSquads lists all user roles +func (s *Squader) GetUserRolesInSquads(playerRaw *dbmapping.Player) ([]dbmapping.SquadPlayerFull, bool) { + userRoles := []dbmapping.SquadPlayerFull{} + userRolesRaw := []dbmapping.SquadPlayer{} + + err := c.Db.Select(&userRolesRaw, c.Db.Rebind("SELECT * FROM squads_players WHERE player_id=?"), playerRaw.ID) + if err != nil { + c.Log.Error(err.Error()) + return userRoles, false + } + + for i := range userRolesRaw { + userRoleFull := dbmapping.SquadPlayerFull{} + userRoleFull.Player = *playerRaw + userProfile, profileOk := c.Users.GetProfile(playerRaw.ID) + userRoleFull.Profile = userProfile + userRoleFull.UserRole = userRolesRaw[i].UserType + squad, squadOk := s.GetSquadByID(userRolesRaw[i].SquadID) + userRoleFull.Squad = squad + + if profileOk && squadOk { + userRoles = append(userRoles, userRoleFull) + } + } + + return userRoles, true +} diff --git a/lib/squader/responders.go b/lib/squader/responders.go new file mode 100644 index 0000000..bd7db92 --- /dev/null +++ b/lib/squader/responders.go @@ -0,0 +1,97 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package squader + +import ( + "github.com/go-telegram-bot-api/telegram-bot-api" + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" + "strconv" + "strings" +) + +// SquadsList lists all squads +func (s *Squader) SquadsList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string { + if !c.Users.PlayerBetterThan(playerRaw, "admin") { + if s.isUserAnyCommander(playerRaw.ID) { + c.Talkers.AnyMessageUnauthorized(update) + return "fail" + } + } + squads, ok := s.getAllSquadsWithChats() + if !ok { + return "fail" + } + + message := "*Наши отряды:*\n" + + for i := range squads { + message += "---\n" + message += "[#" + strconv.Itoa(squads[i].Squad.ID) + "] _" + squads[i].Chat.Name + message += "_ /show\\_squad" + strconv.Itoa(squads[i].Squad.ID) + "\n" + message += "Telegram ID: " + strconv.FormatInt(squads[i].Chat.TelegramID, 10) + "\n" + message += "Флудилка отряда: _" + squads[i].FloodChat.Name + "_\n" + message += "Статистика отряда:\n" + message += c.Statistics.SquadStatictics(squads[i].Squad.ID) + } + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) + + return "ok" +} + +// SquadInfo returns statistic and list of squad players +func (s *Squader) SquadInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string { + squadNumber := strings.Replace(update.Message.Text, "/show_squad", "", 1) + squadID, _ := strconv.Atoi(squadNumber) + if squadID == 0 { + squadID = 1 + } + + if !c.Users.PlayerBetterThan(playerRaw, "admin") { + if s.getUserRoleForSquad(squadID, playerRaw.ID) != "commander" { + c.Talkers.AnyMessageUnauthorized(update) + return "fail" + } + } + + squad, ok := s.GetSquadByID(squadID) + if !ok { + c.Talkers.BotError(update) + return "fail" + } + + message := "*Информация об отряде* _" + squad.Chat.Name + "_*:*\n" + message += c.Statistics.SquadStatictics(squad.Squad.ID) + message += "\n" + + squadMembers, ok := s.getPlayersForSquad(squad.Squad.ID) + if !ok { + return "fail" + } + if len(squadMembers) > 0 { + message += "Участники отряда:\n" + for i := range squadMembers { + message += "#" + strconv.Itoa(squadMembers[i].Player.ID) + if squadMembers[i].UserRole == "commander" { + message += " \\[К]" + } + message += " " + squadMembers[i].Profile.Nickname + " " + if squadMembers[i].Profile.TelegramNickname != "" { + message += "(@" + squadMembers[i].Profile.TelegramNickname + ")" + } + message += " ⚔" + strconv.Itoa(squadMembers[i].Profile.Power) + message += "\n" + } + } + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) + + return "ok" +} diff --git a/lib/squader/squader.go b/lib/squader/squader.go index b7b8522..9447a2d 100644 --- a/lib/squader/squader.go +++ b/lib/squader/squader.go @@ -12,6 +12,46 @@ import ( "time" ) +func (s *Squader) getPlayersForSquad(squadID int) ([]dbmapping.SquadPlayerFull, bool) { + players := []dbmapping.SquadPlayerFull{} + playersRaw := []dbmapping.Player{} + squadPlayers := []dbmapping.SquadPlayer{} + + squad, ok := s.GetSquadByID(squadID) + if !ok { + return players, false + } + + err := c.Db.Select(&playersRaw, c.Db.Rebind("SELECT p.* FROM players p, squads_players sp WHERE p.id = sp.player_id AND sp.squad_id=?"), squad.Squad.ID) + if err != nil { + c.Log.Error(err.Error()) + return players, false + } + + err = c.Db.Select(&squadPlayers, c.Db.Rebind("SELECT * FROM squads_players WHERE squad_id=?"), squad.Squad.ID) + if err != nil { + c.Log.Error(err.Error()) + return players, false + } + + for i := range playersRaw { + for ii := range squadPlayers { + if squadPlayers[ii].PlayerID == playersRaw[i].ID { + playerWithProfile := dbmapping.SquadPlayerFull{} + profile, _ := c.Users.GetProfile(playersRaw[i].ID) + playerWithProfile.Profile = profile + playerWithProfile.Player = playersRaw[i] + playerWithProfile.Squad = squad + playerWithProfile.UserRole = squadPlayers[ii].UserType + + players = append(players, playerWithProfile) + } + } + } + + return players, true +} + func (s *Squader) getAllSquadsWithChats() ([]dbmapping.SquadChat, bool) { squadsWithChats := []dbmapping.SquadChat{} squads := []dbmapping.Squad{} @@ -122,6 +162,31 @@ func (s *Squader) getSquadByChatID(update *tgbotapi.Update, chatID int) (dbmappi return squad, "ok" } +func (s *Squader) getUserRoleForSquad(squadID int, playerID int) string { + squadPlayer := dbmapping.SquadPlayer{} + err := c.Db.Get(&squadPlayer, c.Db.Rebind("SELECT * FROM squads_players WHERE squad_id=? AND player_id=?"), squadID, playerID) + if err != nil { + c.Log.Debug(err.Error()) + return "nobody" + } + + return squadPlayer.UserType +} + +func (s *Squader) isUserAnyCommander(playerID int) bool { + squadPlayers := []dbmapping.SquadPlayer{} + err := c.Db.Select(&squadPlayers, c.Db.Rebind("SELECT * FROM squads_players WHERE player_id=?"), playerID) + if err != nil { + c.Log.Debug(err.Error()) + } + + if len(squadPlayers) > 0 { + return true + } + + return false +} + func (s *Squader) squadCreationDuplicate(update *tgbotapi.Update) string { message := "*Отряд уже существует*\n" message += "Проверьте, правильно ли вы ввели команду, и повторите попытку." @@ -158,8 +223,108 @@ func (s *Squader) squadCreationSuccess(update *tgbotapi.Update) string { return "fail" } +func (s *Squader) squadUserAdditionFailure(update *tgbotapi.Update) string { + message := "*Не удалось добавить игрока в отряд*\n" + message += "Проверьте, правильно ли вы ввели команду, и повторите попытку. Кроме того, возможно, что у пользователя нет профиля в боте." + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) + + return "fail" +} + +func (s *Squader) squadUserAdditionSuccess(update *tgbotapi.Update) string { + message := "*Игрок добавлен в отряд*\n" + message += "Теперь вы можете дать ему ссылку для входа в чаты отряда." + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) + + return "ok" +} + // External functions +// AddUserToSquad adds user to squad +func (s *Squader) AddUserToSquad(update *tgbotapi.Update, adderRaw *dbmapping.Player) string { + command := update.Message.Command() + commandArugments := update.Message.CommandArguments() + userType := "user" + if command == "squad_add_commander" { + userType = "commander" + } + argumentsRx := regexp.MustCompile(`(\d+)\s(\d+)`) + if !argumentsRx.MatchString(commandArugments) { + return s.squadUserAdditionFailure(update) + } + + argumentNumbers := strings.Split(commandArugments, " ") + if len(argumentNumbers) < 2 { + return s.squadUserAdditionFailure(update) + } + squadID, _ := strconv.Atoi(argumentNumbers[0]) + if squadID == 0 { + return s.squadUserAdditionFailure(update) + } + playerID, _ := strconv.Atoi(argumentNumbers[1]) + if playerID == 0 { + return s.squadUserAdditionFailure(update) + } + + playerRaw, ok := c.Users.GetPlayerByID(playerID) + if !ok { + return s.squadUserAdditionFailure(update) + } + squadRaw := dbmapping.Squad{} + err := c.Db.Get(&squadRaw, c.Db.Rebind("SELECT * FROM squads WHERE id=?"), squadID) + if err != nil { + c.Log.Error(err.Error()) + return s.squadUserAdditionFailure(update) + } + _, ok = c.Users.GetProfile(playerRaw.ID) + if !ok { + return s.squadUserAdditionFailure(update) + } + + if !c.Users.PlayerBetterThan(adderRaw, "admin") { + if userType == "commander" { + c.Talkers.AnyMessageUnauthorized(update) + return "fail" + } + + if s.getUserRoleForSquad(squadRaw.ID, adderRaw.ID) != "commander" { + c.Talkers.AnyMessageUnauthorized(update) + return "fail" + } + } + + if !c.Users.PlayerBetterThan(&playerRaw, "admin") { + if playerRaw.LeagueID != 1 { + return s.squadUserAdditionFailure(update) + } + } + + // All checks are passed here, creating new item in database + playerSquad := dbmapping.SquadPlayer{} + playerSquad.SquadID = squadRaw.ID + playerSquad.PlayerID = playerRaw.ID + playerSquad.UserType = userType + playerSquad.AuthorID = adderRaw.ID + playerSquad.CreatedAt = time.Now().UTC() + + _, err = c.Db.NamedExec("INSERT INTO squads_players VALUES(NULL, :squad_id, :player_id, :user_type, :author_id, :created_at)", &playerSquad) + if err != nil { + c.Log.Error(err.Error()) + return s.squadUserAdditionFailure(update) + } + + return s.squadUserAdditionSuccess(update) +} + // CreateSquad creates new squad from chat if not already exist func (s *Squader) CreateSquad(update *tgbotapi.Update) string { commandArugments := update.Message.CommandArguments() @@ -191,67 +356,3 @@ func (s *Squader) CreateSquad(update *tgbotapi.Update) string { return s.squadCreationSuccess(update) } - -// SquadsList lists all squads -func (s *Squader) SquadsList(update *tgbotapi.Update) string { - squads, ok := s.getAllSquadsWithChats() - if !ok { - return "fail" - } - - message := "*Наши отряды:*\n" - - for i := range squads { - message += "---\n" - message += "[#" + strconv.Itoa(squads[i].Squad.ID) + "] _" + squads[i].Chat.Name - message += "_ /show\\_squad" + strconv.Itoa(squads[i].Squad.ID) + "\n" - message += "Telegram ID: " + strconv.FormatInt(squads[i].Chat.TelegramID, 10) + "\n" - message += "Флудилка отряда: _" + squads[i].FloodChat.Name + "_\n" - message += "Статистика отряда:\n" - message += s.SquadStatictics(squads[i].Squad.ID) - } - - msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) - msg.ParseMode = "Markdown" - - c.Bot.Send(msg) - - return "ok" -} - -// SquadStatictics generates statistics message snippet. Public due to usage in chats list -func (s *Squader) SquadStatictics(squadID int) string { - squadMembersWithInformation := []dbmapping.SquadPlayerFull{} - squadMembers := []dbmapping.SquadPlayer{} - squad := dbmapping.Squad{} - - err := c.Db.Get(&squad, c.Db.Rebind("SELECT * FROM squads WHERE id=?"), squadID) - if err != nil { - c.Log.Error(err.Error()) - return "Отряда не существует!" - } - - err = c.Db.Select(&squadMembers, c.Db.Rebind("SELECT * FROM squads_players WHERE squad_id=?"), squadID) - if err != nil { - c.Log.Error(err.Error()) - return "Невозможно получить информацию о данном отряде. Возможно, он пуст или произошла ошибка." - } - - for i := range squadMembers { - fullInfo := dbmapping.SquadPlayerFull{} - - playerRaw, _ := c.Users.GetPlayerByID(squadMembers[i].PlayerID) - profileRaw, _ := c.Users.GetProfile(playerRaw.ID) - - fullInfo.Squad = squad - fullInfo.Player = playerRaw - fullInfo.Profile = profileRaw - - squadMembersWithInformation = append(squadMembersWithInformation, fullInfo) - } - - message := "Количество человек в отряде: " + strconv.Itoa(len(squadMembersWithInformation)) - message += "\n" - - return message -} diff --git a/lib/squader/squaderinterface/squaderinterface.go b/lib/squader/squaderinterface/squaderinterface.go index b21aa6c..1809491 100644 --- a/lib/squader/squaderinterface/squaderinterface.go +++ b/lib/squader/squaderinterface/squaderinterface.go @@ -5,12 +5,19 @@ package squaderinterface import ( "github.com/go-telegram-bot-api/telegram-bot-api" + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" ) // SquaderInterface implements Squader for importing via appcontext. type SquaderInterface interface { Init() + + GetSquadByID(squadID int) (dbmapping.SquadChat, bool) + GetUserRolesInSquads(playerRaw *dbmapping.Player) ([]dbmapping.SquadPlayerFull, bool) + + AddUserToSquad(update *tgbotapi.Update, adderRaw *dbmapping.Player) string CreateSquad(update *tgbotapi.Update) string - SquadsList(update *tgbotapi.Update) string - SquadStatictics(squadID int) string + + SquadInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string + SquadsList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string } diff --git a/lib/statistics/squads.go b/lib/statistics/squads.go new file mode 100644 index 0000000..b78cb7a --- /dev/null +++ b/lib/statistics/squads.go @@ -0,0 +1,49 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package statistics + +import ( + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" + "strconv" +) + +// SquadStatictics generates statistics message snippet. Public due to usage in chats list +func (s *Statistics) SquadStatictics(squadID int) string { + squadMembersWithInformation := []dbmapping.SquadPlayerFull{} + squadMembers := []dbmapping.SquadPlayer{} + + squad, ok := c.Squader.GetSquadByID(squadID) + if !ok { + return "Невозможно получить информацию о данном отряде. Возможно, он пуст или произошла ошибка." + } + + err := c.Db.Select(&squadMembers, c.Db.Rebind("SELECT * FROM squads_players WHERE squad_id=?"), squadID) + if err != nil { + c.Log.Error(err.Error()) + return "Невозможно получить информацию о данном отряде. Возможно, он пуст или произошла ошибка." + } + + for i := range squadMembers { + fullInfo := dbmapping.SquadPlayerFull{} + + playerRaw, _ := c.Users.GetPlayerByID(squadMembers[i].PlayerID) + profileRaw, _ := c.Users.GetProfile(playerRaw.ID) + + fullInfo.Squad = squad + fullInfo.Player = playerRaw + fullInfo.Profile = profileRaw + + squadMembersWithInformation = append(squadMembersWithInformation, fullInfo) + } + + message := "Количество человек в отряде: " + strconv.Itoa(len(squadMembersWithInformation)) + "\n" + + summAttack := 0 + for i := range squadMembersWithInformation { + summAttack += squadMembersWithInformation[i].Profile.Power + } + message += "Суммарная атака: " + strconv.Itoa(summAttack) + " очков.\n" + + return message +} diff --git a/lib/statistics/statisticsinterface/statisticinterface.go b/lib/statistics/statisticsinterface/statisticinterface.go index 5e5db3f..b7a7258 100644 --- a/lib/statistics/statisticsinterface/statisticinterface.go +++ b/lib/statistics/statisticsinterface/statisticinterface.go @@ -7,6 +7,8 @@ package statisticsinterface type StatisticsInterface interface { Init() + SquadStatictics(squadID int) string + GetPoints(pointsStr string) int GetPrintablePoints(points int) string diff --git a/lib/talkers/help.go b/lib/talkers/help.go index 4e93a4d..6480d7e 100644 --- a/lib/talkers/help.go +++ b/lib/talkers/help.go @@ -22,6 +22,7 @@ func (t *Talkers) HelpMessage(update *tgbotapi.Update, playerRaw *dbmapping.Play message += "+ /group\\_chats — получить список групп, в которых работает бот.\n" message += "+ /squads — получить список отрядов.\n" message += "+ /pin _текст_ — отправить сообщение во все группы, где находится бот. Сообщение будет автоматически запинено.\n" + message += "+ /users — просмотреть зарегистрированных пользователей бота\n" } message += "+ /help – выводит данное сообщение\n" diff --git a/lib/users/responders.go b/lib/users/responders.go index 307fdad..4b432c7 100644 --- a/lib/users/responders.go +++ b/lib/users/responders.go @@ -7,6 +7,7 @@ import ( "github.com/go-telegram-bot-api/telegram-bot-api" "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" "strconv" + "strings" ) // ProfileMessage shows current player's profile @@ -81,8 +82,28 @@ func (u *Users) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Pla } message += "\nСтоимость покемемов на руках: " + c.Statistics.GetPrintablePoints(profileRaw.PokememesWealth) + "$" message += "\n\n💳" + strconv.Itoa(playerRaw.TelegramID) - message += "\n⏰Последнее обновление профиля: " + profileRaw.CreatedAt.Format("02.01.2006 15:04:05") - message += "\n\nНе забывай обновляться, это важно для получения актуальной информации.\n\n" + + if playerRaw.Status == "owner" { + message += "\n\nСтатус в боте: _владелец_" + } else if playerRaw.Status == "admin" { + message += "\n\nСтатус в боте: _администратор_" + } else { + message += "\n\nСтатус в боте: _игрок_" + } + + squadRoles, ok := c.Squader.GetUserRolesInSquads(playerRaw) + if ok && len(squadRoles) > 0 { + for i := range squadRoles { + if squadRoles[i].UserRole == "commander" { + message += "\nКомандир отряда " + squadRoles[i].Squad.Chat.Name + } else { + message += "\nУчастник отряда " + squadRoles[i].Squad.Chat.Name + } + } + } + + message += "\n\n⏰Последнее обновление профиля: " + profileRaw.CreatedAt.Format("02.01.2006 15:04:05") + message += "\nНе забывай обновляться, это важно для получения актуальной информации.\n\n" message += "/best – посмотреть лучших покемемов для поимки" msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) @@ -92,3 +113,21 @@ func (u *Users) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Pla return "ok" } + +// UsersList lists all known users +func (u *Users) UsersList(update *tgbotapi.Update) string { + pageNumber := strings.Replace(update.Message.Text, "/users", "", 1) + pageNumber = strings.Replace(pageNumber, "/users", "", 1) + page, _ := strconv.Atoi(pageNumber) + if page == 0 { + page = 1 + } + usersArray, ok := u.getUsersWithProfiles() + if !ok { + c.Talkers.BotError(update) + return "fail" + } else { + u.usersList(update, page, usersArray) + return "ok" + } +} diff --git a/lib/users/users.go b/lib/users/users.go index 59940e4..328e4ec 100644 --- a/lib/users/users.go +++ b/lib/users/users.go @@ -5,11 +5,48 @@ package users import ( "github.com/go-telegram-bot-api/telegram-bot-api" + "lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping" + "strconv" ) // Internal functions for Users package -// profileAddSuccessMessage shows profile addition success message +func (u *Users) getUsersWithProfiles() ([]dbmapping.PlayerProfile, bool) { + usersArray := []dbmapping.PlayerProfile{} + players := []dbmapping.Player{} + err := c.Db.Select(&players, "SELECT * FROM players") + if err != nil { + c.Log.Error(err) + return usersArray, false + } + + for i := range players { + playerWithProfile := dbmapping.PlayerProfile{} + profile, ok := u.GetProfile(players[i].ID) + if !ok { + playerWithProfile.HaveProfile = false + } else { + playerWithProfile.HaveProfile = true + } + playerWithProfile.Profile = profile + playerWithProfile.Player = players[i] + + league := dbmapping.League{} + if players[i].LeagueID != 0 { + err = c.Db.Get(&league, c.Db.Rebind("SELECT * FROM leagues WHERE id=?"), players[i].LeagueID) + if err != nil { + c.Log.Error(err.Error()) + return usersArray, false + } + } + playerWithProfile.League = league + + usersArray = append(usersArray, playerWithProfile) + } + + return usersArray, true +} + func (u *Users) profileAddSuccessMessage(update *tgbotapi.Update) { message := "*Профиль успешно обновлен.*\n\n" message += "Функциональность бота держится на актуальности профилей. Обновляйся почаще, и да пребудет с тобой Рандом!\n" @@ -22,7 +59,6 @@ func (u *Users) profileAddSuccessMessage(update *tgbotapi.Update) { c.Bot.Send(msg) } -// profileAddFailureMessage shows profile addition failure message func (u *Users) profileAddFailureMessage(update *tgbotapi.Update) { message := "*Неудачно получилось :(*\n\n" message += "Случилась жуткая ошибка, и мы не смогли записать профиль в базу. Напиши @fat0troll, он разберется." @@ -32,3 +68,51 @@ func (u *Users) profileAddFailureMessage(update *tgbotapi.Update) { c.Bot.Send(msg) } + +func (u *Users) usersList(update *tgbotapi.Update, page int, usersArray []dbmapping.PlayerProfile) { + message := "*Зарегистрированные пользователи бота*\n" + message += "Список отсортирован по ID регистрации.\n" + message += "Количество зарегистрированных пользователей: " + strconv.Itoa(len(usersArray)) + "\n" + message += "Отображаем пользователей с " + strconv.Itoa(((page-1)*25)+1) + " по " + strconv.Itoa(page*25) + "\n" + if len(usersArray) > page*25 { + message += "Переход на следующую страницу: /users" + strconv.Itoa(page+1) + } + if page > 1 { + message += "\nПереход на предыдущую страницу: /users" + strconv.Itoa(page-1) + } + message += "\n\n" + + for i := range usersArray { + if (i+1 > 25*(page-1)) && (i+1 < (25*page)+1) { + message += "#" + strconv.Itoa(usersArray[i].Player.ID) + if usersArray[i].HaveProfile { + message += " " + usersArray[i].League.Symbol + message += " " + usersArray[i].Profile.Nickname + if usersArray[i].Profile.TelegramNickname != "" { + message += " (@" + usersArray[i].Profile.TelegramNickname + ")" + } + message += "\n" + message += "Telegram ID: " + strconv.Itoa(usersArray[i].Player.TelegramID) + "\n" + message += "Последнее обновление: " + usersArray[i].Profile.CreatedAt.Format("02.01.2006 15:04:05") + "\n" + } else { + message += " _без профиля_\n" + message += "Telegram ID: " + strconv.Itoa(usersArray[i].Player.TelegramID) + "\n" + } + } + } + + if len(usersArray) > page*50 { + message += "\n" + message += "Переход на следующую страницу: /users" + strconv.Itoa(page+1) + } + if page > 1 { + message += "\nПереход на предыдущую страницу: /users" + strconv.Itoa(page-1) + } + + message += "\nЧтобы добавить пользователя в отряд, введите команду /squad\\_add\\_user _X Y_ или /squad\\_add\\_commander _X Y_, где _X_ — ID отряда (посмотреть все отряды можно командой /squads), а _Y_ — ID пользователя из списка выше." + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, message) + msg.ParseMode = "Markdown" + + c.Bot.Send(msg) +} diff --git a/lib/users/usersinterface/usersinterface.go b/lib/users/usersinterface/usersinterface.go index 3d62669..5a8af98 100644 --- a/lib/users/usersinterface/usersinterface.go +++ b/lib/users/usersinterface/usersinterface.go @@ -20,4 +20,5 @@ type UsersInterface interface { PlayerBetterThan(playerRaw *dbmapping.Player, powerLevel string) bool ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Player) string + UsersList(update *tgbotapi.Update) string }