Skip to content

Commit

Permalink
WIP: Update Send-SlackAPI to support cursor-based pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
rkeithhill-keysight committed Jun 23, 2019
1 parent 326c123 commit 68bc48f
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 72 deletions.
54 changes: 21 additions & 33 deletions PSSlack/Public/Get-SlackUser.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
.FUNCTIONALITY
Slack
#>

[cmdletbinding(DefaultParameterSetName = 'Content')]
param (
[string]$Token = $Script:PSSlack.Token,
Expand All @@ -47,50 +46,43 @@
[switch]$ExcludeBots,
[switch]$Raw
)

begin
{
$body = @{}
if($Presence)
{
if ($Presence) {
$body.add('presence', 1)
}

$params = @{
Token = $Token
Method = 'users.list'
}
if($body.keys.count -gt 0)
{
if ($body.keys.count -gt 0) {
$params.add('body', $Body)
}
$RawUsers = Send-SlackApi @params
$RawUsers = Send-SlackApi @params -EnablePagination

$HasWildCard = $False
foreach($Item in $Name)
{
if($Item -match '\*')
{
$HasWildCard = $false
foreach ($Item in $Name) {
if ($Item -match '\*') {
$HasWildCard = $true
break
}
}

if($Billing)
{
$BillingInfo = Send-SlackApi -Token $Token -Method team.billableInfo
if ($Billing) {
$BillingInfo = Send-SlackApi -Token $Token -Method team.billableInfo -EnablePagination
$UserIDs = $BillingInfo.billable_info.psobject.properties.name
foreach($User in $RawUsers.members)
{
foreach ($User in $RawUsers.members) {
$UserId = $User.Id
if($UserIDs -contains $UserId)
{
if ($UserIDs -contains $UserId) {
Add-Member -InputObject $User -MemberType NoteProperty -Name BillingActive -Value $BillingInfo.billable_info.$UserId.billing_active -Force
}
}
}

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

# allow like operator on each channel requested in the param, avoid dupes
$UserHash = [ordered]@{}
foreach($SlackUser in $AllUsers)
{
foreach($Username in $Name)
{
if($SlackUser.Name -like $Username -and -not $UserHash.Contains($SlackUser.id))
{
foreach ($SlackUser in $AllUsers) {
foreach ($Username in $Name) {
if ($SlackUser.Name -like $Username -and -not $UserHash.Contains($SlackUser.id)) {
$UserHash.Add($SlackUser.Id, $SlackUser)
}
}
}

$Users = $UserHash.Values
}
else # nothing specified
{
else {
# nothing specified
$Users = $RawUsers.members
}

if($Raw)
{
if ($Raw) {
$RawUsers
}
else
{
else {
Parse-SlackUser -InputObject $Users
}
}
}
}
127 changes: 88 additions & 39 deletions PSSlack/Public/Send-SlackAPI.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function Send-SlackApi
[ValidateNotNullOrEmpty()]
[hashtable]$Body = @{ },

[Parameter()]
[ValidateNotNullOrEmpty()]
[ValidateScript({
if (-not $_ -and -not $Script:PSSlack.Token)
Expand All @@ -57,67 +58,115 @@ function Send-SlackApi
})]
[string]$Token = $Script:PSSlack.Token,

[Parameter()]
[string]$Proxy = $Script:PSSlack.Proxy,

[switch]$ForceVerbose = $Script:PSSlack.ForceVerbose
[Parameter()]
[switch]$ForceVerbose = $Script:PSSlack.ForceVerbose,

# If specified, enables cursor-based pagination of results. See https://api.slack.com/docs/pagination
# for the list of Slack REST API methods that support cursor-based pagination.
[Parameter(ParameterSetName="Pagination")]
[switch]
$EnablePagination,

# Specifies the page size when using cursor-based pagination. Slack recommends a range of 100-200.
# The default is 200. Note: Slack limits the max to 1000 on certain APIs. That limit may vary over
# time and over different APIs.
[Parameter(ParameterSetName="Pagination")]
[ValidateRange(1,1000)]
[int]
$PageSize = 200,

# MaxNumberPages can be used to limit the number of pages returned from Slack. The default value is
# 0 which represents no limit i.e. all results are returned.
[Parameter(ParameterSetName="Pagination")]
[ValidateRange(0, [int]::MaxValue)]
[int]
$MaxNumberPages = 0
)

$Params = @{
Uri = "https://slack.com/api/$Method"
ErrorAction = 'Stop'
}
if($Proxy) {
if ($Proxy) {
$Params['Proxy'] = $Proxy
}
if(-not $ForceVerbose) {
$Params.Add('Verbose', $False)
if (-not $ForceVerbose) {
$Params.Add('Verbose', $false)
}
if($ForceVerbose) {
if ($ForceVerbose) {
$Params.Add('Verbose', $true)
}
$Body.token = $Token

try {
$Response = $null
$Response = Invoke-RestMethod @Params -Body $Body
if ($EnablePagination) {
$Params['Uri'] += "?limit=$PageSize"
}
catch {
# (HTTP 429 is "Too Many Requests")
if ($_.Exception.Response.StatusCode -eq 429) {

# Get the time before we can try again.
if( $_.Exception.Response.Headers -and $_.Exception.Response.Headers.Contains('Retry-After') ) {
$RetryPeriod = $_.Exception.Response.Headers.GetValues('Retry-After')
if($RetryPeriod -is [string[]]) {
$RetryPeriod = [int]$RetryPeriod[0]

$Body.token = $Token
$pageCount = 0
$hasMoreData = $true
$paginationUriBase = $Params.Uri

do {
try {
$Response = $null
$Response = Invoke-RestMethod @Params -Body $Body
}
catch {
# (HTTP 429 is "Too Many Requests")
if ($_.Exception.Response.StatusCode -eq 429) {

# Get the time before we can try again.
if ($_.Exception.Response.Headers -and $_.Exception.Response.Headers.Contains('Retry-After') ) {
$RetryPeriod = $_.Exception.Response.Headers.GetValues('Retry-After')
if ($RetryPeriod -is [string[]]) {
$RetryPeriod = [int]$RetryPeriod[0]
}
}
else {
$RetryPeriod = 2
}

Write-Verbose "Sleeping [$RetryPeriod] seconds due to Slack 429 response"
Start-Sleep -Seconds $RetryPeriod
continue
}
elseif ($null -ne $_.ErrorDetails.Message) {
# Convert the error-message to an object. (Invoke-RestMethod will not return data by-default if a 4xx/5xx status code is generated.)
$_.ErrorDetails.Message | ConvertFrom-Json | Parse-SlackError -Exception $_.Exception -ErrorAction Stop
}
else {
$RetryPeriod = 2
Write-Error -Exception $_.Exception -Message "Slack API call failed: $_"
}
Write-Verbose "Sleeping [$RetryPeriod] seconds due to Slack 429 response"
Start-Sleep -Seconds $RetryPeriod
Send-SlackApi @PSBoundParameters

}
elseif ($_.ErrorDetails.Message -ne $null) {
# Convert the error-message to an object. (Invoke-RestMethod will not return data by-default if a 4xx/5xx status code is generated.)
$_.ErrorDetails.Message | ConvertFrom-Json | Parse-SlackError -Exception $_.Exception -ErrorAction Stop

# Check to see if we have confirmation that our API call failed.
# (Responses with exception-generating status codes are handled in the "catch" block above - this one is for errors that don't generate exceptions)
if ($null -ne $Response -and $Response.ok -eq $false) {
$Response | Parse-SlackError
break
}
elseif ($Response) {
Write-Output $Response
if ($EnablePagination) {
$pageCount++

$nextCursor = $Response.response_metadata.next_cursor
if ($nextCursor) {
$encodedNextCursor = [System.Web.HttpUtility]::UrlEncode($nextCursor)
$Params['Uri'] = "${paginationUriBase}&cursor=$encodedNextCursor"
}
else {
$hasMoreData = $false
}
}
}
else {
Write-Error -Exception $_.Exception -Message "Slack API call failed: $_"
Write-Verbose "Something went wrong. `$Response is `$null"
break
}
}

# Check to see if we have confirmation that our API call failed.
# (Responses with exception-generating status codes are handled in the "catch" block above - this one is for errors that don't generate exceptions)
if ($Response -ne $null -and $Response.ok -eq $False) {
$Response | Parse-SlackError
}
elseif($Response) {
Write-Output $Response
}
else {
Write-Verbose "Something went wrong. `$Response is `$null"
}
while ($EnablePagination -and $hasMoreData -and ($MaxNumberPages -and ($pageCount -lt $MaxNumberPages)))
}

0 comments on commit 68bc48f

Please sign in to comment.