Wednesday, July 15, 2026 4:02:00 AM
> community_channels.rb
# frozen_string_literal: true

module ESM
  module Website
    class API
      module Handlers
        ##
        # Returns the community's text channels grouped by category, filtered to
        # channels the bot (and optional user) can read/send in. Format matches
        # what the website's channel picker expects.
        #
        class CommunityChannels
          def self.call(id:, user_id:, **)
            community = ESM::Community.find_by(id: id)
            return if community.nil?

            server = community.discord_server
            return if server.nil?

            user = ESM::User.find_by(id: user_id)

            channels = server.channels.filter_map do |channel|
              bot_can_read = ESM.discord_bot.channel_permission?(:send_messages, channel)
              user_can_read = true
              user_can_read = user.channel_permission?(:read_messages, channel) if user
              next unless bot_can_read && user_can_read

              channel.to_h
            rescue Discordrb::Errors::CodeError, Discordrb::Errors::NoPermission
              # Skip channels the bot can't introspect (lost access mid-list).
              nil
            end

            channels.sort_by! { |c| c[:position] || 0 }

            grouped_channels = channels.filter_map do |category_channel|
              next unless category_channel[:type] == :category

              children = channels.select do |channel|
                channel[:type] == :text && channel.dig(:category, :id) == category_channel[:id]
              end

              [category_channel, children]
            end

            not_categorized_channels = channels.select { |channel| channel[:type] == :text && channel[:category].nil? }
            grouped_channels.unshift([{name: community.community_name}, not_categorized_channels])

            grouped_channels
          rescue Discordrb::Errors::CodeError, Discordrb::Errors::NoPermission
            # Bot can't read the guild's channel list at all. Caller sees nil.
            nil
          end
        end
      end
    end
  end
end
All opinions represented herein are my own
- © 2024 - 2026 itsthedevman
- build 43aa0d7