add group system

This commit is contained in:
Dawid Wysokiński 2020-06-26 20:30:25 +02:00 committed by Kichiyaki
parent a9c2f9fb40
commit 449297e71b
14 changed files with 556 additions and 127 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
.env.development .env.development
.env.production .env.production
.env .env
.netrc .netrc
todo.sql

View File

@ -6,6 +6,7 @@ import (
"github.com/tribalwarshelp/golang-sdk/sdk" "github.com/tribalwarshelp/golang-sdk/sdk"
"github.com/tribalwarshelp/dcbot/discord" "github.com/tribalwarshelp/dcbot/discord"
"github.com/tribalwarshelp/dcbot/group"
"github.com/tribalwarshelp/dcbot/observation" "github.com/tribalwarshelp/dcbot/observation"
"github.com/tribalwarshelp/dcbot/server" "github.com/tribalwarshelp/dcbot/server"
@ -16,6 +17,7 @@ type Config struct {
ServerRepo server.Repository ServerRepo server.Repository
ObservationRepo observation.Repository ObservationRepo observation.Repository
Discord *discord.Session Discord *discord.Session
GroupRepo group.Repository
API *sdk.SDK API *sdk.SDK
} }
@ -24,6 +26,7 @@ func Attach(c *cron.Cron, cfg Config) {
lastEnnoblementAt: make(map[string]time.Time), lastEnnoblementAt: make(map[string]time.Time),
serverRepo: cfg.ServerRepo, serverRepo: cfg.ServerRepo,
observationRepo: cfg.ObservationRepo, observationRepo: cfg.ObservationRepo,
groupRepo: cfg.GroupRepo,
discord: cfg.Discord, discord: cfg.Discord,
api: cfg.API, api: cfg.API,
} }

View File

@ -8,6 +8,7 @@ import (
shared_models "github.com/tribalwarshelp/shared/models" shared_models "github.com/tribalwarshelp/shared/models"
"github.com/tribalwarshelp/dcbot/discord" "github.com/tribalwarshelp/dcbot/discord"
"github.com/tribalwarshelp/dcbot/group"
"github.com/tribalwarshelp/dcbot/models" "github.com/tribalwarshelp/dcbot/models"
"github.com/tribalwarshelp/dcbot/observation" "github.com/tribalwarshelp/dcbot/observation"
"github.com/tribalwarshelp/dcbot/server" "github.com/tribalwarshelp/dcbot/server"
@ -19,6 +20,7 @@ type handler struct {
lastEnnoblementAt map[string]time.Time lastEnnoblementAt map[string]time.Time
serverRepo server.Repository serverRepo server.Repository
observationRepo observation.Repository observationRepo observation.Repository
groupRepo group.Repository
discord *discord.Session discord *discord.Session
api *sdk.SDK api *sdk.SDK
} }
@ -87,44 +89,44 @@ func (h *handler) loadLangVersions(worlds []string) map[shared_models.LanguageTa
} }
func (h *handler) checkLastEnnoblements() { func (h *handler) checkLastEnnoblements() {
worlds, err := h.observationRepo.FetchWorlds(context.Background()) servers, err := h.observationRepo.FetchServers(context.Background())
if err != nil { if err != nil {
log.Print("checkLastEnnoblements error: " + err.Error()) log.Print("checkLastEnnoblements error: " + err.Error())
return return
} }
log.Print("checkLastEnnoblements: worlds: ", worlds) log.Print("checkLastEnnoblements: servers: ", servers)
servers, total, err := h.serverRepo.Fetch(context.Background(), nil) groups, total, err := h.groupRepo.Fetch(context.Background(), nil)
if err != nil { if err != nil {
log.Print("checkLastEnnoblements error: " + err.Error()) log.Print("checkLastEnnoblements error: " + err.Error())
return return
} }
log.Print("checkLastEnnoblements: number of loaded discord servers: ", total) log.Print("checkLastEnnoblements: number of loaded groups: ", total)
langVersions := h.loadLangVersions(worlds) langVersions := h.loadLangVersions(servers)
ennoblementsByServerKey := h.loadEnnoblements(worlds) ennoblementsByServerKey := h.loadEnnoblements(servers)
for _, server := range servers { for _, group := range groups {
if server.ConqueredVillagesChannelID == "" && server.LostVillagesChannelID == "" { if group.ConqueredVillagesChannelID == "" && group.LostVillagesChannelID == "" {
continue continue
} }
for _, tribe := range server.Observations { for _, observation := range group.Observations {
ennoblements, ok := ennoblementsByServerKey[tribe.World] ennoblements, ok := ennoblementsByServerKey[observation.Server]
langVersion, ok2 := langVersions[utils.LanguageTagFromWorldName(tribe.World)] langVersion, ok2 := langVersions[utils.LanguageTagFromWorldName(observation.Server)]
if ok && ok2 { if ok && ok2 {
if server.LostVillagesChannelID != "" { if group.LostVillagesChannelID != "" {
for _, ennoblement := range ennoblements.getLostVillagesByTribe(tribe.TribeID) { for _, ennoblement := range ennoblements.getLostVillagesByTribe(observation.TribeID) {
if !isPlayerTribeNil(ennoblement.NewOwner) && if !isPlayerTribeNil(ennoblement.NewOwner) &&
server.Observations.Contains(tribe.World, ennoblement.NewOwner.Tribe.ID) { group.Observations.Contains(observation.Server, ennoblement.NewOwner.Tribe.ID) {
continue continue
} }
newMsgDataConfig := newMessageDataConfig{ newMsgDataConfig := newMessageDataConfig{
host: langVersion.Host, host: langVersion.Host,
world: tribe.World, world: observation.Server,
ennoblement: ennoblement, ennoblement: ennoblement,
} }
msgData := newMessageData(newMsgDataConfig) msgData := newMessageData(newMsgDataConfig)
h.discord.SendEmbed(server.LostVillagesChannelID, h.discord.SendEmbed(group.LostVillagesChannelID,
discord. discord.
NewEmbed(). NewEmbed().
SetTitle("Stracona wioska"). SetTitle("Stracona wioska").
@ -134,19 +136,19 @@ func (h *handler) checkLastEnnoblements() {
} }
} }
if server.ConqueredVillagesChannelID != "" { if group.ConqueredVillagesChannelID != "" {
for _, ennoblement := range ennoblements.getConqueredVillagesByTribe(tribe.TribeID) { for _, ennoblement := range ennoblements.getConqueredVillagesByTribe(observation.TribeID) {
if !isPlayerTribeNil(ennoblement.OldOwner) && if !isPlayerTribeNil(ennoblement.OldOwner) &&
server.Observations.Contains(tribe.World, ennoblement.OldOwner.Tribe.ID) { group.Observations.Contains(observation.Server, ennoblement.OldOwner.Tribe.ID) {
continue continue
} }
newMsgDataConfig := newMessageDataConfig{ newMsgDataConfig := newMessageDataConfig{
host: langVersion.Host, host: langVersion.Host,
world: tribe.World, world: observation.Server,
ennoblement: ennoblement, ennoblement: ennoblement,
} }
msgData := newMessageData(newMsgDataConfig) msgData := newMessageData(newMsgDataConfig)
h.discord.SendEmbed(server.ConqueredVillagesChannelID, h.discord.SendEmbed(group.ConqueredVillagesChannelID,
discord. discord.
NewEmbed(). NewEmbed().
SetTitle("Podbita wioska"). SetTitle("Podbita wioska").
@ -188,7 +190,7 @@ func (h *handler) checkBotMembershipOnServers() {
} }
func (h *handler) deleteClosedTribalWarsServers() { func (h *handler) deleteClosedTribalWarsServers() {
servers, err := h.observationRepo.FetchWorlds(context.Background()) servers, err := h.observationRepo.FetchServers(context.Background())
if err != nil { if err != nil {
log.Print("deleteClosedTribalWarsServers: " + err.Error()) log.Print("deleteClosedTribalWarsServers: " + err.Error())
return return
@ -214,7 +216,7 @@ func (h *handler) deleteClosedTribalWarsServers() {
if len(keys) > 0 { if len(keys) > 0 {
deleted, err := h.observationRepo.Delete(context.Background(), &models.ObservationFilter{ deleted, err := h.observationRepo.Delete(context.Background(), &models.ObservationFilter{
World: keys, Server: keys,
}) })
if err != nil { if err != nil {
log.Print("deleteClosedTribalWarsServers error: " + err.Error()) log.Print("deleteClosedTribalWarsServers error: " + err.Error())

View File

@ -15,13 +15,17 @@ import (
) )
const ( const (
ObservationsPerServer = 10 ObservationsPerGroup = 10
GroupsPerServer = 5
) )
type Command string type Command string
const ( const (
HelpCommand Command = "help" HelpCommand Command = "help"
AddGroupCommand Command = "addgroup"
DeleteGroupCommand Command = "deletegroup"
GroupsCommand Command = "groups"
ObserveCommand Command = "observe" ObserveCommand Command = "observe"
ObservationsCommand Command = "observations" ObservationsCommand Command = "observations"
UnObserveCommand Command = "unobserve" UnObserveCommand Command = "unobserve"
@ -70,22 +74,35 @@ func (s *Session) handleHelpCommand(m *discordgo.MessageCreate) {
) )
commandsForGuildAdmins := fmt.Sprintf(` commandsForGuildAdmins := fmt.Sprintf(`
- **%s** [świat] [id] - dodaje plemię z danego świata do obserwowanych - **%s** - tworzy nową grupę
- **%s** - wyświetla wszystkie obserwowane plemiona - **%s** - usuwa grupę
- **%s** [id z %s] - usuwa plemię z obserwowanych - **%s** - lista grup
- **%s** - ustawia kanał na którym będą wyświetlać się informacje o podbitych wioskach - **%s** [id grupy z %s] [świat] [id plemienia] - dodaje plemię z danego świata do obserwowanych
- **%s** - informacje o podbitych wioskach na wybranym kanale nie będą się już pojawiały - **%s** [id grupy z %s] - wyświetla wszystkie obserwowane plemiona
- **%s** - ustawia kanał na którym będą wyświetlać się informacje o straconych wioskach - **%s** [id grupy z %s] [id z %s] - usuwa plemię z obserwowanych
- **%s** - informacje o straconych 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 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), ObserveCommand.WithPrefix(s.cfg.CommandPrefix),
GroupsCommand.WithPrefix(s.cfg.CommandPrefix),
ObservationsCommand.WithPrefix(s.cfg.CommandPrefix), ObservationsCommand.WithPrefix(s.cfg.CommandPrefix),
GroupsCommand.WithPrefix(s.cfg.CommandPrefix),
UnObserveCommand.WithPrefix(s.cfg.CommandPrefix), UnObserveCommand.WithPrefix(s.cfg.CommandPrefix),
GroupsCommand.WithPrefix(s.cfg.CommandPrefix),
ObservationsCommand.WithPrefix(s.cfg.CommandPrefix), ObservationsCommand.WithPrefix(s.cfg.CommandPrefix),
ConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix), ConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix),
GroupsCommand.WithPrefix(s.cfg.CommandPrefix),
UnObserveConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix), UnObserveConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix),
GroupsCommand.WithPrefix(s.cfg.CommandPrefix),
LostVillagesCommand.WithPrefix(s.cfg.CommandPrefix), LostVillagesCommand.WithPrefix(s.cfg.CommandPrefix),
GroupsCommand.WithPrefix(s.cfg.CommandPrefix),
UnObserveLostVillagesCommand.WithPrefix(s.cfg.CommandPrefix), UnObserveLostVillagesCommand.WithPrefix(s.cfg.CommandPrefix),
GroupsCommand.WithPrefix(s.cfg.CommandPrefix),
) )
s.SendEmbed(m.ChannelID, NewEmbed(). s.SendEmbed(m.ChannelID, NewEmbed().
@ -245,10 +262,11 @@ func (s *Session) handleTribeCommand(m *discordgo.MessageCreate, args ...string)
MessageEmbed) MessageEmbed)
} }
func (s *Session) handleConqueredVillagesCommand(m *discordgo.MessageCreate) { func (s *Session) handleAddGroupCommand(m *discordgo.MessageCreate) {
if m.GuildID == "" { if m.GuildID == "" {
return return
} }
if has, err := s.memberHasPermission(m.GuildID, m.Author.ID, discordgo.PermissionAdministrator); err != nil || !has { if has, err := s.memberHasPermission(m.GuildID, m.Author.ID, discordgo.PermissionAdministrator); err != nil || !has {
return return
} }
@ -256,17 +274,142 @@ func (s *Session) handleConqueredVillagesCommand(m *discordgo.MessageCreate) {
server := &models.Server{ server := &models.Server{
ID: m.GuildID, ID: m.GuildID,
} }
err := s.cfg.ServerRepository.Store(context.Background(), server) if err := s.cfg.ServerRepository.Store(context.Background(), server); err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Nie udało się dodać grupy", m.Author.Mention()))
return
}
if len(server.Groups) >= GroupsPerServer {
s.SendMessage(m.ChannelID,
m.Author.Mention()+fmt.Sprintf(` Osiągnięto limit grup na serwerze (%d/%d).`, GroupsPerServer, GroupsPerServer))
return
}
group := &models.Group{
ServerID: m.GuildID,
}
if err := s.cfg.GroupRepository.Store(context.Background(), group); err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Nie udało się dodać grupy", m.Author.Mention()))
return
}
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Utworzono nową grupę o ID %d.", m.Author.Mention(), group.ID))
}
func (s *Session) handleDeleteGroupCommand(m *discordgo.MessageCreate, args ...string) {
if m.GuildID == "" {
return
}
if has, err := s.memberHasPermission(m.GuildID, m.Author.ID, discordgo.PermissionAdministrator); err != nil || !has {
return
}
argsLength := len(args)
if argsLength > 1 {
s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...)
return
} else if argsLength < 1 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [id grupy]",
m.Author.Mention(),
DeleteGroupCommand.WithPrefix(s.cfg.CommandPrefix)))
return
}
groupID, err := strconv.Atoi(args[0])
if err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention()))
return
}
go s.cfg.GroupRepository.Delete(context.Background(), &models.GroupFilter{
ID: []int{groupID},
ServerID: []string{m.GuildID},
})
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Usunięto grupę.", m.Author.Mention()))
}
func (s *Session) handleGroupsCommand(m *discordgo.MessageCreate) {
if m.GuildID == "" {
return
}
if has, err := s.memberHasPermission(m.GuildID, m.Author.ID, discordgo.PermissionAdministrator); err != nil || !has {
return
}
groups, _, err := s.cfg.GroupRepository.Fetch(context.Background(), &models.GroupFilter{
ServerID: []string{m.GuildID},
})
if err != nil { if err != nil {
return return
} }
server.ConqueredVillagesChannelID = m.ChannelID
go s.cfg.ServerRepository.Update(context.Background(), server) msg := ""
for i, groups := range groups {
msg += fmt.Sprintf("**%d**. %d\n", i+1, groups.ID)
}
if msg == "" {
msg = "Brak dodanych grup"
}
s.SendEmbed(m.ChannelID, NewEmbed().
SetTitle("Lista grup").
AddField("Indeks. ID", msg).
SetFooter("Strona 1 z 1").
MessageEmbed)
}
func (s *Session) handleConqueredVillagesCommand(m *discordgo.MessageCreate, args ...string) {
if m.GuildID == "" {
return
}
if has, err := s.memberHasPermission(m.GuildID, m.Author.ID, discordgo.PermissionAdministrator); err != nil || !has {
return
}
argsLength := len(args)
if argsLength > 1 {
s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...)
return
} else if argsLength < 1 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [id grupy]",
m.Author.Mention(),
ConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix)))
return
}
groupID, err := strconv.Atoi(args[0])
if err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention()))
return
}
groups, _, err := s.cfg.GroupRepository.Fetch(context.Background(), &models.GroupFilter{
ID: []int{groupID},
ServerID: []string{m.GuildID},
})
if err != nil || len(groups) == 0 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s nie znaleziono grupy.", m.Author.Mention()))
return
}
groups[0].ConqueredVillagesChannelID = m.ChannelID
go s.cfg.GroupRepository.Update(context.Background(), groups[0])
s.SendMessage(m.ChannelID, 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.", m.Author.Mention()))
} }
func (s *Session) handleUnObserveConqueredVillagesCommand(m *discordgo.MessageCreate) { func (s *Session) handleUnObserveConqueredVillagesCommand(m *discordgo.MessageCreate, args ...string) {
if m.GuildID == "" { if m.GuildID == "" {
return return
} }
@ -274,22 +417,44 @@ func (s *Session) handleUnObserveConqueredVillagesCommand(m *discordgo.MessageCr
return return
} }
server := &models.Server{ argsLength := len(args)
ID: m.GuildID, if argsLength > 1 {
} s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...)
err := s.cfg.ServerRepository.Store(context.Background(), server) return
if err != nil { } else if argsLength < 1 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [id grupy]",
m.Author.Mention(),
UnObserveConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix)))
return return
} }
if server.ConqueredVillagesChannelID != "" {
server.ConqueredVillagesChannelID = "" groupID, err := strconv.Atoi(args[0])
go s.cfg.ServerRepository.Update(context.Background(), server) if err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention()))
return
}
groups, _, err := s.cfg.GroupRepository.Fetch(context.Background(), &models.GroupFilter{
ID: []int{groupID},
ServerID: []string{m.GuildID},
})
if err != nil || len(groups) == 0 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s nie znaleziono grupy.", m.Author.Mention()))
return
}
if groups[0].ConqueredVillagesChannelID != "" {
groups[0].ConqueredVillagesChannelID = ""
go s.cfg.GroupRepository.Update(context.Background(), groups[0])
} }
s.SendMessage(m.ChannelID, 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 nie będą się już pojawiały.", m.Author.Mention()))
} }
func (s *Session) handleLostVillagesCommand(m *discordgo.MessageCreate) { func (s *Session) handleLostVillagesCommand(m *discordgo.MessageCreate, args ...string) {
if m.GuildID == "" { if m.GuildID == "" {
return return
} }
@ -297,20 +462,42 @@ func (s *Session) handleLostVillagesCommand(m *discordgo.MessageCreate) {
return return
} }
server := &models.Server{ argsLength := len(args)
ID: m.GuildID, if argsLength > 1 {
} s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...)
err := s.cfg.ServerRepository.Store(context.Background(), server) return
if err != nil { } else if argsLength < 1 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [id grupy]",
m.Author.Mention(),
LostVillagesCommand.WithPrefix(s.cfg.CommandPrefix)))
return return
} }
server.LostVillagesChannelID = m.ChannelID
go s.cfg.ServerRepository.Update(context.Background(), server) groupID, err := strconv.Atoi(args[0])
if err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention()))
return
}
groups, _, err := s.cfg.GroupRepository.Fetch(context.Background(), &models.GroupFilter{
ID: []int{groupID},
ServerID: []string{m.GuildID},
})
if err != nil || len(groups) == 0 {
s.SendMessage(m.ChannelID,
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, 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.", m.Author.Mention()))
} }
func (s *Session) handleUnObserveLostVillagesCommand(m *discordgo.MessageCreate) { func (s *Session) handleUnObserveLostVillagesCommand(m *discordgo.MessageCreate, args ...string) {
if m.GuildID == "" { if m.GuildID == "" {
return return
} }
@ -318,17 +505,40 @@ func (s *Session) handleUnObserveLostVillagesCommand(m *discordgo.MessageCreate)
return return
} }
server := &models.Server{ argsLength := len(args)
ID: m.GuildID, if argsLength > 1 {
} s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...)
err := s.cfg.ServerRepository.Store(context.Background(), server) return
if err != nil { } else if argsLength < 1 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [id grupy]",
m.Author.Mention(),
UnObserveLostVillagesCommand.WithPrefix(s.cfg.CommandPrefix)))
return return
} }
if server.LostVillagesChannelID != "" {
server.LostVillagesChannelID = "" groupID, err := strconv.Atoi(args[0])
go s.cfg.ServerRepository.Update(context.Background(), server) if err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s Niepoprawne ID grupy", m.Author.Mention()))
return
} }
groups, _, err := s.cfg.GroupRepository.Fetch(context.Background(), &models.GroupFilter{
ID: []int{groupID},
ServerID: []string{m.GuildID},
})
if err != nil || len(groups) == 0 {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s nie znaleziono grupy.", m.Author.Mention()))
return
}
if groups[0].LostVillagesChannelID != "" {
groups[0].LostVillagesChannelID = ""
go s.cfg.GroupRepository.Update(context.Background(), groups[0])
}
s.SendMessage(m.ChannelID, 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 nie będą się już pojawiały.", m.Author.Mention()))
} }
@ -342,19 +552,27 @@ func (s *Session) handleObserveCommand(m *discordgo.MessageCreate, args ...strin
} }
argsLength := len(args) argsLength := len(args)
if argsLength > 2 { if argsLength > 3 {
s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[2:argsLength]...) s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[3:argsLength]...)
return return
} else if argsLength < 2 { } else if argsLength < 3 {
s.SendMessage(m.ChannelID, s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [świat] [id plemienia]", fmt.Sprintf("%s %s [id grupy] [świat] [id plemienia]",
m.Author.Mention(), m.Author.Mention(),
ObserveCommand.WithPrefix(s.cfg.CommandPrefix))) ObserveCommand.WithPrefix(s.cfg.CommandPrefix)))
return return
} }
world := args[0] groupID, err := strconv.Atoi(args[0])
id, err := strconv.Atoi(args[1]) if err != nil {
s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [id grupy] [świat] [id plemienia]",
m.Author.Mention(),
ObserveCommand.WithPrefix(s.cfg.CommandPrefix)))
return
}
serverKey := args[1]
tribeID, err := strconv.Atoi(args[2])
if err != nil { if err != nil {
s.SendMessage(m.ChannelID, s.SendMessage(m.ChannelID,
fmt.Sprintf("%s %s [świat] [id plemienia]", fmt.Sprintf("%s %s [świat] [id plemienia]",
@ -363,40 +581,38 @@ func (s *Session) handleObserveCommand(m *discordgo.MessageCreate, args ...strin
return return
} }
server, err := s.cfg.API.Servers.Read(world, nil) server, err := s.cfg.API.Servers.Read(serverKey, nil)
if err != nil || server == nil { if err != nil || server == nil {
s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` świat %s jest nieobsługiwany.`, world)) s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` świat %s jest nieobsługiwany.`, serverKey))
return return
} }
if server.Status == shared_models.ServerStatusClosed { if server.Status == shared_models.ServerStatusClosed {
s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` świat %s jest zamknięty.`, world)) s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` świat %s jest zamknięty.`, serverKey))
return return
} }
tribe, err := s.cfg.API.Tribes.Read(world, id) tribe, err := s.cfg.API.Tribes.Read(server.Key, tribeID)
if err != nil || tribe == nil { if err != nil || tribe == nil {
s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` Plemię o ID: %d nie istnieje na świecie %s.`, id, world)) s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` Plemię o ID: %d nie istnieje na świecie %s.`, tribeID, server.Key))
return return
} }
dcServer := &models.Server{ group, err := s.cfg.GroupRepository.GetByID(context.Background(), groupID)
ID: m.GuildID, if err != nil || group.ServerID != m.GuildID {
} s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie znaleziono grupy.`)
err = s.cfg.ServerRepository.Store(context.Background(), dcServer)
if err != nil {
s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie udało się dodać plemienia do obserwowanych.`)
return return
} }
if len(dcServer.Observations) >= ObservationsPerServer { if len(group.Observations) >= ObservationsPerGroup {
s.SendMessage(m.ChannelID, m.Author.Mention()+fmt.Sprintf(` Osiągnięto limit plemion (%d/%d).`, ObservationsPerServer, ObservationsPerServer)) s.SendMessage(m.ChannelID,
m.Author.Mention()+fmt.Sprintf(` Osiągnięto limit plemion w grupie (%d/%d).`, ObservationsPerGroup, ObservationsPerGroup))
return return
} }
err = s.cfg.ObservationRepository.Store(context.Background(), &models.Observation{ err = s.cfg.ObservationRepository.Store(context.Background(), &models.Observation{
World: world, Server: server.Key,
TribeID: id, TribeID: tribeID,
ServerID: dcServer.ID, GroupID: groupID,
}) })
if err != nil { if err != nil {
s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie udało się dodać plemienia do obserwowanych.`) s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie udało się dodać plemienia do obserwowanych.`)
@ -415,35 +631,49 @@ func (s *Session) handleUnObserveCommand(m *discordgo.MessageCreate, args ...str
} }
argsLength := len(args) argsLength := len(args)
if argsLength > 1 { if argsLength > 2 {
s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...) s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[2:argsLength]...)
return return
} else if argsLength < 1 { } else if argsLength < 2 {
s.SendMessage(m.ChannelID, s.SendMessage(m.ChannelID,
fmt.Sprintf(`%s %s [id z tw!list]`, fmt.Sprintf(`%s %s [id grupy] [id obserwacji]`,
m.Author.Mention(), m.Author.Mention(),
UnObserveCommand.WithPrefix(s.cfg.CommandPrefix))) UnObserveCommand.WithPrefix(s.cfg.CommandPrefix)))
return return
} }
id, err := strconv.Atoi(args[0]) groupID, err := strconv.Atoi(args[0])
if err != nil { if err != nil {
s.SendMessage(m.ChannelID, s.SendMessage(m.ChannelID,
fmt.Sprintf(`%s %s [id z tw!list]`, fmt.Sprintf(`%s %s [id grupy] [id obserwacji]`,
m.Author.Mention(), m.Author.Mention(),
UnObserveCommand.WithPrefix(s.cfg.CommandPrefix))) UnObserveCommand.WithPrefix(s.cfg.CommandPrefix)))
return 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)))
return
}
group, err := s.cfg.GroupRepository.GetByID(context.Background(), groupID)
if err != nil || group.ServerID != m.GuildID {
s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie znaleziono grupy.`)
return
}
go s.cfg.ObservationRepository.Delete(context.Background(), &models.ObservationFilter{ go s.cfg.ObservationRepository.Delete(context.Background(), &models.ObservationFilter{
ServerID: []string{m.GuildID}, GroupID: []int{groupID},
ID: []int{id}, ID: []int{observationID},
}) })
s.SendMessage(m.ChannelID, m.Author.Mention()+` Usunięto.`) s.SendMessage(m.ChannelID, m.Author.Mention()+` Usunięto.`)
} }
func (s *Session) handleObservationsCommand(m *discordgo.MessageCreate) { func (s *Session) handleObservationsCommand(m *discordgo.MessageCreate, args ...string) {
if m.GuildID == "" { if m.GuildID == "" {
return return
} }
@ -451,8 +681,35 @@ func (s *Session) handleObservationsCommand(m *discordgo.MessageCreate) {
return return
} }
argsLength := len(args)
if argsLength > 1 {
s.sendUnknownCommandError(m.Author.Mention(), m.ChannelID, args[1:argsLength]...)
return
} else if argsLength < 1 {
s.SendMessage(m.ChannelID,
fmt.Sprintf(`%s %s [id grupy]`,
m.Author.Mention(),
ObservationsCommand.WithPrefix(s.cfg.CommandPrefix)))
return
}
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)))
return
}
group, err := s.cfg.GroupRepository.GetByID(context.Background(), groupID)
if err != nil || group.ServerID != m.GuildID {
s.SendMessage(m.ChannelID, m.Author.Mention()+` Nie znaleziono grupy.`)
return
}
observations, _, err := s.cfg.ObservationRepository.Fetch(context.Background(), &models.ObservationFilter{ observations, _, err := s.cfg.ObservationRepository.Fetch(context.Background(), &models.ObservationFilter{
ServerID: []string{m.GuildID}, GroupID: []int{groupID},
}) })
if err != nil { if err != nil {
return return
@ -460,12 +717,16 @@ func (s *Session) handleObservationsCommand(m *discordgo.MessageCreate) {
msg := "" msg := ""
for i, observation := range observations { for i, observation := range observations {
msg += fmt.Sprintf("**%d**. %d - %s - %d\n", i+1, observation.ID, observation.World, observation.TribeID) msg += fmt.Sprintf("**%d**. %d - %s - %d\n", i+1, observation.ID, observation.Server, observation.TribeID)
}
if msg == "" {
msg = "Brak dodanych obserwacji do tej grupy"
} }
s.SendEmbed(m.ChannelID, NewEmbed(). s.SendEmbed(m.ChannelID, NewEmbed().
SetTitle("Lista obserwowanych plemion"). SetTitle("Lista obserwowanych plemion").
AddField("Indeks. ID - świat - ID plemienia", msg). AddField("Indeks. ID - Serwer - ID plemienia", msg).
SetFooter("Strona 1 z 1"). SetFooter("Strona 1 z 1").
MessageEmbed) MessageEmbed)
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/tribalwarshelp/dcbot/group"
"github.com/tribalwarshelp/dcbot/observation" "github.com/tribalwarshelp/dcbot/observation"
"github.com/tribalwarshelp/dcbot/server" "github.com/tribalwarshelp/dcbot/server"
"github.com/tribalwarshelp/golang-sdk/sdk" "github.com/tribalwarshelp/golang-sdk/sdk"
@ -16,6 +17,7 @@ type SessionConfig struct {
CommandPrefix string CommandPrefix string
Status string Status string
ServerRepository server.Repository ServerRepository server.Repository
GroupRepository group.Repository
ObservationRepository observation.Repository ObservationRepository observation.Repository
API *sdk.SDK API *sdk.SDK
} }
@ -81,22 +83,31 @@ func (s *Session) handleNewMessage(_ *discordgo.Session, m *discordgo.MessageCre
s.handleHelpCommand(m) s.handleHelpCommand(m)
case AuthorCommand.WithPrefix(s.cfg.CommandPrefix): case AuthorCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleAuthorCommand(m) s.handleAuthorCommand(m)
case TribeCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleTribeCommand(m, args...)
case AddGroupCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleAddGroupCommand(m)
case DeleteGroupCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleDeleteGroupCommand(m, args...)
case GroupsCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleGroupsCommand(m)
case ObserveCommand.WithPrefix(s.cfg.CommandPrefix): case ObserveCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleObserveCommand(m, args...) s.handleObserveCommand(m, args...)
case UnObserveCommand.WithPrefix(s.cfg.CommandPrefix): case UnObserveCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleUnObserveCommand(m, args...) s.handleUnObserveCommand(m, args...)
case ObservationsCommand.WithPrefix(s.cfg.CommandPrefix): case ObservationsCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleObservationsCommand(m) s.handleObservationsCommand(m, args...)
case ConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix): case ConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleConqueredVillagesCommand(m) s.handleConqueredVillagesCommand(m, args...)
case UnObserveConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix): case UnObserveConqueredVillagesCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleUnObserveConqueredVillagesCommand(m) s.handleUnObserveConqueredVillagesCommand(m, args...)
case LostVillagesCommand.WithPrefix(s.cfg.CommandPrefix): case LostVillagesCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleLostVillagesCommand(m) s.handleLostVillagesCommand(m, args...)
case UnObserveLostVillagesCommand.WithPrefix(s.cfg.CommandPrefix): case UnObserveLostVillagesCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleUnObserveLostVillagesCommand(m) s.handleUnObserveLostVillagesCommand(m, args...)
case TribeCommand.WithPrefix(s.cfg.CommandPrefix):
s.handleTribeCommand(m, args...)
} }
} }

16
group/repository.go Normal file
View File

@ -0,0 +1,16 @@
package group
import (
"context"
"github.com/tribalwarshelp/dcbot/models"
)
type Repository interface {
Store(ctx context.Context, group *models.Group) error
StoreMany(ctx context.Context, groups []*models.Group) error
Update(ctx context.Context, group *models.Group) error
Delete(ctx context.Context, filter *models.GroupFilter) ([]*models.Group, error)
GetByID(ctx context.Context, id int) (*models.Group, error)
Fetch(ctx context.Context, filter *models.GroupFilter) ([]*models.Group, int, error)
}

View File

@ -0,0 +1,109 @@
package repository
import (
"context"
"github.com/tribalwarshelp/dcbot/group"
"github.com/tribalwarshelp/dcbot/models"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/pkg/errors"
)
type pgRepo struct {
*pg.DB
}
func NewPgRepo(db *pg.DB) (group.Repository, error) {
if err := db.CreateTable((*models.Group)(nil), &orm.CreateTableOptions{
IfNotExists: true,
FKConstraints: true,
}); err != nil {
return nil, errors.Wrap(err, "Cannot create 'groups' table")
}
return &pgRepo{db}, nil
}
func (repo *pgRepo) Store(ctx context.Context, group *models.Group) error {
if _, err := repo.Model(group).Returning("*").Context(ctx).Insert(); err != nil {
return err
}
return nil
}
func (repo *pgRepo) StoreMany(ctx context.Context, groups []*models.Group) error {
if _, err := repo.Model(&groups).Returning("*").Context(ctx).Insert(); err != nil {
return err
}
return nil
}
func (repo *pgRepo) Update(ctx context.Context, group *models.Group) error {
if _, err := repo.
Model(group).
WherePK().
Returning("*").
Context(ctx).
Update(); err != nil {
return err
}
return nil
}
func (repo *pgRepo) GetByID(ctx context.Context, id int) (*models.Group, error) {
group := &models.Group{
ID: id,
}
if err := repo.
Model(group).
WherePK().
Returning("*").
Relation("Observations").
Context(ctx).
Select(); err != nil {
return nil, err
}
return group, nil
}
func (repo *pgRepo) Fetch(ctx context.Context, f *models.GroupFilter) ([]*models.Group, int, error) {
var err error
data := []*models.Group{}
query := repo.Model(&data).Relation("Observations").Context(ctx)
if f != nil {
query = query.
WhereStruct(f).
Limit(f.Limit).
Offset(f.Offset)
if len(f.Order) > 0 {
query = query.Order(f.Order...)
}
}
total, err := query.SelectAndCount()
if err != nil && err != pg.ErrNoRows {
return nil, 0, err
}
return data, total, nil
}
func (repo *pgRepo) Delete(ctx context.Context, f *models.GroupFilter) ([]*models.Group, error) {
data := []*models.Group{}
query := repo.Model(&data).Context(ctx)
if f != nil {
query = query.WhereStruct(f)
}
_, err := query.
Returning("*").
Delete()
if err != nil && err != pg.ErrNoRows {
return nil, err
}
return data, nil
}

View File

@ -10,6 +10,7 @@ import (
_cron "github.com/tribalwarshelp/dcbot/cron" _cron "github.com/tribalwarshelp/dcbot/cron"
"github.com/tribalwarshelp/dcbot/discord" "github.com/tribalwarshelp/dcbot/discord"
group_repository "github.com/tribalwarshelp/dcbot/group/repository"
observation_repository "github.com/tribalwarshelp/dcbot/observation/repository" observation_repository "github.com/tribalwarshelp/dcbot/observation/repository"
server_repository "github.com/tribalwarshelp/dcbot/server/repository" server_repository "github.com/tribalwarshelp/dcbot/server/repository"
@ -46,6 +47,10 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
groupRepo, err := group_repository.NewPgRepo(db)
if err != nil {
log.Fatal(err)
}
observationRepo, err := observation_repository.NewPgRepo(db) observationRepo, err := observation_repository.NewPgRepo(db)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -56,6 +61,7 @@ func main() {
Status: "Tribal Wars | tw!help", Status: "Tribal Wars | tw!help",
ObservationRepository: observationRepo, ObservationRepository: observationRepo,
ServerRepository: serverRepo, ServerRepository: serverRepo,
GroupRepository: groupRepo,
API: api, API: api,
}) })
if err != nil { if err != nil {
@ -70,6 +76,7 @@ func main() {
ServerRepo: serverRepo, ServerRepo: serverRepo,
ObservationRepo: observationRepo, ObservationRepo: observationRepo,
Discord: sess, Discord: sess,
GroupRepo: groupRepo,
API: api, API: api,
}) })
go func() { go func() {

18
models/group.go Normal file
View File

@ -0,0 +1,18 @@
package models
type Group struct {
ID int `pg:",pk" json:"id" gqlgen:"id"`
ConqueredVillagesChannelID string `pg:",use_zero" json:"conqueredVillagesChannelID" gqlgen:"conqueredVillagesChannelID"`
LostVillagesChannelID string `pg:",use_zero" json:"lostVillagesChannelID" gqlgen:"lostVillagesChannelID"`
ServerID string `pg:"on_delete:CASCADE,use_zero" json:"serverID" gqlgen:"serverID"`
Server *Server `json:"server,omitempty" gqlgen:"server"`
Observations Observations `json:"observation,omitempty" gqlgen:"observation"`
}
type GroupFilter struct {
ID []int
ServerID []string
Limit int `urlstruct:",nowhere"`
Offset int `urlstruct:",nowhere"`
Order []string `urlstruct:",nowhere"`
}

View File

@ -1,20 +1,23 @@
package models package models
import "time"
type Observation struct { type Observation struct {
tableName struct{} `pg:",alias:observation"` tableName struct{} `pg:",alias:observation"`
ID int `json:"id" gqlgen:"id"` ID int `json:"id" gqlgen:"id"`
World string `pg:"unique:group_1,use_zero" json:"world" gqlgen:"world"` Server string `pg:"unique:group_1,use_zero" json:"server" gqlgen:"server"`
TribeID int `pg:"unique:group_1,use_zero" json:"tribeID" gqlgen:"tribeID"` TribeID int `pg:"unique:group_1,use_zero" json:"tribeID" gqlgen:"tribeID"`
ServerID string `pg:"on_delete:CASCADE,unique:group_1,use_zero" json:"serverID" gqlgen:"serverID"` GroupID int `pg:"on_delete:CASCADE,unique:group_1,use_zero" json:"groupID" gqlgen:"groupID"`
Server *Server `json:"server,omitempty" gqlgen:"server"` Group *Group `json:"group,omitempty" gqlgen:"group"`
CreatedAt time.Time `pg:"default:now()" json:"createdAt" gqlgen:"createdAt" xml:"createdAt"`
} }
type Observations []*Observation type Observations []*Observation
func (o Observations) Contains(world string, id int) bool { func (o Observations) Contains(server string, id int) bool {
for _, observation := range o { for _, observation := range o {
if observation.TribeID == id && observation.World == world { if observation.TribeID == id && observation.Server == server {
return true return true
} }
} }
@ -22,10 +25,10 @@ func (o Observations) Contains(world string, id int) bool {
} }
type ObservationFilter struct { type ObservationFilter struct {
ID []int ID []int
World []string Server []string
ServerID []string GroupID []int
Limit int `urlstruct:",nowhere"` Limit int `urlstruct:",nowhere"`
Offset int `urlstruct:",nowhere"` Offset int `urlstruct:",nowhere"`
Order []string `urlstruct:",nowhere"` Order []string `urlstruct:",nowhere"`
} }

View File

@ -3,10 +3,8 @@ package models
type Server struct { type Server struct {
tableName struct{} `pg:",alias:server"` tableName struct{} `pg:",alias:server"`
ID string `pg:",pk" json:"id" gqlgen:"id"` ID string `pg:",pk" json:"id" gqlgen:"id"`
ConqueredVillagesChannelID string `pg:",use_zero" json:"conqueredVillagesChannelID" gqlgen:"conqueredVillagesChannelID"` Groups []*Group
LostVillagesChannelID string `pg:",use_zero" json:"lostVillagesChannelID" gqlgen:"lostVillagesChannelID"`
Observations Observations `json:"observation,omitempty" gqlgen:"observation"`
} }
type ServerFilter struct { type ServerFilter struct {

View File

@ -12,5 +12,5 @@ type Repository interface {
Update(ctx context.Context, observation *models.Observation) error Update(ctx context.Context, observation *models.Observation) error
Delete(ctx context.Context, filter *models.ObservationFilter) ([]*models.Observation, error) Delete(ctx context.Context, filter *models.ObservationFilter) ([]*models.Observation, error)
Fetch(ctx context.Context, filter *models.ObservationFilter) ([]*models.Observation, int, error) Fetch(ctx context.Context, filter *models.ObservationFilter) ([]*models.Observation, int, error)
FetchWorlds(ctx context.Context) ([]string, error) FetchServers(ctx context.Context) ([]string, error)
} }

View File

@ -75,15 +75,15 @@ func (repo *pgRepo) Fetch(ctx context.Context, f *models.ObservationFilter) ([]*
return data, total, nil return data, total, nil
} }
func (repo *pgRepo) FetchWorlds(ctx context.Context) ([]string, error) { func (repo *pgRepo) FetchServers(ctx context.Context) ([]string, error) {
data := []*models.Observation{} data := []*models.Observation{}
res := []string{} res := []string{}
err := repo. err := repo.
Model(&data). Model(&data).
Column("world"). Column("server").
Context(ctx). Context(ctx).
Group("world"). Group("server").
Order("world ASC"). Order("server ASC").
Select(&res) Select(&res)
return res, err return res, err
} }

View File

@ -30,7 +30,7 @@ func (repo *pgRepo) Store(ctx context.Context, server *models.Server) error {
Where("id = ?id"). Where("id = ?id").
Returning("*"). Returning("*").
Context(ctx). Context(ctx).
Relation("Observations"). Relation("Groups").
SelectOrInsert(); err != nil { SelectOrInsert(); err != nil {
return err return err
} }
@ -52,7 +52,7 @@ func (repo *pgRepo) Update(ctx context.Context, server *models.Server) error {
func (repo *pgRepo) Fetch(ctx context.Context, f *models.ServerFilter) ([]*models.Server, int, error) { func (repo *pgRepo) Fetch(ctx context.Context, f *models.ServerFilter) ([]*models.Server, int, error) {
var err error var err error
data := []*models.Server{} data := []*models.Server{}
query := repo.Model(&data).Context(ctx).Relation("Observations") query := repo.Model(&data).Context(ctx).Relation("Groups")
if f != nil { if f != nil {
query = query. query = query.