Skip to content

Commit 68bc48f

Browse files
WIP: Update Send-SlackAPI to support cursor-based pagination
1 parent 326c123 commit 68bc48f

2 files changed

Lines changed: 109 additions & 72 deletions

File tree

PSSlack/Public/Get-SlackUser.ps1

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
.FUNCTIONALITY
3838
Slack
3939
#>
40-
4140
[cmdletbinding(DefaultParameterSetName = 'Content')]
4241
param (
4342
[string]$Token = $Script:PSSlack.Token,
@@ -47,50 +46,43 @@
4746
[switch]$ExcludeBots,
4847
[switch]$Raw
4948
)
49+
5050
begin
5151
{
5252
$body = @{}
53-
if($Presence)
54-
{
53+
if ($Presence) {
5554
$body.add('presence', 1)
5655
}
5756

5857
$params = @{
5958
Token = $Token
6059
Method = 'users.list'
6160
}
62-
if($body.keys.count -gt 0)
63-
{
61+
if ($body.keys.count -gt 0) {
6462
$params.add('body', $Body)
6563
}
66-
$RawUsers = Send-SlackApi @params
64+
$RawUsers = Send-SlackApi @params -EnablePagination
6765

68-
$HasWildCard = $False
69-
foreach($Item in $Name)
70-
{
71-
if($Item -match '\*')
72-
{
66+
$HasWildCard = $false
67+
foreach ($Item in $Name) {
68+
if ($Item -match '\*') {
7369
$HasWildCard = $true
7470
break
7571
}
7672
}
7773

78-
if($Billing)
79-
{
80-
$BillingInfo = Send-SlackApi -Token $Token -Method team.billableInfo
74+
if ($Billing) {
75+
$BillingInfo = Send-SlackApi -Token $Token -Method team.billableInfo -EnablePagination
8176
$UserIDs = $BillingInfo.billable_info.psobject.properties.name
82-
foreach($User in $RawUsers.members)
83-
{
77+
foreach ($User in $RawUsers.members) {
8478
$UserId = $User.Id
85-
if($UserIDs -contains $UserId)
86-
{
79+
if ($UserIDs -contains $UserId) {
8780
Add-Member -InputObject $User -MemberType NoteProperty -Name BillingActive -Value $BillingInfo.billable_info.$UserId.billing_active -Force
8881
}
8982
}
9083
}
9184

92-
if($Name -and -not $HasWildCard)
93-
{
85+
if ($Name -and -not $HasWildCard) {
9486
# torn between independent queries, or filtering users.list
9587
# submit a PR if this isn't performant enough or doesn't make sense.
9688
$Users = $RawUsers.members |
@@ -102,30 +94,26 @@
10294

10395
# allow like operator on each channel requested in the param, avoid dupes
10496
$UserHash = [ordered]@{}
105-
foreach($SlackUser in $AllUsers)
106-
{
107-
foreach($Username in $Name)
108-
{
109-
if($SlackUser.Name -like $Username -and -not $UserHash.Contains($SlackUser.id))
110-
{
97+
foreach ($SlackUser in $AllUsers) {
98+
foreach ($Username in $Name) {
99+
if ($SlackUser.Name -like $Username -and -not $UserHash.Contains($SlackUser.id)) {
111100
$UserHash.Add($SlackUser.Id, $SlackUser)
112101
}
113102
}
114103
}
104+
115105
$Users = $UserHash.Values
116106
}
117-
else # nothing specified
118-
{
107+
else {
108+
# nothing specified
119109
$Users = $RawUsers.members
120110
}
121111

122-
if($Raw)
123-
{
112+
if ($Raw) {
124113
$RawUsers
125114
}
126-
else
127-
{
115+
else {
128116
Parse-SlackUser -InputObject $Users
129117
}
130118
}
131-
}
119+
}

PSSlack/Public/Send-SlackAPI.ps1

Lines changed: 88 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ function Send-SlackApi
4444
[ValidateNotNullOrEmpty()]
4545
[hashtable]$Body = @{ },
4646

47+
[Parameter()]
4748
[ValidateNotNullOrEmpty()]
4849
[ValidateScript({
4950
if (-not $_ -and -not $Script:PSSlack.Token)
@@ -57,67 +58,115 @@ function Send-SlackApi
5758
})]
5859
[string]$Token = $Script:PSSlack.Token,
5960

61+
[Parameter()]
6062
[string]$Proxy = $Script:PSSlack.Proxy,
6163

62-
[switch]$ForceVerbose = $Script:PSSlack.ForceVerbose
64+
[Parameter()]
65+
[switch]$ForceVerbose = $Script:PSSlack.ForceVerbose,
66+
67+
# If specified, enables cursor-based pagination of results. See https://api.slack.com/docs/pagination
68+
# for the list of Slack REST API methods that support cursor-based pagination.
69+
[Parameter(ParameterSetName="Pagination")]
70+
[switch]
71+
$EnablePagination,
72+
73+
# Specifies the page size when using cursor-based pagination. Slack recommends a range of 100-200.
74+
# The default is 200. Note: Slack limits the max to 1000 on certain APIs. That limit may vary over
75+
# time and over different APIs.
76+
[Parameter(ParameterSetName="Pagination")]
77+
[ValidateRange(1,1000)]
78+
[int]
79+
$PageSize = 200,
80+
81+
# MaxNumberPages can be used to limit the number of pages returned from Slack. The default value is
82+
# 0 which represents no limit i.e. all results are returned.
83+
[Parameter(ParameterSetName="Pagination")]
84+
[ValidateRange(0, [int]::MaxValue)]
85+
[int]
86+
$MaxNumberPages = 0
6387
)
88+
6489
$Params = @{
6590
Uri = "https://slack.com/api/$Method"
6691
ErrorAction = 'Stop'
6792
}
68-
if($Proxy) {
93+
if ($Proxy) {
6994
$Params['Proxy'] = $Proxy
7095
}
71-
if(-not $ForceVerbose) {
72-
$Params.Add('Verbose', $False)
96+
if (-not $ForceVerbose) {
97+
$Params.Add('Verbose', $false)
7398
}
74-
if($ForceVerbose) {
99+
if ($ForceVerbose) {
75100
$Params.Add('Verbose', $true)
76101
}
77-
$Body.token = $Token
78102

79-
try {
80-
$Response = $null
81-
$Response = Invoke-RestMethod @Params -Body $Body
103+
if ($EnablePagination) {
104+
$Params['Uri'] += "?limit=$PageSize"
82105
}
83-
catch {
84-
# (HTTP 429 is "Too Many Requests")
85-
if ($_.Exception.Response.StatusCode -eq 429) {
86-
87-
# Get the time before we can try again.
88-
if( $_.Exception.Response.Headers -and $_.Exception.Response.Headers.Contains('Retry-After') ) {
89-
$RetryPeriod = $_.Exception.Response.Headers.GetValues('Retry-After')
90-
if($RetryPeriod -is [string[]]) {
91-
$RetryPeriod = [int]$RetryPeriod[0]
106+
107+
$Body.token = $Token
108+
$pageCount = 0
109+
$hasMoreData = $true
110+
$paginationUriBase = $Params.Uri
111+
112+
do {
113+
try {
114+
$Response = $null
115+
$Response = Invoke-RestMethod @Params -Body $Body
116+
}
117+
catch {
118+
# (HTTP 429 is "Too Many Requests")
119+
if ($_.Exception.Response.StatusCode -eq 429) {
120+
121+
# Get the time before we can try again.
122+
if ($_.Exception.Response.Headers -and $_.Exception.Response.Headers.Contains('Retry-After') ) {
123+
$RetryPeriod = $_.Exception.Response.Headers.GetValues('Retry-After')
124+
if ($RetryPeriod -is [string[]]) {
125+
$RetryPeriod = [int]$RetryPeriod[0]
126+
}
92127
}
128+
else {
129+
$RetryPeriod = 2
130+
}
131+
132+
Write-Verbose "Sleeping [$RetryPeriod] seconds due to Slack 429 response"
133+
Start-Sleep -Seconds $RetryPeriod
134+
continue
135+
}
136+
elseif ($null -ne $_.ErrorDetails.Message) {
137+
# Convert the error-message to an object. (Invoke-RestMethod will not return data by-default if a 4xx/5xx status code is generated.)
138+
$_.ErrorDetails.Message | ConvertFrom-Json | Parse-SlackError -Exception $_.Exception -ErrorAction Stop
93139
}
94140
else {
95-
$RetryPeriod = 2
141+
Write-Error -Exception $_.Exception -Message "Slack API call failed: $_"
96142
}
97-
Write-Verbose "Sleeping [$RetryPeriod] seconds due to Slack 429 response"
98-
Start-Sleep -Seconds $RetryPeriod
99-
Send-SlackApi @PSBoundParameters
100-
101143
}
102-
elseif ($_.ErrorDetails.Message -ne $null) {
103-
# Convert the error-message to an object. (Invoke-RestMethod will not return data by-default if a 4xx/5xx status code is generated.)
104-
$_.ErrorDetails.Message | ConvertFrom-Json | Parse-SlackError -Exception $_.Exception -ErrorAction Stop
105144

145+
# Check to see if we have confirmation that our API call failed.
146+
# (Responses with exception-generating status codes are handled in the "catch" block above - this one is for errors that don't generate exceptions)
147+
if ($null -ne $Response -and $Response.ok -eq $false) {
148+
$Response | Parse-SlackError
149+
break
150+
}
151+
elseif ($Response) {
152+
Write-Output $Response
153+
if ($EnablePagination) {
154+
$pageCount++
155+
156+
$nextCursor = $Response.response_metadata.next_cursor
157+
if ($nextCursor) {
158+
$encodedNextCursor = [System.Web.HttpUtility]::UrlEncode($nextCursor)
159+
$Params['Uri'] = "${paginationUriBase}&cursor=$encodedNextCursor"
160+
}
161+
else {
162+
$hasMoreData = $false
163+
}
164+
}
106165
}
107166
else {
108-
Write-Error -Exception $_.Exception -Message "Slack API call failed: $_"
167+
Write-Verbose "Something went wrong. `$Response is `$null"
168+
break
109169
}
110170
}
111-
112-
# Check to see if we have confirmation that our API call failed.
113-
# (Responses with exception-generating status codes are handled in the "catch" block above - this one is for errors that don't generate exceptions)
114-
if ($Response -ne $null -and $Response.ok -eq $False) {
115-
$Response | Parse-SlackError
116-
}
117-
elseif($Response) {
118-
Write-Output $Response
119-
}
120-
else {
121-
Write-Verbose "Something went wrong. `$Response is `$null"
122-
}
171+
while ($EnablePagination -and $hasMoreData -and ($MaxNumberPages -and ($pageCount -lt $MaxNumberPages)))
123172
}

0 commit comments

Comments
 (0)