Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Update Send-SlackAPI to support cursor-based pagination #91

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
}
}
}
130 changes: 89 additions & 41 deletions PSSlack/Public/Send-SlackAPI.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function Send-SlackApi
Slack
#>
[OutputType([String])]
[cmdletbinding()]
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
Expand All @@ -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,114 @@ 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 = $nextCursor -replace '=$','%3D'
$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 -eq 0) -or ($pageCount -lt $MaxNumberPages)))
}