From 482a6d21b784c0a87b24f8b4edf73abed41fafcc 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. --- .../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/services/slack/loads_slack_channel_members.rb b/app/services/slack/loads_slack_channel_members.rb index 6ee17fb..f684b0f 100644 --- a/app/services/slack/loads_slack_channel_members.rb +++ b/app/services/slack/loads_slack_channel_members.rb @@ -14,10 +14,21 @@ def call(channel:) def eligible_user_ids response = retry_when_rate_limited do - ClientWrapper.client.users_list + ClientWrapper.client.users_list(limit: 200) end - (response&.members || []).reject { |u| u.is_bot }.map(&:id) + members = get_paged_members(cursor: response&.response_metadata&.next_cursor, members: response&.members || []) + (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)