From 2e2a9c07f813c8a2b26ef1d0bd9a62a4a236b2b4 Mon Sep 17 00:00:00 2001 From: Ringo Hoffmann Date: Thu, 3 Mar 2022 11:28:31 +0100 Subject: [PATCH] add autoremoval of deleted autovcs [#324, #357] When an auto voice channel is deleted, also remove the entry from the database. --- internal/inits/botsession.go | 5 +- internal/listeners/autovc.go | 266 +++++++++++++++++++---------------- 2 files changed, 146 insertions(+), 125 deletions(-) diff --git a/internal/inits/botsession.go b/internal/inits/botsession.go index 1d25ffc4..094ee915 100644 --- a/internal/inits/botsession.go +++ b/internal/inits/botsession.go @@ -86,6 +86,7 @@ func InitDiscordBotSession(container di.Container) (release func()) { listenerStarboard := listeners.NewListenerStarboard(container) listenerVerification := listeners.NewListenerVerifications(container) + listenerAutoVoice := listeners.NewListenerAutoVoice(container) session.AddHandler(listeners.NewListenerReady(container).Handler) session.AddHandler(listeners.NewListenerMemberAdd(container).Handler) @@ -93,7 +94,6 @@ func InitDiscordBotSession(container di.Container) (release func()) { session.AddHandler(listeners.NewListenerVote(container).Handler) session.AddHandler(listeners.NewListenerChannelCreate(container).Handler) session.AddHandler(listeners.NewListenerVoiceUpdate(container).Handler) - session.AddHandler(listeners.NewListenerAutoVoice(container).Handler) session.AddHandler(listeners.NewListenerKarma(container).Handler) session.AddHandler(listeners.NewListenerAntiraid(container).HandlerMemberAdd) session.AddHandler(listeners.NewListenerBotMention(container).Listener) @@ -118,6 +118,9 @@ func InitDiscordBotSession(container di.Container) (release func()) { session.AddHandler(listenerVerification.HandlerMemberAdd) session.AddHandler(listenerVerification.HandlerMemberRemove) + session.AddHandler(listenerAutoVoice.HandlerVoiceUpdate) + session.AddHandler(listenerAutoVoice.HandlerChannelDelete) + session.AddHandler(func(s *discordgo.Session, e *discordgo.MessageCreate) { atomic.AddUint64(&util.StatsMessagesAnalysed, 1) }) diff --git a/internal/listeners/autovc.go b/internal/listeners/autovc.go index d8225d8c..e9bc4905 100644 --- a/internal/listeners/autovc.go +++ b/internal/listeners/autovc.go @@ -1,124 +1,142 @@ -package listeners - -import ( - "github.com/bwmarrin/discordgo" - "github.com/sarulabs/di/v2" - "github.com/zekroTJA/shinpuru/internal/services/database" - "github.com/zekroTJA/shinpuru/internal/services/permissions" - "github.com/zekroTJA/shinpuru/internal/util/static" - "github.com/zekrotja/dgrs" - "strings" -) - -type ListenerAutoVoice struct { - db database.Database - st *dgrs.State - pmw *permissions.Permissions - autovcCache map[string]string - voiceStateCache map[string]*discordgo.VoiceState -} - -func NewListenerAutoVoice(container di.Container) *ListenerAutoVoice { - return &ListenerAutoVoice{ - db: container.Get(static.DiDatabase).(database.Database), - st: container.Get(static.DiState).(*dgrs.State), - pmw: container.Get(static.DiPermissions).(*permissions.Permissions), - autovcCache: map[string]string{}, - voiceStateCache: map[string]*discordgo.VoiceState{}, - } -} - -func (l *ListenerAutoVoice) Handler(s *discordgo.Session, e *discordgo.VoiceStateUpdate) { - - allowed, _, err := l.pmw.CheckPermissions(s, e.GuildID, e.UserID, "sp.chat.autochannel") - if err != nil || !allowed { - return - } - vsOld, _ := l.voiceStateCache[e.UserID] - vsNew := e.VoiceState - - l.voiceStateCache[e.UserID] = vsNew - - ids, err := l.db.GetGuildAutoVC(e.GuildID) - if err != nil { - return - } - idString := strings.Join(ids, ";") - - if vsOld == nil || (vsOld != nil && vsOld.ChannelID == "") { - - if !strings.Contains(idString, vsNew.ChannelID) { - return - } - - if err := l.createAutoVC(s, e.UserID, e.GuildID, vsNew.ChannelID); err != nil { - return - } - - } else if vsOld != nil && vsNew.ChannelID != "" && vsOld.ChannelID != vsNew.ChannelID { - - // we don't want to delete the channel, if the user get's moved to their auto voicechannel - if vsNew.ChannelID == l.autovcCache[e.UserID] { - - } else if strings.Contains(idString, vsNew.ChannelID) && l.autovcCache[e.UserID] == "" { - if l.autovcCache[e.UserID] == "" { - if err := l.createAutoVC(s, e.UserID, e.GuildID, vsNew.ChannelID); err != nil { - return - } - } else { - if err := l.deleteAutoVC(s, e.UserID); err != nil { - return - } - } - } else if l.autovcCache[e.UserID] != "" { - if err := l.deleteAutoVC(s, e.UserID); err != nil { - return - } - } - - } else if vsOld != nil && vsNew.ChannelID == "" { - if l.autovcCache[e.UserID] != "" { - if err := l.deleteAutoVC(s, e.UserID); err != nil { - return - } - } - - } -} - -func (l *ListenerAutoVoice) createAutoVC(s *discordgo.Session, userID, guildID, parentChannelId string) error { - parentCh, err := l.st.Channel(parentChannelId) - if err != nil { - return err - } - user, err := l.st.User(userID) - if err != nil { - return err - } - ch, err := s.GuildChannelCreate(guildID, user.Username, discordgo.ChannelTypeGuildVoice) - if err != nil { - return err - } - ch, err = s.ChannelEditComplex(ch.ID, &discordgo.ChannelEdit{ - ParentID: parentCh.ParentID, - Position: parentCh.Position, - }) - if err != nil { - return err - } - l.autovcCache[userID] = ch.ID - if err := s.GuildMemberMove(guildID, userID, &ch.ID); err != nil { - return err - } - return nil -} - -func (l *ListenerAutoVoice) deleteAutoVC(s *discordgo.Session, userID string) error { - vcID := l.autovcCache[userID] - _, err := s.ChannelDelete(vcID) - if err != nil { - return err - } - delete(l.autovcCache, userID) - return nil -} +package listeners + +import ( + "strings" + + "github.com/bwmarrin/discordgo" + "github.com/sarulabs/di/v2" + "github.com/zekroTJA/shinpuru/internal/services/database" + "github.com/zekroTJA/shinpuru/internal/services/permissions" + "github.com/zekroTJA/shinpuru/internal/util/static" + "github.com/zekroTJA/shinpuru/pkg/slices" + "github.com/zekrotja/dgrs" +) + +type ListenerAutoVoice struct { + db database.Database + st *dgrs.State + pmw *permissions.Permissions + autovcCache map[string]string + voiceStateCache map[string]*discordgo.VoiceState +} + +func NewListenerAutoVoice(container di.Container) *ListenerAutoVoice { + return &ListenerAutoVoice{ + db: container.Get(static.DiDatabase).(database.Database), + st: container.Get(static.DiState).(*dgrs.State), + pmw: container.Get(static.DiPermissions).(*permissions.Permissions), + autovcCache: map[string]string{}, + voiceStateCache: map[string]*discordgo.VoiceState{}, + } +} + +func (l *ListenerAutoVoice) HandlerVoiceUpdate(s *discordgo.Session, e *discordgo.VoiceStateUpdate) { + + allowed, _, err := l.pmw.CheckPermissions(s, e.GuildID, e.UserID, "sp.chat.autochannel") + if err != nil || !allowed { + return + } + vsOld, _ := l.voiceStateCache[e.UserID] + vsNew := e.VoiceState + + l.voiceStateCache[e.UserID] = vsNew + + ids, err := l.db.GetGuildAutoVC(e.GuildID) + if err != nil { + return + } + idString := strings.Join(ids, ";") + + if vsOld == nil || (vsOld != nil && vsOld.ChannelID == "") { + + if !strings.Contains(idString, vsNew.ChannelID) { + return + } + + if err := l.createAutoVC(s, e.UserID, e.GuildID, vsNew.ChannelID); err != nil { + return + } + + } else if vsOld != nil && vsNew.ChannelID != "" && vsOld.ChannelID != vsNew.ChannelID { + + // we don't want to delete the channel, if the user get's moved to their auto voicechannel + if vsNew.ChannelID == l.autovcCache[e.UserID] { + + } else if strings.Contains(idString, vsNew.ChannelID) && l.autovcCache[e.UserID] == "" { + if l.autovcCache[e.UserID] == "" { + if err := l.createAutoVC(s, e.UserID, e.GuildID, vsNew.ChannelID); err != nil { + return + } + } else { + if err := l.deleteAutoVC(s, e.UserID); err != nil { + return + } + } + } else if l.autovcCache[e.UserID] != "" { + if err := l.deleteAutoVC(s, e.UserID); err != nil { + return + } + } + + } else if vsOld != nil && vsNew.ChannelID == "" { + if l.autovcCache[e.UserID] != "" { + if err := l.deleteAutoVC(s, e.UserID); err != nil { + return + } + } + + } +} + +func (l *ListenerAutoVoice) HandlerChannelDelete(s *discordgo.Session, e *discordgo.ChannelDelete) { + autoVCs, err := l.db.GetGuildAutoVC(e.GuildID) + if err != nil || len(autoVCs) == 0 { + return + } + + i := slices.IndexOf(autoVCs, e.Channel.ID) + if i == -1 { + return + } + + autoVCs, _ = slices.Splice(autoVCs, i, 1) + + l.db.SetGuildAutoVC(e.GuildID, autoVCs) +} + +func (l *ListenerAutoVoice) createAutoVC(s *discordgo.Session, userID, guildID, parentChannelId string) error { + parentCh, err := l.st.Channel(parentChannelId) + if err != nil { + return err + } + user, err := l.st.User(userID) + if err != nil { + return err + } + ch, err := s.GuildChannelCreate(guildID, user.Username, discordgo.ChannelTypeGuildVoice) + if err != nil { + return err + } + ch, err = s.ChannelEditComplex(ch.ID, &discordgo.ChannelEdit{ + ParentID: parentCh.ParentID, + Position: parentCh.Position, + }) + if err != nil { + return err + } + l.autovcCache[userID] = ch.ID + if err := s.GuildMemberMove(guildID, userID, &ch.ID); err != nil { + return err + } + return nil +} + +func (l *ListenerAutoVoice) deleteAutoVC(s *discordgo.Session, userID string) error { + vcID := l.autovcCache[userID] + _, err := s.ChannelDelete(vcID) + if err != nil { + return err + } + delete(l.autovcCache, userID) + return nil +}