diff options
| author | 2020-01-16 12:09:26 +0700 | |
|---|---|---|
| committer | 2020-01-16 12:09:26 +0700 | |
| commit | f222617484cb2177d4ec92d5392bddfe4fcb7ff1 (patch) | |
| tree | ba3b238d5508e6acf747840550f315bb02f79731 | |
| parent | Discord.py server added to whitelist (diff) | |
| parent | Merge branch 'master' into feature/645-voice-event-log (diff) | |
Merge pull request #686 from python-discord/feature/645-voice-event-log
Log voice channel events
| -rw-r--r-- | bot/cogs/moderation/modlog.py | 93 | ||||
| -rw-r--r-- | bot/constants.py | 7 | ||||
| -rw-r--r-- | config-default.yml | 9 | 
3 files changed, 101 insertions, 8 deletions
| diff --git a/bot/cogs/moderation/modlog.py b/bot/cogs/moderation/modlog.py index 35ef6cbcc..7f24654d8 100644 --- a/bot/cogs/moderation/modlog.py +++ b/bot/cogs/moderation/modlog.py @@ -26,6 +26,12 @@ CHANNEL_CHANGES_SUPPRESSED = ("_overwrites", "position")  MEMBER_CHANGES_SUPPRESSED = ("status", "activities", "_client_status", "nick")  ROLE_CHANGES_UNSUPPORTED = ("colour", "permissions") +VOICE_STATE_ATTRIBUTES = { +    "channel.name": "Channel", +    "self_stream": "Streaming", +    "self_video": "Broadcasting", +} +  class ModLog(Cog, name="ModLog"):      """Logging for server events and staff actions.""" @@ -206,7 +212,7 @@ class ModLog(Cog, name="ModLog"):                  new = value["new_value"]                  old = value["old_value"] -                changes.append(f"**{key.title()}:** `{old}` **->** `{new}`") +                changes.append(f"**{key.title()}:** `{old}` **→** `{new}`")              done.append(key) @@ -284,7 +290,7 @@ class ModLog(Cog, name="ModLog"):                  new = value["new_value"]                  old = value["old_value"] -                changes.append(f"**{key.title()}:** `{old}` **->** `{new}`") +                changes.append(f"**{key.title()}:** `{old}` **→** `{new}`")              done.append(key) @@ -334,7 +340,7 @@ class ModLog(Cog, name="ModLog"):              new = value["new_value"]              old = value["old_value"] -            changes.append(f"**{key.title()}:** `{old}` **->** `{new}`") +            changes.append(f"**{key.title()}:** `{old}` **→** `{new}`")              done.append(key) @@ -487,23 +493,23 @@ class ModLog(Cog, name="ModLog"):                  old = value.get("old_value")                  if new and old: -                    changes.append(f"**{key.title()}:** `{old}` **->** `{new}`") +                    changes.append(f"**{key.title()}:** `{old}` **→** `{new}`")              done.append(key)          if before.name != after.name:              changes.append( -                f"**Username:** `{before.name}` **->** `{after.name}`" +                f"**Username:** `{before.name}` **→** `{after.name}`"              )          if before.discriminator != after.discriminator:              changes.append( -                f"**Discriminator:** `{before.discriminator}` **->** `{after.discriminator}`" +                f"**Discriminator:** `{before.discriminator}` **→** `{after.discriminator}`"              )          if before.display_name != after.display_name:              changes.append( -                f"**Display name:** `{before.display_name}` **->** `{after.display_name}`" +                f"**Display name:** `{before.display_name}` **→** `{after.display_name}`"              )          if not changes: @@ -749,3 +755,76 @@ class ModLog(Cog, name="ModLog"):              Icons.message_edit, Colour.blurple(), "Message edited (After)",              after_response, channel_id=Channels.message_log          ) + +    @Cog.listener() +    async def on_voice_state_update( +        self, +        member: discord.Member, +        before: discord.VoiceState, +        after: discord.VoiceState +    ) -> None: +        """Log member voice state changes to the voice log channel.""" +        if ( +            member.guild.id != GuildConstant.id +            or (before.channel and before.channel.id in GuildConstant.ignored) +        ): +            return + +        if member.id in self._ignored[Event.voice_state_update]: +            self._ignored[Event.voice_state_update].remove(member.id) +            return + +        # Exclude all channel attributes except the name. +        diff = DeepDiff( +            before, +            after, +            exclude_paths=("root.session_id", "root.afk"), +            exclude_regex_paths=r"root\.channel\.(?!name)", +        ) + +        # A type change seems to always take precedent over a value change. Furthermore, it will +        # include the value change along with the type change anyway. Therefore, it's OK to +        # "overwrite" values_changed; in practice there will never even be anything to overwrite. +        diff_values = {**diff.get("values_changed", {}), **diff.get("type_changes", {})} + +        icon = Icons.voice_state_blue +        colour = Colour.blurple() +        changes = [] + +        for attr, values in diff_values.items(): +            if not attr:  # Not sure why, but it happens. +                continue + +            old = values["old_value"] +            new = values["new_value"] + +            attr = attr[5:]  # Remove "root." prefix. +            attr = VOICE_STATE_ATTRIBUTES.get(attr, attr.replace("_", " ").capitalize()) + +            changes.append(f"**{attr}:** `{old}` **→** `{new}`") + +            # Set the embed icon and colour depending on which attribute changed. +            if any(name in attr for name in ("Channel", "deaf", "mute")): +                if new is None or new is True: +                    # Left a channel or was muted/deafened. +                    icon = Icons.voice_state_red +                    colour = Colours.soft_red +                elif old is None or old is True: +                    # Joined a channel or was unmuted/undeafened. +                    icon = Icons.voice_state_green +                    colour = Colours.soft_green + +        if not changes: +            return + +        message = "\n".join(f"{Emojis.bullet} {item}" for item in sorted(changes)) +        message = f"**{member}** (`{member.id}`)\n{message}" + +        await self.send_log_message( +            icon_url=icon, +            colour=colour, +            title="Voice state updated", +            text=message, +            thumbnail=member.avatar_url_as(static_format="png"), +            channel_id=Channels.voice_log +        ) diff --git a/bot/constants.py b/bot/constants.py index 2c0e3b10b..25c7856ba 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -333,6 +333,10 @@ class Icons(metaclass=YAMLGetter):      superstarify: str      unsuperstarify: str +    voice_state_blue: str +    voice_state_green: str +    voice_state_red: str +  class CleanMessages(metaclass=YAMLGetter):      section = "bot" @@ -387,6 +391,7 @@ class Channels(metaclass=YAMLGetter):      userlog: int      user_event_a: int      verification: int +    voice_log: int  class Webhooks(metaclass=YAMLGetter): @@ -553,6 +558,8 @@ class Event(Enum):      message_delete = "message_delete"      message_edit = "message_edit" +    voice_state_update = "voice_state_update" +  # Debug mode  DEBUG_MODE = True if 'local' in os.environ.get("SITE_URL", "local") else False diff --git a/config-default.yml b/config-default.yml index f66ba8794..f842cf606 100644 --- a/config-default.yml +++ b/config-default.yml @@ -100,6 +100,10 @@ style:          superstarify: "https://cdn.discordapp.com/emojis/636288153044516874.png"          unsuperstarify: "https://cdn.discordapp.com/emojis/636288201258172446.png" +        voice_state_blue: "https://cdn.discordapp.com/emojis/656899769662439456.png" +        voice_state_green: "https://cdn.discordapp.com/emojis/656899770094452754.png" +        voice_state_red: "https://cdn.discordapp.com/emojis/656899769905709076.png" +  guild:      id: 267624335836053506 @@ -109,6 +113,7 @@ guild:      channels:          admins:            &ADMINS        365960823622991872          admin_spam:        &ADMIN_SPAM    563594791770914816 +        admins_voice:      &ADMINS_VOICE  500734494840717332          announcements:                    354619224620138496          big_brother_logs:  &BBLOGS        468507907357409333          bot:                              267659945086812160 @@ -139,13 +144,15 @@ guild:          python:                           267624335836053506          reddit:                           458224812528238616          staff_lounge:      &STAFF_LOUNGE  464905259261755392 +        staff_voice:       &STAFF_VOICE   412375055910043655          talent_pool:       &TALENT_POOL   534321732593647616          userlog:                          528976905546760203          user_event_a:      &USER_EVENT_A  592000283102674944          verification:                     352442727016693763 +        voice_log:                        640292421988646961      staff_channels: [*ADMINS, *ADMIN_SPAM, *MOD_SPAM, *MODS, *HELPERS, *ORGANISATION, *DEFCON] -    ignored: [*ADMINS, *MESSAGE_LOG, *MODLOG] +    ignored: [*ADMINS, *MESSAGE_LOG, *MODLOG, *ADMINS_VOICE, *STAFF_VOICE]      roles:          admin:             &ADMIN_ROLE      267628507062992896 | 
