From 903dd5e7b2f4c778f2b34e9e2e6d3b0320fdd12c Mon Sep 17 00:00:00 2001 From: Sara Jackson Date: Wed, 27 Apr 2022 12:01:11 -0400 Subject: [PATCH] Paginate through users If there are/have been over 1000 users in an organization, the eligible_user_ids method in loads_slack_channel_members would only retrieve the first 1000. This change adds a method to follow any pagination cursors and combine user pages together to ensure we have a complete user list to compare to when intersecting with the channel member list. This change also adds a limit of 200 for user retrievable, as recommended by Slack's API guide. --- app/lib/slack/loads_slack_channel_members.rb | 15 +++++++++-- .../slack/loads_slack_channel_members_spec.rb | 27 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/app/lib/slack/loads_slack_channel_members.rb b/app/lib/slack/loads_slack_channel_members.rb index e6c8c2e..86704a5 100644 --- a/app/lib/slack/loads_slack_channel_members.rb +++ b/app/lib/slack/loads_slack_channel_members.rb @@ -9,9 +9,20 @@ def call(channel:) private def eligible_user_ids - response = ClientWrapper.client.users_list + response = ClientWrapper.client.users_list(limit: 200) + members = get_paged_members(cursor: response&.response_metadata&.next_cursor, members: response&.members || []) - (response&.members || []).reject { |u| u.is_bot }.map(&:id) + (members || []).reject { |u| u.is_bot }.map(&:id) + end + + def get_paged_members(cursor:, members:) + while cursor.present? + response = ClientWrapper.client.users_list(cursor: cursor, limit: 200) + members.append(response.members) + cursor = response.response_metadata&.next_cursor + end + + members.flatten end end end diff --git a/spec/lib/slack/loads_slack_channel_members_spec.rb b/spec/lib/slack/loads_slack_channel_members_spec.rb index d48f934..564ff43 100644 --- a/spec/lib/slack/loads_slack_channel_members_spec.rb +++ b/spec/lib/slack/loads_slack_channel_members_spec.rb @@ -35,6 +35,33 @@ expect(members).to eq(slack_members) end + it "loads members found in a channel when pagination is required" do + all_slack_users = (0..205).map do |id| + Slack::Messages::Message.new(id: "USER_ID_#{id}") + end + + slack_members = [ + "USER_ID_1", + "USER_ID_3", + "USER_ID_205" + ] + + response_metadata = Slack::Messages::Message.new(next_cursor: "cursor") + expect(@slack_client).to receive(:users_list).with(limit: 200) { + Slack::Messages::Message.new(ok: true, members: all_slack_users[0..199], response_metadata: response_metadata) + } + expect(@slack_client).to receive(:users_list).with(cursor: response_metadata.next_cursor, limit: 200) { + Slack::Messages::Message.new(ok: true, members: all_slack_users[200..]) + } + expect(@slack_client).to receive(:conversations_members).with(channel: "CHANNEL_ID", limit: 1000) { + Slack::Messages::Message.new(ok: true, members: slack_members) + } + + members = subject.call(channel: "CHANNEL_ID") + + expect(members).to eq(slack_members) + end + it "excludes bots from the returned users" do slack_user = Slack::Messages::Message.new(id: "USER_ID", is_bot: false) slack_app = Slack::Messages::Message.new(id: "APP_ID", is_bot: true)