From 645b55b3c15df08b3d3387cd034dbe419309d444 Mon Sep 17 00:00:00 2001 From: Robert McLeod Date: Mon, 16 Mar 2020 09:35:18 +1100 Subject: [PATCH 1/2] Adds Sharing Agreement commands. +semver: feature --- PwshZendesk.psd1 | 7 +- functions/Get-SharingAgreement.ps1 | 45 ++++++ functions/New-SharingAgreement.ps1 | 86 ++++++++++++ functions/Remove-SharingAgreement.ps1 | 38 +++++ functions/Update-SharingAgreement.ps1 | 50 +++++++ tests/Routes-SharingAgreement.tests.ps1 | 178 ++++++++++++++++++++++++ 6 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 functions/Get-SharingAgreement.ps1 create mode 100644 functions/New-SharingAgreement.ps1 create mode 100644 functions/Remove-SharingAgreement.ps1 create mode 100644 functions/Update-SharingAgreement.ps1 create mode 100644 tests/Routes-SharingAgreement.tests.ps1 diff --git a/PwshZendesk.psd1 b/PwshZendesk.psd1 index dfa3413..e607f07 100644 --- a/PwshZendesk.psd1 +++ b/PwshZendesk.psd1 @@ -35,7 +35,7 @@ Description = 'Wrapper for the Zendesk Rest API' # Minimum version of the PowerShell engine required by this module - PowerShellVersion = '5.0' + PowerShellVersion = '5.1' # Name of the PowerShell host required by this module # PowerShellHostName = '' @@ -96,6 +96,8 @@ 'Get-OrganizationRelated', 'Get-ZendeskOrganizationRelated' 'Get-Problem', 'Get-ZendeskProblem' 'Get-SearchCount', 'Get-ZendeskSearchCount' + 'Get-SharingAgreement', 'Get-ZendeskSharingAgreement' + 'Get-SharingAgreement', 'Get-ZendeskSharingAgreement' 'Get-SuspendedTicket', 'Get-ZendeskSuspendedTicket' 'Get-Tag', 'Get-ZendeskTag' 'Get-Ticket', 'Get-ZendeskTicket' @@ -118,6 +120,7 @@ 'New-GroupMembership', 'New-ZendeskGroupMembership' 'New-Organization', 'New-ZendeskOrganization' 'New-OrganizationMembership', 'New-ZendeskOrganizationMembership' + 'New-SharingAgreement', 'New-ZendeskSharingAgreement' 'New-Ticket', 'New-ZendeskTicket' 'New-UserIdentity', 'New-ZendeskUserIdentity' 'Remove-Attachment', 'Remove-ZendeskAttachment' @@ -125,6 +128,7 @@ 'Remove-GroupMembership', 'Remove-ZendeskGroupMembership' 'Remove-Organization', 'Remove-ZendeskOrganization' 'Remove-OrganizationMembership', 'Remove-ZendeskOrganizationMembership' + 'Remove-SharingAgreement', 'Remove-ZendeskSharingAgreement' 'Remove-SuspendedTicket', 'Remove-ZendeskSuspendedTicket' 'Remove-Tag', 'Remove-ZendeskTag' 'Remove-Ticket', 'Remove-ZendeskTicket' @@ -146,6 +150,7 @@ 'Test-Connection', 'Test-ZendeskConnection' 'Update-Group', 'Update-ZendeskGroup' 'Update-Organization', 'Update-ZendeskOrganization' + 'Update-SharingAgreement', 'Update-ZendeskSharingAgreement' 'Update-Ticket', 'Update-ZendeskTicket' 'Update-User', 'Update-ZendeskUser' 'Update-UserIdentity', 'Update-ZendeskUserIdentity' diff --git a/functions/Get-SharingAgreement.ps1 b/functions/Get-SharingAgreement.ps1 new file mode 100644 index 0000000..cb5bda4 --- /dev/null +++ b/functions/Get-SharingAgreement.ps1 @@ -0,0 +1,45 @@ +function Get-SharingAgreement { + <# + .SYNOPSIS + Returns a sharing agreement for your account. + .DESCRIPTION + Returns a sharing agreement for your account. + .EXAMPLE + PS C:\> Get-ZendeskSharingAgreement + + Lists all sharing agreements + .EXAMPLE + PS C:\> Get-ZendeskSharingAgreement -Id 1 + + Gets the details of the sharing agreement with id 1 + #> + [OutputType([PSCustomObject])] + [CmdletBinding(DefaultParameterSetName = 'Default')] + Param ( + + # Unique Id of the group to retrieve + [Parameter(Mandatory = $false)] + [ValidateRange(1, [Int64]::MaxValue)] + [Int64] + $Id, + + # Zendesk Connection Context from `Get-ZendeskConnection` + [Parameter(Mandatory = $false)] + [PSTypeName('ZendeskContext')] + [PSCustomObject] + $Context = $null + ) + + Assert-IsAgent -Context $Context + + if ($PSBoundParameters.ContainsKey('Id')) { + $path = "/api/v2/sharing_agreements/$Id.json" + $key = 'sharing_agreement' + } else { + $path = '/api/v2/sharing_agreements.json' + $key = 'sharing_agreements' + } + + $result = Invoke-Method -Context $Context -Path $path -Verbose:$VerbosePreference + $result | Select-Object -Expand $key +} diff --git a/functions/New-SharingAgreement.ps1 b/functions/New-SharingAgreement.ps1 new file mode 100644 index 0000000..21a46a6 --- /dev/null +++ b/functions/New-SharingAgreement.ps1 @@ -0,0 +1,86 @@ + +function New-SharingAgreement { + <# + .SYNOPSIS + Creates a sharing agreement. + .DESCRIPTION + Creatas a sharing agreement. Requires sharing to be enabled on the Zendesk instance. For more information see: https://support.zendesk.com/hc/en-us/articles/203661466-Sharing-tickets-with-other-Zendesk-Support-accounts + .EXAMPLE + PS C:\> New-ZendeskSharingAgreement -RemoteSubdomain 'Foo' + + Creates a new sharing agreement with the Foo Zendesk Support instance. + #> + [OutputType([PSCustomObject])] + [CMDletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + Param ( + # Name of this sharing agreement + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + # The direction of the agreement + [Parameter(Mandatory = $false)] + [ValidateSet('inbound', 'outbound')] + [String] + $Type, + + # The status of the agreement + [Parameter(Mandatory = $false)] + [ValidateSet('accepted', 'declined', 'pending', 'inactive')] + [String] + $Status, + + # The Partner System + [Parameter(Mandatory = $false)] + [ValidateSet('jira')] + [String] + $PartnerName, + + # Subdomain of the remote account + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [String] + $RemoteSubdomain, + + # Zendesk Connection Context from `Get-ZendeskConnection` + [Parameter(Mandatory = $false)] + [PSTypeName('ZendeskContext')] + [PSCustomObject] + $Context = $null + ) + + Assert-IsAdmin -Context $Context + + $path = '/api/v2/sharing_agreements.json' + $body = @{ + sharing_agreement = @{ + } + } + + if ($PSBoundParameters.ContainsKey('Name')) { + $body.sharing_agreement['name'] = $Name + } + + if ($PSBoundParameters.ContainsKey('Type')) { + $body.sharing_agreement['type'] = $Type + } + + if ($PSBoundParameters.ContainsKey('Status')) { + $body.sharing_agreement['status'] = $Status + } + + if ($PSBoundParameters.ContainsKey('PartnerName')) { + $body.sharing_agreement['partner_name'] = $PartnerName + } + + if ($PSBoundParameters.ContainsKey('RemoteSubdomain')) { + $body.sharing_agreement['remote_subdomain'] = $RemoteSubdomain + } + + if ($PSCmdlet.ShouldProcess($Name, 'Create Group')) { + $result = Invoke-Method -Context $Context -Method 'Post' -Path $path -Body $body -Verbose:$VerbosePreference + $result + } + +} diff --git a/functions/Remove-SharingAgreement.ps1 b/functions/Remove-SharingAgreement.ps1 new file mode 100644 index 0000000..42e7a4b --- /dev/null +++ b/functions/Remove-SharingAgreement.ps1 @@ -0,0 +1,38 @@ + +function Remove-SharingAgreement { + <# + .SYNOPSIS + Deletes a sharing agreement. + .DESCRIPTION + Deletes a sharing agreement. + .EXAMPLE + PS C:\> Remove-ZendeskSharingAgreement -Id 1 + + Deletes the sharing agreement with Id 1 + #> + [OutputType([PSCustomObject])] + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + Param ( + # Unique Id of group to delete + [Parameter(Mandatory = $true)] + [ValidateRange(1, [Int64]::MaxValue)] + [Int64] + $Id, + + # Zendesk Connection Context from `Get-ZendeskConnection` + [Parameter(Mandatory = $false)] + [PSTypeName('ZendeskContext')] + [PSCustomObject] + $Context = $null + ) + + Assert-IsAdmin -Context $Context + + $path = "/api/v2/sharing_agreements/$Id.json" + + if ($PSCmdlet.ShouldProcess($Id, "Delete Sharing Agreement")) { + $result = Invoke-Method -Context $Context -Method 'Delete' -Path $path -Verbose:$VerbosePreference + $result + } + +} diff --git a/functions/Update-SharingAgreement.ps1 b/functions/Update-SharingAgreement.ps1 new file mode 100644 index 0000000..80e76eb --- /dev/null +++ b/functions/Update-SharingAgreement.ps1 @@ -0,0 +1,50 @@ +function Update-SharingAgreement { + <# + .SYNOPSIS + Updates the status of a sharing agreement + .DESCRIPTION + Updates the status of a sharing agreement + .EXAMPLE + PS C:\> Update-SharingAgreement -Id 1 -Status 'accepted' + + Accepts the sharing agreement with id 1. + .EXAMPLE + PS C:\> Update-SharingAgreement -Id 1 -Status 'declined' + + Declines the sharing agreement with id 1. + #> + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + Param ( + # Unique Id of the group to retrieve + [Parameter(Mandatory = $false)] + [ValidateRange(1, [Int64]::MaxValue)] + [Int64] + $Id, + + # Unique Id of the group to retrieve + [Parameter(Mandatory = $false)] + [ValidateSet('accepted', 'declined', 'pending', 'inactive')] + [String] + $Status, + + # Zendesk Connection Context from `Get-ZendeskConnection` + [Parameter(Mandatory = $false)] + [PSTypeName('ZendeskContext')] + [PSCustomObject] + $Context = $null + ) + + Assert-IsAdmin -Context $Context + + $path = "/api/v2/sharing_agreements/$Id.json" + $body = @{ + sharing_agreement = @{ + status = $Status + } + } + + if ($PSCmdlet.ShouldProcess($Id, 'Update Group Name.')) { + $result = Invoke-Method -Context $Context -Method 'Put' -Path $path -Body $body -Verbose:$VerbosePreference + $result + } +} diff --git a/tests/Routes-SharingAgreement.tests.ps1 b/tests/Routes-SharingAgreement.tests.ps1 new file mode 100644 index 0000000..71396ba --- /dev/null +++ b/tests/Routes-SharingAgreement.tests.ps1 @@ -0,0 +1,178 @@ +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] +Param() + +Import-Module "$PSScriptRoot/../PwshZendesk.psm1" -Force + +Describe 'Groups Routes' { + + InModuleScope PwshZendesk { + + $IsInteractive = [Environment]::GetCommandLineArgs() -join ' ' -notmatch '-NonI' + + $context = @{ + Organization = 'company' + BaseUrl = 'https://company.testdesk.com' + Credential = [System.Management.Automation.PSCredential]::New('email', ('api-key' | ConvertTo-SecureString -AsPlainText -Force)) + User = [PSCustomObject]@{ role = '' } + } + $context | Add-Member -TypeName 'ZendeskContext' + + Mock -ModuleName PwshZendesk Invoke-RestMethod { [PSCustomObject]@{ sharing_agreement = $null; sharing_agreements = $null } } + + Context 'List Sharing Agreements' { + It 'Matches the endpoint' { + if ($IsInteractive) { + throw 'Please run test in non-interactive mode' + } + + $context.User.role = 'admin' + + { Get-SharingAgreement -Context $context } | Should -Not -Throw + Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Get' -and $Uri -match '/api/v2/sharing_agreements\.json' } -Scope It + } + + It 'Does not allow end users to call' { + $context.User.role = 'end-user' + + { Get-SharingAgreement -Context $context } | Should -Throw 'Authenticated user must have role' + } + + It 'Allows agents to call' { + $context.User.role = 'agent' + + { Get-SharingAgreement -Context $context } | Should -Not -Throw + } + + It 'Allows admins to call' { + $context.User.role = 'admin' + + { Get-SharingAgreement -Context $context } | Should -Not -Throw + } + } + + Context 'Show a Sharing Agreement' { + It 'Matches the endpoint' { + if ($IsInteractive) { + throw 'Please run test in non-interactive mode' + } + + $context.User.role = 'admin' + + { Get-SharingAgreement -Context $context -Id 1 } | Should -Not -Throw + Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Get' -and $Uri -match '/api/v2/sharing_agreements/\d+\.json' } -Scope It + } + + It 'Does not allow end users to call' { + $context.User.role = 'end-user' + + { Get-SharingAgreement -Context $context -Id 1 } | Should -Throw 'Authenticated user must have role' + } + + It 'Allows agents to call' { + $context.User.role = 'agent' + + { Get-SharingAgreement -Context $context -Id 1 } | Should -Not -Throw + } + + It 'Allows admins to call' { + $context.User.role = 'admin' + + { Get-SharingAgreement -Context $context -Id 1 } | Should -Not -Throw + } + } + + Context 'Create Sharing Agreement' { + It 'Matches the endpoint' { + if ($IsInteractive) { + throw 'Please run test in non-interactive mode' + } + + $context.User.role = 'admin' + + { New-SharingAgreement -Context $context -Name 'Company @ Zendesk' -Type 'inbound' -RemoteSubdomain 'company' -Confirm:$false } | Should -Not -Throw + Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Post' -and $Uri -match '/api/v2/sharing_agreements\.json' } -Scope It + } + + It 'Does not allow end users to call' { + $context.User.role = 'end-user' + + { New-SharingAgreement -Context $context -Name 'Company @ Zendesk' -Type 'inbound' -RemoteSubdomain 'company' -Confirm:$false } | Should -Throw 'Authenticated user must have role' + } + + It 'Does not allow agents to call' { + $context.User.role = 'agent' + + { New-SharingAgreement -Context $context -Name 'Company @ Zendesk' -Type 'inbound' -RemoteSubdomain 'company' -Confirm:$false } | Should -Throw 'Authenticated user must have role' + } + + It 'Allows admins to call' { + $context.User.role = 'admin' + + { New-SharingAgreement -Context $context -Name 'Company @ Zendesk' -Type 'inbound' -RemoteSubdomain 'company' -Confirm:$false } | Should -Not -Throw + } + } + + Context 'Update a Sharing Agreement' { + It 'Matches the endpoint' { + if ($IsInteractive) { + throw 'Please run test in non-interactive mode' + } + + $context.User.role = 'admin' + + { Update-SharingAgreement -Context $context -Id 1 -Status 'accepted' -Confirm:$false } | Should -Not -Throw + Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Put' -and $Uri -match '/api/v2/sharing_agreements/\d+\.json' } -Scope It + } + + It 'Does not allow end users to call' { + $context.User.role = 'end-user' + + { Update-SharingAgreement -Context $context -Id 1 -Status 'accepted' -Confirm:$false } | Should -Throw 'Authenticated user must have role' + } + + It 'Does not allow agents to call' { + $context.User.role = 'agent' + + { Update-SharingAgreement -Context $context -Id 1 -Status 'accepted' -Confirm:$false } | Should -Throw 'Authenticated user must have role' + } + + It 'Allows admins to call' { + $context.User.role = 'admin' + + { Update-SharingAgreement -Context $context -Id 1 -Status 'accepted' -Confirm:$false } | Should -Not -Throw + } + } + + Context 'Delete a Sharing Agreement' { + It 'Matches the endpoint' { + if ($IsInteractive) { + throw 'Please run test in non-interactive mode' + } + + $context.User.role = 'admin' + + { Remove-SharingAgreement -Context $context -Id 1 -Confirm:$false } | Should -Not -Throw + Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Delete' -and $Uri -match '/api/v2/sharing_agreements/\d+\.json' } -Scope It + } + + It 'Does not allow end users to call' { + $context.User.role = 'end-user' + + { Remove-SharingAgreement -Context $context -Id 1 -Confirm:$false } | Should -Throw 'Authenticated user must have role' + } + + It 'Does not allow agents to call' { + $context.User.role = 'agent' + + { Remove-SharingAgreement -Context $context -Id 1 -Confirm:$false } | Should -Throw 'Authenticated user must have role' + } + + It 'Allows admins to call' { + $context.User.role = 'admin' + + { Remove-SharingAgreement -Context $context -Id 1 -Confirm:$false } | Should -Not -Throw + } + } + } + +} From 3358c38f6746192847c7972a953d2d9d4c288baf Mon Sep 17 00:00:00 2001 From: Robert McLeod Date: Sun, 29 Mar 2020 22:08:08 +1100 Subject: [PATCH 2/2] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Mickaël Derriey --- PwshZendesk.psd1 | 1 - README.md | 4 ++-- functions/Get-SharingAgreement.ps1 | 2 +- functions/New-SharingAgreement.ps1 | 4 ++-- functions/Remove-SharingAgreement.ps1 | 2 +- functions/Update-SharingAgreement.ps1 | 10 +++++----- tests/Routes-SharingAgreement.tests.ps1 | 2 +- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/PwshZendesk.psd1 b/PwshZendesk.psd1 index e607f07..44ac35d 100644 --- a/PwshZendesk.psd1 +++ b/PwshZendesk.psd1 @@ -97,7 +97,6 @@ 'Get-Problem', 'Get-ZendeskProblem' 'Get-SearchCount', 'Get-ZendeskSearchCount' 'Get-SharingAgreement', 'Get-ZendeskSharingAgreement' - 'Get-SharingAgreement', 'Get-ZendeskSharingAgreement' 'Get-SuspendedTicket', 'Get-ZendeskSuspendedTicket' 'Get-Tag', 'Get-ZendeskTag' 'Get-Ticket', 'Get-ZendeskTicket' diff --git a/README.md b/README.md index cc74d15..b4c790b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![Build Status] PwshZendesk is a Zendesk Support API client for Powershell. -PwshZendesk supports Powershell versions 5.0, 5.1, 6, and 7 on all platforms. +PwshZendesk supports Powershell versions 5.1, 6, and 7 on all platforms. ## Getting Started @@ -22,7 +22,7 @@ Head to Admin => Channels => API and click the `+` under "Token Access" ### Installing -PwshZendesk supports Powershell versions 5.0, 5.1, 6, and 7 on all platforms. +PwshZendesk supports Powershell versions 5.1, 6, and 7 on all platforms. It is recommended to install PwshZendesk from the [PowerShell Gallery]: diff --git a/functions/Get-SharingAgreement.ps1 b/functions/Get-SharingAgreement.ps1 index cb5bda4..e9300ab 100644 --- a/functions/Get-SharingAgreement.ps1 +++ b/functions/Get-SharingAgreement.ps1 @@ -17,7 +17,7 @@ function Get-SharingAgreement { [CmdletBinding(DefaultParameterSetName = 'Default')] Param ( - # Unique Id of the group to retrieve + # Unique Id of the sharing agreement to retrieve [Parameter(Mandatory = $false)] [ValidateRange(1, [Int64]::MaxValue)] [Int64] diff --git a/functions/New-SharingAgreement.ps1 b/functions/New-SharingAgreement.ps1 index 21a46a6..be11f9e 100644 --- a/functions/New-SharingAgreement.ps1 +++ b/functions/New-SharingAgreement.ps1 @@ -4,14 +4,14 @@ function New-SharingAgreement { .SYNOPSIS Creates a sharing agreement. .DESCRIPTION - Creatas a sharing agreement. Requires sharing to be enabled on the Zendesk instance. For more information see: https://support.zendesk.com/hc/en-us/articles/203661466-Sharing-tickets-with-other-Zendesk-Support-accounts + Creates a sharing agreement. Requires sharing to be enabled on the Zendesk instance. For more information see: https://support.zendesk.com/hc/en-us/articles/203661466-Sharing-tickets-with-other-Zendesk-Support-accounts .EXAMPLE PS C:\> New-ZendeskSharingAgreement -RemoteSubdomain 'Foo' Creates a new sharing agreement with the Foo Zendesk Support instance. #> [OutputType([PSCustomObject])] - [CMDletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] Param ( # Name of this sharing agreement [Parameter(Mandatory = $false)] diff --git a/functions/Remove-SharingAgreement.ps1 b/functions/Remove-SharingAgreement.ps1 index 42e7a4b..f7b1e4d 100644 --- a/functions/Remove-SharingAgreement.ps1 +++ b/functions/Remove-SharingAgreement.ps1 @@ -13,7 +13,7 @@ function Remove-SharingAgreement { [OutputType([PSCustomObject])] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] Param ( - # Unique Id of group to delete + # Unique Id of sharing agreement to delete [Parameter(Mandatory = $true)] [ValidateRange(1, [Int64]::MaxValue)] [Int64] diff --git a/functions/Update-SharingAgreement.ps1 b/functions/Update-SharingAgreement.ps1 index 80e76eb..2dddda3 100644 --- a/functions/Update-SharingAgreement.ps1 +++ b/functions/Update-SharingAgreement.ps1 @@ -15,14 +15,14 @@ function Update-SharingAgreement { #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] Param ( - # Unique Id of the group to retrieve - [Parameter(Mandatory = $false)] + # Unique Id of the sharing agreement to update + [Parameter(Mandatory = $true)] [ValidateRange(1, [Int64]::MaxValue)] [Int64] $Id, - # Unique Id of the group to retrieve - [Parameter(Mandatory = $false)] + # The status of the agreement + [Parameter(Mandatory = $true)] [ValidateSet('accepted', 'declined', 'pending', 'inactive')] [String] $Status, @@ -43,7 +43,7 @@ function Update-SharingAgreement { } } - if ($PSCmdlet.ShouldProcess($Id, 'Update Group Name.')) { + if ($PSCmdlet.ShouldProcess($Id, 'Update Sharing Agreement.')) { $result = Invoke-Method -Context $Context -Method 'Put' -Path $path -Body $body -Verbose:$VerbosePreference $result } diff --git a/tests/Routes-SharingAgreement.tests.ps1 b/tests/Routes-SharingAgreement.tests.ps1 index 71396ba..bf8122c 100644 --- a/tests/Routes-SharingAgreement.tests.ps1 +++ b/tests/Routes-SharingAgreement.tests.ps1 @@ -3,7 +3,7 @@ Param() Import-Module "$PSScriptRoot/../PwshZendesk.psm1" -Force -Describe 'Groups Routes' { +Describe 'Sharing Agreement Routes' { InModuleScope PwshZendesk {