diff --git a/cron/cron.go b/cron/cron.go index 3186b60..51b3fd1 100644 --- a/cron/cron.go +++ b/cron/cron.go @@ -32,7 +32,7 @@ func Attach(c *cron.Cron, cfg Config) { } c.AddFunc("@every 1m", h.checkLastEnnoblements) c.AddFunc("@every 30m", h.checkBotMembershipOnServers) - c.AddFunc("@every 2h", h.deleteClosedTribalWarsServers) + c.AddFunc("@every 2h10m", h.deleteClosedTribalWarsServers) go func() { h.checkBotMembershipOnServers() h.deleteClosedTribalWarsServers() diff --git a/cron/handler.go b/cron/handler.go index 64f1bb3..8212929 100644 --- a/cron/handler.go +++ b/cron/handler.go @@ -25,10 +25,10 @@ type handler struct { api *sdk.SDK } -func (h *handler) loadEnnoblements(worlds []string) map[string]ennoblements { +func (h *handler) loadEnnoblements(servers []string) map[string]ennoblements { m := make(map[string]ennoblements) - for _, w := range worlds { + for _, w := range servers { es, err := h.api.LiveEnnoblements.Browse(w, &sdk.LiveEnnoblementInclude{ NewOwner: true, Village: true, @@ -47,7 +47,7 @@ func (h *handler) loadEnnoblements(worlds []string) map[string]ennoblements { lastEnnoblementAt, ok := h.lastEnnoblementAt[w] if !ok { - lastEnnoblementAt = time.Now().Add(-1 * time.Minute) + lastEnnoblementAt = time.Now().Add(-60 * time.Minute) } m[w] = filterEnnoblements(es, lastEnnoblementAt) @@ -62,11 +62,11 @@ func (h *handler) loadEnnoblements(worlds []string) map[string]ennoblements { return m } -func (h *handler) loadLangVersions(worlds []string) map[shared_models.LanguageTag]*shared_models.LangVersion { +func (h *handler) loadLangVersions(servers []string) map[shared_models.LanguageTag]*shared_models.LangVersion { languageTags := []shared_models.LanguageTag{} cache := make(map[shared_models.LanguageTag]bool) - for _, world := range worlds { - languageTag := utils.LanguageTagFromWorldName(world) + for _, server := range servers { + languageTag := utils.LanguageTagFromWorldName(server) if languageTag.IsValid() && !cache[languageTag] { cache[languageTag] = true languageTags = append(languageTags, languageTag) @@ -89,6 +89,8 @@ func (h *handler) loadLangVersions(worlds []string) map[shared_models.LanguageTa } func (h *handler) checkLastEnnoblements() { + start := time.Now() + servers, err := h.observationRepo.FetchServers(context.Background()) if err != nil { log.Print("checkLastEnnoblements error: " + err.Error()) @@ -120,19 +122,14 @@ func (h *handler) checkLastEnnoblements() { group.Observations.Contains(observation.Server, ennoblement.NewOwner.Tribe.ID) { continue } - newMsgDataConfig := newMessageDataConfig{ + newMsgDataConfig := newMessageConfig{ host: langVersion.Host, - world: observation.Server, + server: observation.Server, ennoblement: ennoblement, + t: messageTypeLost, } - msgData := newMessageData(newMsgDataConfig) - h.discord.SendEmbed(group.LostVillagesChannelID, - discord. - NewEmbed(). - SetTitle("Stracona wioska"). - AddField(msgData.world, formatMsgAboutVillageLost(msgData)). - SetTimestamp(msgData.date). - MessageEmbed) + msg := newMessage(newMsgDataConfig) + h.discord.SendEmbed(group.LostVillagesChannelID, msg.toEmbed()) } } @@ -142,24 +139,21 @@ func (h *handler) checkLastEnnoblements() { group.Observations.Contains(observation.Server, ennoblement.OldOwner.Tribe.ID) { continue } - newMsgDataConfig := newMessageDataConfig{ + newMsgDataConfig := newMessageConfig{ host: langVersion.Host, - world: observation.Server, + server: observation.Server, ennoblement: ennoblement, + t: messageTypeConquer, } - msgData := newMessageData(newMsgDataConfig) - h.discord.SendEmbed(group.ConqueredVillagesChannelID, - discord. - NewEmbed(). - SetTitle("Podbita wioska"). - AddField(msgData.world, formatMsgAboutVillageConquest(msgData)). - SetTimestamp(msgData.date). - MessageEmbed) + msg := newMessage(newMsgDataConfig) + h.discord.SendEmbed(group.ConqueredVillagesChannelID, msg.toEmbed()) } } } } } + + log.Printf("checkLastEnnoblements: finished in %s", time.Since(start).String()) } func (h *handler) checkBotMembershipOnServers() { diff --git a/cron/helpers.go b/cron/helpers.go index 3bc46d3..c576275 100644 --- a/cron/helpers.go +++ b/cron/helpers.go @@ -1,6 +1,7 @@ package cron import ( + "fmt" "time" shared_models "github.com/tribalwarshelp/shared/models" @@ -33,10 +34,9 @@ func formatDateOfConquest(t time.Time) string { return t.Format(time.RFC3339) } -func getLocation(timezone string) *time.Location { - loc, err := time.LoadLocation(timezone) - if err != nil { - return time.UTC +func formatMsgLink(text string, url string) string { + if url == "" { + return text } - return loc + return fmt.Sprintf("[``%s``](%s)", text, url) } diff --git a/cron/message.go b/cron/message.go index 4d9cbea..2ddf3b3 100644 --- a/cron/message.go +++ b/cron/message.go @@ -3,18 +3,24 @@ package cron import ( "fmt" + "github.com/bwmarrin/discordgo" + "github.com/tribalwarshelp/dcbot/discord" "github.com/tribalwarshelp/dcbot/utils" shared_models "github.com/tribalwarshelp/shared/models" ) +type messageType string + const ( - endpointTribeProfile = "/game.php?screen=info_ally&id=%d" - endpointPlayerProfile = "/game.php?screen=info_player&id=%d" - endpointVillageProfile = "/game.php?screen=info_village&id=%d" + messageTypeConquer messageType = "conquer" + messageTypeLost messageType = "lost" + colorLostVillage = 0xff0000 + colorConqueredVillage = 0x00ff00 ) -type messageData struct { - world string +type message struct { + t messageType + server string date string village string villageURL string @@ -28,16 +34,18 @@ type messageData struct { newOwnerTribeTag string } -type newMessageDataConfig struct { +type newMessageConfig struct { + t messageType host string - world string + server string ennoblement *shared_models.LiveEnnoblement } -func newMessageData(cfg newMessageDataConfig) messageData { - data := messageData{ +func newMessage(cfg newMessageConfig) message { + data := message{ + t: cfg.t, date: formatDateOfConquest(cfg.ennoblement.EnnobledAt), - world: cfg.world, + server: cfg.server, village: "-", oldOwnerName: "-", oldOwnerTribeTag: "-", @@ -50,48 +58,61 @@ func newMessageData(cfg newMessageDataConfig) messageData { cfg.ennoblement.Village.X, cfg.ennoblement.Village.Y, cfg.ennoblement.Village.Continent()) - data.villageURL = utils.FormatVillageURL(cfg.world, cfg.host, cfg.ennoblement.Village.ID) + data.villageURL = utils.FormatVillageURL(cfg.server, cfg.host, cfg.ennoblement.Village.ID) } if !isPlayerNil(cfg.ennoblement.OldOwner) { data.oldOwnerName = cfg.ennoblement.OldOwner.Name - data.oldOwnerURL = utils.FormatPlayerURL(cfg.world, cfg.host, cfg.ennoblement.OldOwner.ID) + data.oldOwnerURL = utils.FormatPlayerURL(cfg.server, cfg.host, cfg.ennoblement.OldOwner.ID) } if !isPlayerTribeNil(cfg.ennoblement.OldOwner) { data.oldOwnerTribeTag = cfg.ennoblement.OldOwner.Tribe.Tag - data.oldOwnerTribeURL = utils.FormatTribeURL(cfg.world, cfg.host, cfg.ennoblement.OldOwner.Tribe.ID) + data.oldOwnerTribeURL = utils.FormatTribeURL(cfg.server, cfg.host, cfg.ennoblement.OldOwner.Tribe.ID) } if !isPlayerNil(cfg.ennoblement.NewOwner) { data.newOwnerName = cfg.ennoblement.NewOwner.Name - data.newOwnerURL = utils.FormatPlayerURL(cfg.world, cfg.host, cfg.ennoblement.NewOwner.ID) + data.newOwnerURL = utils.FormatPlayerURL(cfg.server, cfg.host, cfg.ennoblement.NewOwner.ID) } if !isPlayerTribeNil(cfg.ennoblement.NewOwner) { data.newOwnerTribeTag = cfg.ennoblement.NewOwner.Tribe.Tag - data.newOwnerTribeURL = utils.FormatTribeURL(cfg.world, cfg.host, cfg.ennoblement.NewOwner.Tribe.ID) + data.newOwnerTribeURL = utils.FormatTribeURL(cfg.server, cfg.host, cfg.ennoblement.NewOwner.Tribe.ID) } + return data } -func formatMsgLink(text string, url string) string { - if url == "" { - return text - } - return fmt.Sprintf("[``%s``](%s)", text, url) -} - -func formatMsgAboutVillageLost(msgData messageData) string { +func (msg message) formatMsgAboutVillageLost() string { return fmt.Sprintf(`Wioska %s gracza %s (%s) została stracona na rzecz %s (%s)`, - formatMsgLink(msgData.village, msgData.villageURL), - formatMsgLink(msgData.oldOwnerName, msgData.oldOwnerURL), - formatMsgLink(msgData.oldOwnerTribeTag, msgData.oldOwnerTribeURL), - formatMsgLink(msgData.newOwnerName, msgData.newOwnerURL), - formatMsgLink(msgData.newOwnerTribeTag, msgData.newOwnerTribeURL)) + formatMsgLink(msg.village, msg.villageURL), + formatMsgLink(msg.oldOwnerName, msg.oldOwnerURL), + formatMsgLink(msg.oldOwnerTribeTag, msg.oldOwnerTribeURL), + formatMsgLink(msg.newOwnerName, msg.newOwnerURL), + formatMsgLink(msg.newOwnerTribeTag, msg.newOwnerTribeURL)) } -func formatMsgAboutVillageConquest(msgData messageData) string { +func (msg message) formatMsgAboutVillageConquest() string { return fmt.Sprintf("Gracz %s (%s) podbił wioskę %s od gracza %s (%s)", - formatMsgLink(msgData.newOwnerName, msgData.newOwnerURL), - formatMsgLink(msgData.newOwnerTribeTag, msgData.newOwnerTribeURL), - formatMsgLink(msgData.village, msgData.villageURL), - formatMsgLink(msgData.oldOwnerName, msgData.oldOwnerURL), - formatMsgLink(msgData.oldOwnerTribeTag, msgData.oldOwnerTribeURL)) + formatMsgLink(msg.newOwnerName, msg.newOwnerURL), + formatMsgLink(msg.newOwnerTribeTag, msg.newOwnerTribeURL), + formatMsgLink(msg.village, msg.villageURL), + formatMsgLink(msg.oldOwnerName, msg.oldOwnerURL), + formatMsgLink(msg.oldOwnerTribeTag, msg.oldOwnerTribeURL)) +} + +func (msg message) toEmbed() *discordgo.MessageEmbed { + title := "Podbita wioska" + fieldContent := msg.formatMsgAboutVillageConquest() + color := colorConqueredVillage + if msg.t == messageTypeLost { + title = "Stracona wioska" + fieldContent = msg.formatMsgAboutVillageLost() + color = colorLostVillage + } + + return discord. + NewEmbed(). + SetTitle(title). + AddField(msg.server, fieldContent). + SetTimestamp(msg.date). + SetColor(color). + MessageEmbed } diff --git a/discord/commands.go b/discord/admin_commands.go similarity index 57% rename from discord/commands.go rename to discord/admin_commands.go index be4daff..0af833a 100644 --- a/discord/commands.go +++ b/discord/admin_commands.go @@ -3,15 +3,11 @@ package discord import ( "context" "fmt" - "math" "strconv" - shared_models "github.com/tribalwarshelp/shared/models" - "github.com/bwmarrin/discordgo" "github.com/tribalwarshelp/dcbot/models" - "github.com/tribalwarshelp/dcbot/utils" - "github.com/tribalwarshelp/golang-sdk/sdk" + shared_models "github.com/tribalwarshelp/shared/models" ) const ( @@ -19,10 +15,7 @@ const ( GroupsPerServer = 5 ) -type Command string - const ( - HelpCommand Command = "help" AddGroupCommand Command = "addgroup" DeleteGroupCommand Command = "deletegroup" GroupsCommand Command = "groups" @@ -33,235 +26,8 @@ const ( UnObserveLostVillagesCommand Command = "unobservelostvillages" ConqueredVillagesCommand Command = "conqueredvillages" UnObserveConqueredVillagesCommand Command = "unobserveconqueredvillages" - TribeCommand Command = "tribe" - TopAttCommand Command = "topatt" - TopDefCommand Command = "topdef" - TopSuppCommand Command = "topsupp" - TopTotalCommand Command = "toptotal" - TopPointsCommand Command = "toppoints" - AuthorCommand Command = "author" ) -func (cmd Command) String() string { - return string(cmd) -} - -func (cmd Command) WithPrefix(prefix string) string { - return prefix + cmd.String() -} - -func (s *Session) handleHelpCommand(m *discordgo.MessageCreate) { - tribeCMDWithPrefix := TribeCommand.WithPrefix(s.cfg.CommandPrefix) - commandsForAll := fmt.Sprintf(` -- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największym RA z plemion o podanych id -- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największym RO z plemion o podanych id -- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największym RW z plemion o podanych id -- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największej liczbie pokonanych z plemion o podanych id -- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największej liczbie punktów z plemion o podanych id -- **%s** - kontakt z autorem bota - `, - tribeCMDWithPrefix, - TopAttCommand.String(), - tribeCMDWithPrefix, - TopDefCommand.String(), - tribeCMDWithPrefix, - TopSuppCommand.String(), - tribeCMDWithPrefix, - TopTotalCommand.String(), - tribeCMDWithPrefix, - TopPointsCommand.String(), - AuthorCommand.WithPrefix(s.cfg.CommandPrefix), - ) - - commandsForGuildAdmins := fmt.Sprintf(` -- **%s** - tworzy nową grupę -- **%s** - usuwa grupę -- **%s** - lista grup -- **%s** [id grupy z %s] [świat] [id plemienia] - dodaje plemię z danego świata do obserwowanych -- **%s** [id grupy z %s] - wyświetla wszystkie obserwowane plemiona -- **%s** [id grupy z %s] [id z %s] - usuwa plemię z obserwowanych -- **%s** [id grupy z %s] - ustawia kanał na którym będą wyświetlać się informacje o podbitych wioskach -- **%s** [id grupy z %s] - informacje o podbitych wioskach na wybranym kanale nie będą się już pojawiały -- **%s** [id grupy z %s] - ustawia kanał na którym będą wyświetlać się informacje o straconych wioskach -- **%s** [id grupy z %s] - informacje o straconych wioskach na wybranym kanale nie będą się już pojawiały - `, - AddGroupCommand.WithPrefix(s.cfg.CommandPrefix), - DeleteGroupCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - ObserveCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - ObservationsCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - UnObserveCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - ObservationsCommand.WithPrefix(s.cfg.CommandPrefix), - ConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - UnObserveConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - LostVillagesCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - UnObserveLostVillagesCommand.WithPrefix(s.cfg.CommandPrefix), - GroupsCommand.WithPrefix(s.cfg.CommandPrefix), - ) - - s.SendEmbed(m.ChannelID, NewEmbed(). - SetTitle("Pomoc"). - SetDescription("Komendy oferowane przez bota"). - AddField("Dla wszystkich", commandsForAll). - AddField("Dla adminów", commandsForGuildAdmins). - MessageEmbed) -} - -func (s *Session) handleAuthorCommand(m *discordgo.MessageCreate) { - s.SendMessage(m.ChannelID, fmt.Sprintf("%s Discord: Kichiyaki#2064.", m.Author.Mention())) -} - -func (s *Session) handleTribeCommand(m *discordgo.MessageCreate, args ...string) { - argsLength := len(args) - if argsLength < 4 { - s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Niepoprawna komenda (sprawdź %s)", - m.Author.Mention(), - HelpCommand.WithPrefix(s.cfg.CommandPrefix))) - return - } - - command := Command(args[0]) - world := args[1] - page, err := strconv.Atoi(args[2]) - if err != nil || page <= 0 { - s.SendMessage(m.ChannelID, fmt.Sprintf("%s 3 argument musi być liczbą większą od 0.", m.Author.Mention())) - return - } - ids := []int{} - for _, arg := range args[3:argsLength] { - id, err := strconv.Atoi(arg) - if err != nil || id <= 0 { - continue - } - ids = append(ids, id) - } - if len(ids) == 0 { - s.SendMessage(m.ChannelID, fmt.Sprintf("%s Nie wprowadziłeś ID plemion.", m.Author.Mention())) - return - } - - exists := true - limit := 10 - offset := (page - 1) * limit - filter := &shared_models.PlayerFilter{ - Exists: &exists, - TribeID: ids, - Limit: limit, - Offset: offset, - } - title := "" - switch command { - case TopAttCommand: - filter.RankAttGTE = 1 - filter.Sort = "rankAtt ASC" - title = "Top pokonani w ataku" - case TopDefCommand: - filter.RankDefGTE = 1 - filter.Sort = "rankDef ASC" - title = "Top pokonani w obronie" - case TopSuppCommand: - filter.RankSupGTE = 1 - filter.Sort = "rankSup ASC" - title = "Top pokonani jako wspierający" - case TopTotalCommand: - filter.RankTotalGTE = 1 - filter.Sort = "rankTotal ASC" - title = "Top pokonani ogólnie" - case TopPointsCommand: - filter.Sort = "rank ASC" - title = "Najwięcej punktów" - default: - s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Nieznana komenda %s (sprawdź %s)", - m.Author.Mention(), - command.String(), - HelpCommand.WithPrefix(s.cfg.CommandPrefix))) - return - } - - playersList, err := s.cfg.API.Players.Browse(world, filter, &sdk.PlayerInclude{ - Tribe: true, - }) - if err != nil { - s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Wystąpił błąd podczas pobierania danych z API, prosimy spróbować później.", m.Author.Mention())) - return - } - if playersList == nil || playersList.Total == 0 { - s.SendMessage(m.ChannelID, fmt.Sprintf("%s Nie znaleziono graczy należących do plemion o podanych ID.", m.Author.Mention())) - return - } - totalPages := int(math.Ceil(float64(playersList.Total) / float64(limit))) - if page > totalPages { - s.SendMessage(m.ChannelID, fmt.Sprintf("%s Przekroczyłeś limit stron (%d/%d).", m.Author.Mention(), page, totalPages)) - return - } - - langTag := utils.LanguageTagFromWorldName(world) - langVersion, err := s.cfg.API.LangVersions.Read(langTag) - if err != nil || langVersion == nil { - s.SendMessage(m.ChannelID, fmt.Sprintf("%s Nie znaleziono wersji językowej: %s.", m.Author.Mention(), langTag)) - return - } - - msg := &EmbedMessage{} - for i, player := range playersList.Items { - if player == nil { - continue - } - - rank := 0 - score := 0 - switch command { - case TopAttCommand: - rank = player.RankAtt - score = player.ScoreAtt - case TopDefCommand: - rank = player.RankDef - score = player.ScoreDef - case TopSuppCommand: - rank = player.RankSup - score = player.ScoreSup - case TopTotalCommand: - rank = player.RankTotal - score = player.ScoreTotal - case TopPointsCommand: - rank = player.Rank - score = player.Points - } - - tribeTag := "-" - tribeURL := "-" - if player.Tribe != nil { - tribeTag = player.Tribe.Tag - tribeURL = utils.FormatTribeURL(world, langVersion.Host, player.Tribe.ID) - } - - msg.Append(fmt.Sprintf("**%d**. [``%s``](%s) (Plemię: [``%s``](%s) | Ranking ogólny: **%d** | Wynik: **%d**)\n", - offset+i+1, - player.Name, - utils.FormatPlayerURL(world, langVersion.Host, player.ID), - tribeTag, - tribeURL, - rank, - score)) - } - - s.SendEmbed(m.ChannelID, NewEmbed(). - SetTitle(title). - SetDescription("A oto lista!"). - SetFields(msg.ToMessageEmbedFields()). - SetFooter(fmt.Sprintf("Strona %d z %d", page, totalPages)). - MessageEmbed) -} - func (s *Session) handleAddGroupCommand(m *discordgo.MessageCreate) { if m.GuildID == "" { return @@ -321,7 +87,7 @@ func (s *Session) handleDeleteGroupCommand(m *discordgo.MessageCreate, args ...s groupID, err := strconv.Atoi(args[0]) if err != nil { s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention())) + fmt.Sprintf("%s Niepoprawne ID grupy (powinna to być liczba całkowita większa od 1).", m.Author.Mention())) return } @@ -351,7 +117,7 @@ func (s *Session) handleGroupsCommand(m *discordgo.MessageCreate) { msg := "" for i, groups := range groups { - msg += fmt.Sprintf("**%d**. %d\n", i+1, groups.ID) + msg += fmt.Sprintf("**%d** | %d\n", i+1, groups.ID) } if msg == "" { @@ -360,7 +126,7 @@ func (s *Session) handleGroupsCommand(m *discordgo.MessageCreate) { s.SendEmbed(m.ChannelID, NewEmbed(). SetTitle("Lista grup"). - AddField("Indeks. ID", msg). + AddField("Indeks | ID", msg). SetFooter("Strona 1 z 1"). MessageEmbed) } @@ -389,7 +155,7 @@ func (s *Session) handleConqueredVillagesCommand(m *discordgo.MessageCreate, arg groupID, err := strconv.Atoi(args[0]) if err != nil { s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention())) + fmt.Sprintf("%s Niepoprawne ID grupy (powinna to być liczba całkowita większa od 1).", m.Author.Mention())) return } @@ -406,7 +172,8 @@ func (s *Session) handleConqueredVillagesCommand(m *discordgo.MessageCreate, arg groups[0].ConqueredVillagesChannelID = m.ChannelID go s.cfg.GroupRepository.Update(context.Background(), groups[0]) s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Pomyślnie zmieniono kanał na którym będą się wyświetlać informacje o podbitych wioskach.", m.Author.Mention())) + fmt.Sprintf("%s Pomyślnie zmieniono kanał na którym będą się wyświetlać informacje o podbitych wioskach (Grupa: %d).", + m.Author.Mention(), groupID)) } func (s *Session) handleUnObserveConqueredVillagesCommand(m *discordgo.MessageCreate, args ...string) { @@ -432,7 +199,7 @@ func (s *Session) handleUnObserveConqueredVillagesCommand(m *discordgo.MessageCr groupID, err := strconv.Atoi(args[0]) if err != nil { s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention())) + fmt.Sprintf("%s Niepoprawne ID grupy (powinna to być liczba całkowita większa od 1).", m.Author.Mention())) return } @@ -451,7 +218,7 @@ func (s *Session) handleUnObserveConqueredVillagesCommand(m *discordgo.MessageCr go s.cfg.GroupRepository.Update(context.Background(), groups[0]) } s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Informacje o podbitych wioskach nie będą się już pojawiały.", m.Author.Mention())) + fmt.Sprintf("%s Informacje o podbitych wioskach grupy %d nie będą się już pojawiały.", m.Author.Mention(), groupID)) } func (s *Session) handleLostVillagesCommand(m *discordgo.MessageCreate, args ...string) { @@ -487,14 +254,16 @@ func (s *Session) handleLostVillagesCommand(m *discordgo.MessageCreate, args ... }) if err != nil || len(groups) == 0 { s.SendMessage(m.ChannelID, - fmt.Sprintf("%s nie znaleziono grupy.", m.Author.Mention())) + fmt.Sprintf("%s Nie znaleziono grupy.", m.Author.Mention())) return } groups[0].LostVillagesChannelID = m.ChannelID go s.cfg.GroupRepository.Update(context.Background(), groups[0]) s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Pomyślnie zmieniono kanał na którym będą się wyświetlać informacje o straconych wioskach.", m.Author.Mention())) + fmt.Sprintf("%s Pomyślnie zmieniono kanał na którym będą się wyświetlać informacje o straconych wioskach (Grupa: %d).", + m.Author.Mention(), + groupID)) } func (s *Session) handleUnObserveLostVillagesCommand(m *discordgo.MessageCreate, args ...string) { @@ -530,7 +299,7 @@ func (s *Session) handleUnObserveLostVillagesCommand(m *discordgo.MessageCreate, }) if err != nil || len(groups) == 0 { s.SendMessage(m.ChannelID, - fmt.Sprintf("%s nie znaleziono grupy.", m.Author.Mention())) + fmt.Sprintf("%s Nie znaleziono grupy.", m.Author.Mention())) return } @@ -540,7 +309,9 @@ func (s *Session) handleUnObserveLostVillagesCommand(m *discordgo.MessageCreate, } s.SendMessage(m.ChannelID, - fmt.Sprintf("%s Informacje o straconych wioskach nie będą się już pojawiały.", m.Author.Mention())) + fmt.Sprintf("%s Informacje o straconych wioskach grupy %d nie będą się już pojawiały.", + m.Author.Mention(), + groupID)) } func (s *Session) handleObserveCommand(m *discordgo.MessageCreate, args ...string) { @@ -566,18 +337,16 @@ func (s *Session) handleObserveCommand(m *discordgo.MessageCreate, args ...strin groupID, err := strconv.Atoi(args[0]) if err != nil { s.SendMessage(m.ChannelID, - fmt.Sprintf("%s %s [id grupy] [świat] [id plemienia]", - m.Author.Mention(), - ObserveCommand.WithPrefix(s.cfg.CommandPrefix))) + fmt.Sprintf("%s ID grupy powinno być liczbą całkowitą większą od 0.", + m.Author.Mention())) return } serverKey := args[1] tribeID, err := strconv.Atoi(args[2]) - if err != nil { + if err != nil || tribeID <= 0 { s.SendMessage(m.ChannelID, - fmt.Sprintf("%s %s [świat] [id plemienia]", - m.Author.Mention(), - ObserveCommand.WithPrefix(s.cfg.CommandPrefix))) + fmt.Sprintf("%s ID plemienia powinno być liczbą całkowitą większą od 0.", + m.Author.Mention())) return } @@ -645,17 +414,15 @@ func (s *Session) handleUnObserveCommand(m *discordgo.MessageCreate, args ...str groupID, err := strconv.Atoi(args[0]) if err != nil { s.SendMessage(m.ChannelID, - fmt.Sprintf(`%s %s [id grupy] [id obserwacji]`, - m.Author.Mention(), - UnObserveCommand.WithPrefix(s.cfg.CommandPrefix))) + fmt.Sprintf(`%s ID grupy powinno być liczbą całkowitą większą od 0.`, + m.Author.Mention())) return } observationID, err := strconv.Atoi(args[1]) if err != nil { s.SendMessage(m.ChannelID, - fmt.Sprintf(`%s %s [id grupy] [id obserwacji]`, - m.Author.Mention(), - UnObserveCommand.WithPrefix(s.cfg.CommandPrefix))) + fmt.Sprintf(`%s ID obserwacji powinno być liczbą całkowitą większą od 0.`, + m.Author.Mention())) return } @@ -696,9 +463,8 @@ func (s *Session) handleObservationsCommand(m *discordgo.MessageCreate, args ... groupID, err := strconv.Atoi(args[0]) if err != nil { s.SendMessage(m.ChannelID, - fmt.Sprintf(`%s %s [id grupy]`, - m.Author.Mention(), - ObservationsCommand.WithPrefix(s.cfg.CommandPrefix))) + fmt.Sprintf(`%s ID grupy powinno być liczbą całkowitą większą od 0.`, + m.Author.Mention())) return } @@ -717,7 +483,7 @@ func (s *Session) handleObservationsCommand(m *discordgo.MessageCreate, args ... msg := "" for i, observation := range observations { - msg += fmt.Sprintf("**%d**. %d - %s - %d\n", i+1, observation.ID, observation.Server, observation.TribeID) + msg += fmt.Sprintf("**%d** | %d - %s - %d\n", i+1, observation.ID, observation.Server, observation.TribeID) } if msg == "" { @@ -726,7 +492,7 @@ func (s *Session) handleObservationsCommand(m *discordgo.MessageCreate, args ... s.SendEmbed(m.ChannelID, NewEmbed(). SetTitle("Lista obserwowanych plemion"). - AddField("Indeks. ID - Serwer - ID plemienia", msg). + AddField("Indeks | ID - Serwer - ID plemienia", msg). SetFooter("Strona 1 z 1"). MessageEmbed) } diff --git a/discord/command.go b/discord/command.go new file mode 100644 index 0000000..30ea701 --- /dev/null +++ b/discord/command.go @@ -0,0 +1,11 @@ +package discord + +type Command string + +func (cmd Command) String() string { + return string(cmd) +} + +func (cmd Command) WithPrefix(prefix string) string { + return prefix + cmd.String() +} diff --git a/discord/public_commands.go b/discord/public_commands.go new file mode 100644 index 0000000..7a38ef8 --- /dev/null +++ b/discord/public_commands.go @@ -0,0 +1,237 @@ +package discord + +import ( + "fmt" + "math" + "strconv" + + shared_models "github.com/tribalwarshelp/shared/models" + + "github.com/bwmarrin/discordgo" + "github.com/tribalwarshelp/dcbot/utils" + "github.com/tribalwarshelp/golang-sdk/sdk" +) + +const ( + HelpCommand Command = "help" + TribeCommand Command = "tribe" + TopAttCommand Command = "topatt" + TopDefCommand Command = "topdef" + TopSuppCommand Command = "topsupp" + TopTotalCommand Command = "toptotal" + TopPointsCommand Command = "toppoints" + AuthorCommand Command = "author" +) + +func (s *Session) handleHelpCommand(m *discordgo.MessageCreate) { + tribeCMDWithPrefix := TribeCommand.WithPrefix(s.cfg.CommandPrefix) + commandsForAll := fmt.Sprintf(` +- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największym RA z plemion o podanych id +- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największym RO z plemion o podanych id +- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największym RW z plemion o podanych id +- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największej liczbie pokonanych z plemion o podanych id +- **%s %s** [serwer] [strona] [id1] [id2] [id3] [n id] - wyświetla graczy o największej liczbie punktów z plemion o podanych id +- **%s** - kontakt z autorem bota + `, + tribeCMDWithPrefix, + TopAttCommand.String(), + tribeCMDWithPrefix, + TopDefCommand.String(), + tribeCMDWithPrefix, + TopSuppCommand.String(), + tribeCMDWithPrefix, + TopTotalCommand.String(), + tribeCMDWithPrefix, + TopPointsCommand.String(), + AuthorCommand.WithPrefix(s.cfg.CommandPrefix), + ) + + commandsForGuildAdmins := fmt.Sprintf(` +- **%s** - tworzy nową grupę +- **%s** - lista grup +- **%s** [id grupy z %s] - usuwa grupę +- **%s** [id grupy z %s] [świat] [id plemienia] - dodaje plemię z danego świata do obserwowanych +- **%s** [id grupy z %s] - wyświetla wszystkie obserwowane plemiona +- **%s** [id grupy z %s] [id z %s] - usuwa plemię z obserwowanych +- **%s** [id grupy z %s] - ustawia kanał na którym będą wyświetlać się informacje o podbitych wioskach +- **%s** [id grupy z %s] - informacje o podbitych wioskach na wybranym kanale nie będą się już pojawiały +- **%s** [id grupy z %s] - ustawia kanał na którym będą wyświetlać się informacje o straconych wioskach +- **%s** [id grupy z %s] - informacje o straconych wioskach na wybranym kanale nie będą się już pojawiały + `, + AddGroupCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + DeleteGroupCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + ObserveCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + ObservationsCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + UnObserveCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + ObservationsCommand.WithPrefix(s.cfg.CommandPrefix), + ConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + UnObserveConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + LostVillagesCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + UnObserveLostVillagesCommand.WithPrefix(s.cfg.CommandPrefix), + GroupsCommand.WithPrefix(s.cfg.CommandPrefix), + ) + + s.SendEmbed(m.ChannelID, NewEmbed(). + SetTitle("Pomoc"). + SetDescription("Komendy oferowane przez bota"). + AddField("Dla wszystkich", commandsForAll). + AddField("Dla adminów", commandsForGuildAdmins). + MessageEmbed) +} + +func (s *Session) handleAuthorCommand(m *discordgo.MessageCreate) { + s.SendMessage(m.ChannelID, fmt.Sprintf("%s Discord: Kichiyaki#2064.", m.Author.Mention())) +} + +func (s *Session) handleTribeCommand(m *discordgo.MessageCreate, args ...string) { + argsLength := len(args) + if argsLength < 4 { + s.SendMessage(m.ChannelID, + fmt.Sprintf("%s Niepoprawna komenda (sprawdź %s)", + m.Author.Mention(), + HelpCommand.WithPrefix(s.cfg.CommandPrefix))) + return + } + + command := Command(args[0]) + world := args[1] + page, err := strconv.Atoi(args[2]) + if err != nil || page <= 0 { + s.SendMessage(m.ChannelID, fmt.Sprintf("%s 3 argument musi być liczbą większą od 0.", m.Author.Mention())) + return + } + ids := []int{} + for _, arg := range args[3:argsLength] { + id, err := strconv.Atoi(arg) + if err != nil || id <= 0 { + continue + } + ids = append(ids, id) + } + if len(ids) == 0 { + s.SendMessage(m.ChannelID, fmt.Sprintf("%s Nie wprowadziłeś ID plemion.", m.Author.Mention())) + return + } + + exists := true + limit := 10 + offset := (page - 1) * limit + filter := &shared_models.PlayerFilter{ + Exists: &exists, + TribeID: ids, + Limit: limit, + Offset: offset, + } + title := "" + switch command { + case TopAttCommand: + filter.RankAttGTE = 1 + filter.Sort = "rankAtt ASC" + title = "Top pokonani w ataku" + case TopDefCommand: + filter.RankDefGTE = 1 + filter.Sort = "rankDef ASC" + title = "Top pokonani w obronie" + case TopSuppCommand: + filter.RankSupGTE = 1 + filter.Sort = "rankSup ASC" + title = "Top pokonani jako wspierający" + case TopTotalCommand: + filter.RankTotalGTE = 1 + filter.Sort = "rankTotal ASC" + title = "Top pokonani ogólnie" + case TopPointsCommand: + filter.Sort = "rank ASC" + title = "Najwięcej punktów" + default: + s.SendMessage(m.ChannelID, + fmt.Sprintf("%s Nieznana komenda %s (sprawdź %s)", + m.Author.Mention(), + command.String(), + HelpCommand.WithPrefix(s.cfg.CommandPrefix))) + return + } + + playersList, err := s.cfg.API.Players.Browse(world, filter, &sdk.PlayerInclude{ + Tribe: true, + }) + if err != nil { + s.SendMessage(m.ChannelID, + fmt.Sprintf("%s Wystąpił błąd podczas pobierania danych z API, prosimy spróbować później.", m.Author.Mention())) + return + } + if playersList == nil || playersList.Total == 0 { + s.SendMessage(m.ChannelID, fmt.Sprintf("%s Nie znaleziono graczy należących do plemion o podanych ID.", m.Author.Mention())) + return + } + totalPages := int(math.Ceil(float64(playersList.Total) / float64(limit))) + if page > totalPages { + s.SendMessage(m.ChannelID, fmt.Sprintf("%s Przekroczyłeś limit stron (%d/%d).", m.Author.Mention(), page, totalPages)) + return + } + + langTag := utils.LanguageTagFromWorldName(world) + langVersion, err := s.cfg.API.LangVersions.Read(langTag) + if err != nil || langVersion == nil { + s.SendMessage(m.ChannelID, fmt.Sprintf("%s Nie znaleziono wersji językowej: %s.", m.Author.Mention(), langTag)) + return + } + + msg := &EmbedMessage{} + for i, player := range playersList.Items { + if player == nil { + continue + } + + rank := 0 + score := 0 + switch command { + case TopAttCommand: + rank = player.RankAtt + score = player.ScoreAtt + case TopDefCommand: + rank = player.RankDef + score = player.ScoreDef + case TopSuppCommand: + rank = player.RankSup + score = player.ScoreSup + case TopTotalCommand: + rank = player.RankTotal + score = player.ScoreTotal + case TopPointsCommand: + rank = player.Rank + score = player.Points + } + + tribeTag := "-" + tribeURL := "-" + if player.Tribe != nil { + tribeTag = player.Tribe.Tag + tribeURL = utils.FormatTribeURL(world, langVersion.Host, player.Tribe.ID) + } + + msg.Append(fmt.Sprintf("**%d**. [``%s``](%s) (Plemię: [``%s``](%s) | Ranking ogólny: **%d** | Wynik: **%d**)\n", + offset+i+1, + player.Name, + utils.FormatPlayerURL(world, langVersion.Host, player.ID), + tribeTag, + tribeURL, + rank, + score)) + } + + s.SendEmbed(m.ChannelID, NewEmbed(). + SetTitle(title). + SetDescription("A oto lista!"). + SetFields(msg.ToMessageEmbedFields()). + SetFooter(fmt.Sprintf("Strona %d z %d", page, totalPages)). + MessageEmbed) +} diff --git a/main.go b/main.go index 56f2ad0..ae4ca9b 100644 --- a/main.go +++ b/main.go @@ -30,8 +30,6 @@ func init() { } func main() { - api := sdk.New(os.Getenv("API_URL")) - //postgres db := pg.Connect(&pg.Options{ User: os.Getenv("DB_USER"), Password: os.Getenv("DB_PASSWORD"), @@ -43,6 +41,7 @@ func main() { log.Fatal(err) } }() + serverRepo, err := server_repository.NewPgRepo(db) if err != nil { log.Fatal(err) @@ -55,6 +54,9 @@ func main() { if err != nil { log.Fatal(err) } + + api := sdk.New(os.Getenv("API_URL")) + sess, err := discord.New(discord.SessionConfig{ Token: os.Getenv("BOT_TOKEN"), CommandPrefix: "tw!", @@ -79,9 +81,7 @@ func main() { GroupRepo: groupRepo, API: api, }) - go func() { - c.Run() - }() + c.Start() defer c.Stop() log.Print("Bot is waiting for your actions!")