@@ -127,6 +132,7 @@ A dropdown menu to categorize the ticket's subject.
* **Field ID**: `40971535122835`
**Field values:**
+
| Field option title | Tag |
| :----------------- | :---- |
| Delivery | `delivery` |
@@ -142,6 +148,7 @@ A dropdown menu to specify the type of refund being processed.
* **Field ID**: `45241019372563`
**Field values:**
+
| Field option title | Tag | Default |
| :----------------- | :---- |:---:|
| Full Refund | `full_refund` | |
@@ -217,6 +224,16 @@ A multi-select dropdown for reporting one or more errors.
---
+## Expected Locales
+A few locales are to be enabled. See Zendesk's current docs on how to do that.
+
+The following languages are required for testing:
+- Spanish (`es`)
+- French (`fr`)
+- English (`en`)
+
+---
+
## Testing Strategy
One of the most important parts of contributing to z4j is getting tests right. A test is written adequately if:
@@ -292,6 +309,8 @@ This method is a little tricky to test for negative tests because the only way t
[branches of code]:https://medium.com/@zubairkhansh/branch-testing-and-branch-coverage-3fb4bbd9f949
[code of conduct]:CODE_OF_CONDUCT.md
[conventional commits]:https://www.conventionalcommits.org/en/v1.0.0/
+[Custom ticket fields]:#custom-ticket-fields-setup
+[Expected locales]:#Expected-Locales
[delegate build and run actions to gradle]:https://www.jetbrains.com/help/idea/work-with-gradle-projects.html#delegate_build_gradle
[different roles]:#Required-Roles-for-Testing
[google's java style guide]:https://google.github.io/styleguide/javaguide.html
@@ -299,7 +318,7 @@ This method is a little tricky to test for negative tests because the only way t
[gradle]:https://gradle.org/maven-and-gradle/
[gradle wrapper]:https://docs.gradle.org/current/userguide/gradle_wrapper_basics.html
[Git]:https://gist.github.com/Jonathan-Zollinger/8d9a231a57f3d33ff813989c34df00e0
-[graal community distro]:https://www.graalvm.org/release-notes/JDK_21/
+[graalvm]:https://www.graalvm.org/release-notes/JDK_21/
[Graal-CE 21]:https://www.graalvm.org/jdk21/docs/
[Environment Variables]:#Required-Environment-Variables
[source function]:https://gist.github.com/Jonathan-Zollinger/96160f971741f5f3a8749d10127e7764
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
index cb4122f..f0213f1 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ To get a local copy up and running, please follow the detailed setup instruction
| Gradle Kotlin | Gradle |
|:-----------------------------------------------|:----------------------------------------------|
-| implementation("lol.pbu:z4j:0.1.0") | implementation 'lol.pbu:z4j:0.1.0'
|
+| implementation("lol.pbu:z4j:0.1.1") | implementation 'lol.pbu:z4j:0.1.1'
|
**Maven**
@@ -26,7 +26,7 @@ To get a local copy up and running, please follow the detailed setup instruction
lol.pbu
z4j
- 0.1.0
+ 0.1.1
```
diff --git a/build.gradle.kts b/build.gradle.kts
index 5f3a05d..51ef51a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -19,7 +19,6 @@ version = project.properties["z4jVersion"]!!
val dataFakerVersion = project.properties["dataFakerVersion"]!!
val lombokVersion = project.properties["lombokVersion"]!!
-extra["netty.version"] = project.properties["nettyVersion"]!!
configurations.create("lombok")
@@ -35,9 +34,11 @@ dependencies {
implementation("io.micronaut.reactor:micronaut-reactor-http-client")
implementation("io.micronaut.serde:micronaut-serde-jackson")
implementation("io.micronaut.validation:micronaut-validation")
+ implementation("io.micronaut:micronaut-retry")
"lombok"("org.projectlombok:lombok:${lombokVersion}")
runtimeOnly("org.yaml:snakeyaml")
testImplementation("net.datafaker:datafaker:$dataFakerVersion")
+ testImplementation("ch.qos.logback:logback-classic")
}
java {
@@ -60,7 +61,7 @@ micronaut {
annotations("lol.pbu.*")
}
openapi {
- version = "6.19.3"
+ version = "6.20.0"
client(file("src/main/resources/z4j.yaml")) {
apiPackageName.set("lol.pbu.z4j.client")
modelPackageName.set("lol.pbu.z4j.model")
@@ -71,6 +72,7 @@ micronaut {
apiNameSuffix.set("Client")
alwaysUseGenerateHttpResponse.set(false)
generateHttpResponseWhereRequired.set(false)
+ additionalProperties.put("retryable", "true")
}
}
}
@@ -86,11 +88,6 @@ tasks.jacocoTestReport {
xml.required.set(true)
html.required.set(true)
}
- classDirectories.setFrom(files(classDirectories.files.map {
- fileTree(it) {
- exclude("lol/pbu/Application.class")
- }
- }))
}
tasks.test {
diff --git a/cleanup_categories.ps1 b/cleanup_categories.ps1
new file mode 100644
index 0000000..9cab475
--- /dev/null
+++ b/cleanup_categories.ps1
@@ -0,0 +1,77 @@
+#Requires -Version 5.1
+
+<#
+.SYNOPSIS
+ This script paginates through all pages of the GET /api/v2/help_center/categories endpoint and deletes all categories.
+.DESCRIPTION
+ This script will first check for the presence of the following environment variables:
+ - Z4J_URL: The URL of your Zendesk instance (e.g., https://your-subdomain.zendesk.com)
+ - Z4J_TOKEN: Your Zendesk API token.
+ - Z4J_ADMIN_EMAIL: The email address of a Zendesk admin.
+
+ If all environment variables are present, it will then:
+ 1. Paginate through all categories.
+ 2. Delete each of those categories.
+.NOTES
+ Author: Jonathan
+ Date: $(Get-Date -Format "yyyy-MM-dd")
+#>
+
+param()
+
+#region Environment Variable Validation
+$requiredEnvVars = @("Z4J_URL", "Z4J_TOKEN", "Z4J_ADMIN_EMAIL")
+$missingEnvVars = @()
+
+foreach ($var in $requiredEnvVars) {
+ if (-not (Test-Path "env:$var")) {
+ $missingEnvVars += $var
+ }
+}
+
+if ($missingEnvVars.Count -gt 0) {
+ Write-Error "The following environment variables are not set: $($missingEnvVars -join ', ')"
+ exit 1
+}
+#endregion
+
+$Z4JUrl = $env:Z4J_URL
+$apiToken = $env:Z4J_TOKEN
+$adminEmail = $env:Z4J_ADMIN_EMAIL
+
+$credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("${adminEmail}/token:${apiToken}"))
+$headers = @{
+ "Authorization" = "Basic $credentials"
+ "Content-Type" = "application/json"
+}
+
+$nextPage = "$Z4JUrl/api/v2/help_center/categories"
+
+do {
+ try {
+ Write-Host "Fetching categories from $nextPage"
+ $response = Invoke-RestMethod -Uri $nextPage -Method Get -Headers $headers
+
+ if ($null -ne $response.categories) {
+ foreach ($category in $response.categories) {
+ Write-Host "Deleting category: $($category.name) (ID: $($category.id))"
+ $deleteUrl = "$Z4JUrl/api/v2/help_center/categories/$($category.id)"
+ try {
+ Invoke-RestMethod -Uri $deleteUrl -Method Delete -Headers $headers
+ Write-Host "Successfully deleted category: $($category.name)"
+ }
+ catch {
+ Write-Error "Error deleting category with ID $($category.id): $_"
+ }
+ }
+ }
+
+ $nextPage = $response.next_page
+ }
+ catch {
+ Write-Error "Error fetching categories: $_"
+ exit 1
+ }
+} while ($null -ne $nextPage)
+
+Write-Host "Category cleanup complete."
\ No newline at end of file
diff --git a/cleanup_user_segments.ps1 b/cleanup_user_segments.ps1
index 568b07a..4f7b908 100644
--- a/cleanup_user_segments.ps1
+++ b/cleanup_user_segments.ps1
@@ -5,9 +5,9 @@
This script paginates through all pages of the GET /api/v2/help_center/user_segments endpoint and deletes any user segment that is not built-in.
.DESCRIPTION
This script will first check for the presence of the following environment variables:
- - ZENDESK_URL: The URL of your Zendesk instance (e.g., https://your-subdomain.zendesk.com)
- - ZENDESK_API_TOKEN: Your Zendesk API token.
- - ZENDESK_ADMIN_EMAIL: The email address of a Zendesk admin.
+ - Z4J_URL: The URL of your Zendesk instance (e.g., https://your-subdomain.zendesk.com)
+ - Z4J_TOKEN: Your Zendesk API token.
+ - Z4J_ADMIN_EMAIL: The email address of a Zendesk admin.
If all environment variables are present, it will then:
1. Paginate through all user segments.
@@ -21,7 +21,7 @@
param()
#region Environment Variable Validation
-$requiredEnvVars = @("ZENDESK_URL", "ZENDESK_API_TOKEN", "ZENDESK_ADMIN_EMAIL")
+$requiredEnvVars = @("Z4J_URL", "Z4J_TOKEN", "Z4J_ADMIN_EMAIL")
$missingEnvVars = @()
foreach ($var in $requiredEnvVars) {
@@ -36,9 +36,9 @@ if ($missingEnvVars.Count -gt 0) {
}
#endregion
-$zendeskUrl = $env:ZENDESK_URL
-$apiToken = $env:ZENDESK_API_TOKEN
-$adminEmail = $env:ZENDESK_ADMIN_EMAIL
+$Z4JUrl = $env:Z4J_URL
+$apiToken = $env:Z4J_TOKEN
+$adminEmail = $env:Z4J_ADMIN_EMAIL
$credentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("${adminEmail}/token:${apiToken}"))
$headers = @{
@@ -46,7 +46,7 @@ $headers = @{
"Content-Type" = "application/json"
}
-$nextPage = "$zendeskUrl/api/v2/help_center/user_segments"
+$nextPage = "$Z4JUrl/api/v2/help_center/user_segments"
do {
try {
@@ -57,7 +57,7 @@ do {
foreach ($segment in $response.user_segments) {
if ($segment.built_in -eq $false) {
Write-Host "Deleting user segment: $($segment.name) (ID: $($segment.id))"
- $deleteUrl = "$zendeskUrl/api/v2/help_center/user_segments/$($segment.id)"
+ $deleteUrl = "$Z4JUrl/api/v2/help_center/user_segments/$($segment.id)"
try {
Invoke-RestMethod -Uri $deleteUrl -Method Delete -Headers $headers
Write-Host "Successfully deleted user segment: $($segment.name)"
diff --git a/gradle.properties b/gradle.properties
index 5beb955..7e7d882 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,6 @@
-micronautVersion=4.8.3
-z4jVersion=0.1.0
-nettyVersion=4.1.124.Final
-lombokVersion=1.18.42
+micronautVersion=4.10.10
+z4jVersion=0.1.1
+lombokVersion=1.18.44
dataFakerVersion=2.5.4
org.gradle.jvmargs=-Xmx4096M
# SonarQube Project Configuration
@@ -14,5 +13,4 @@ systemProp.sonar.tests=src/test/groovy
systemProp.sonar.junit.reportPaths=build/test-results/test
systemProp.sonar.coverage.jacoco.xmlReportPath=build/reports/jacoco/test/jacocoTestReport.xml
systemProp.sonar.java.binaries=build/classes/java/main
-systemProp.sonar.java.test.binaries=build/classes/groovy/test
-
+systemProp.sonar.java.test.binaries=build/classes/groovy/test
\ No newline at end of file
diff --git a/renovate.json b/renovate.json
index 6f2f5ef..c811878 100644
--- a/renovate.json
+++ b/renovate.json
@@ -3,7 +3,7 @@
"extends": [
"config:recommended"
],
- "baseBranches": [
+ "baseBranchPatterns": [
"0.1.1"
]
}
diff --git a/src/main/resources/z4j.yaml b/src/main/resources/z4j.yaml
index 9e71288..7de98a7 100644
--- a/src/main/resources/z4j.yaml
+++ b/src/main/resources/z4j.yaml
@@ -14,7 +14,7 @@ paths:
Returns a list of all system and custom ticket fields in your account.
For end users, only the ticket fields with visible_in_portal set to true are returned.
Consider caching this resource to use with the{@link TicketClient}.
- Allowed For
+ lookup relationships) to
+ href="/api-reference/ticketing/lookup_relationships/lookup_relationships/'>lookup relationships) to
another object such as a user, ticket, or organization
@@ -114,13 +114,13 @@ paths:
Note: Tags can't be re-used across custom ticket fields. For example, if you configure a tag for
a checkbox field, you can't use that tag value for a dropdown (tagger) field option. The use of tags isn't
validated and can prevent editing in the future.
- See About custom field types in the Zendesk
+
See About custom field types in the Zendesk
Help Center.
- Allowed For
+ Field limits
+ Returns a number of ticket properties though not the ticket comments. To get the comments, use List Comments
+ This endpoint supports pagination as described in Pagination.
+ Pagination
+ See Pagination.
responses:
"200":
description: OK Response
@@ -469,12 +469,545 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/TopicsResponse'
+ /api/v2/help_center/{locale}/categories:
+ parameters:
+ - $ref: '#/components/parameters/OptionalLocale'
+ get:
+ operationId: ListCategories
+ tags:
+ - Category
+ summary: List Categories by Locale
+ description: |-
+ Allowed for
+
+ The response will list only the categories that the agent, end user, or
+ anonymous user can view in the help center.
+ Translations are embedded within the category because they're
+ not shared between resources.
+ parameters:
+ - name: sort_by
+ in: query
+ description: |
+ The sort_by parameter can have one of the following values:
+
+
+
+ | value |
+ description |
+
+
+
+
+ position |
+ order set manually using the Arrange Content page. Default order |
+
+
+ created_at |
+ order by creation time |
+
+
+ updated_at |
+ order by update time |
+
+
+
+ schema:
+ type: string
+ enum:
+ - position
+ - created_at
+ - updated_at
+ - name: sort_order
+ in: query
+ description: |
+
+
+
+ | value |
+ description |
+
+
+
+
+ asc |
+ ascending order |
+
+
+ desc |
+ descending order |
+
+
+
+ schema:
+ type: string
+ enum:
+ - asc
+ - desc
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoriesResponse'
+ post:
+ operationId: CreateCategory
+ tags:
+ - Category
+ summary: Create Category by Locale
+ description: |-
+ You must specify a category name and locale. The locale can be omitted if it's specified
+ in the URL. Optionally, you can specify multiple translations for
+ the category. The specified locales must be enabled for the current Help Center.
+ Allowed for
+
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ category:
+ $ref: '#/components/schemas/Category'
+ responses:
+ "201":
+ description: Created response
+ headers:
+ Location:
+ description: The URL of the new created category
+ schema:
+ type: string
+ format: url
+ example: https://{subdomain}.zendesk.com/api/v2/help_center/categories/{category_id}.json
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoryResponse'
+ /api/v2/help_center/{locale}/categories/{category_id}:
+ parameters:
+ - $ref: '#/components/parameters/OptionalLocale'
+ - $ref: '#/components/parameters/CategoryId'
+ get:
+ operationId: ShowCategory
+ tags:
+ - Category
+ summary: Show Category by Locale
+ description: |-
+ Note: {/locale} is an optional parameter for admins and agents. End users and anonymous users must provide the parameter.
+ Allowed for
+
+ Translations are embedded within the category because they're
+ not shared between resources.
+ responses:
+ "200":
+ description: description
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoryResponse'
+ put:
+ operationId: UpdateCategory
+ tags:
+ - Category
+ summary: Update Category by Locale
+ description: |-
+ These endpoints only update category-level metadata such as the sorting position.
+ They don't update category translations.
+ Allowed for
+
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ category:
+ $ref: '#/components/schemas/Category'
+ responses:
+ "200":
+ description: OK Response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoryResponse'
+ delete:
+ operationId: DeleteCategory
+ tags:
+ - Category
+ summary: Delete Category by Locale
+ description: |-
+ WARNING: Every section and all articles in the category will also be deleted.
+ Allowed for
+
+ responses:
+ "204":
+ description: No content
+ /api/v2/help_center/categories/{category_id}/source_locale:
+ parameters:
+ - $ref: '#/components/parameters/CategoryId'
+ put:
+ operationId: UpdateCategorySourceLocale
+ tags:
+ - Category
+ summary: Update Category Source Locale by Locale
+ description: |-
+ The endpoint updates the category source_locale property
+ Allowed for
+
+ responses:
+ "200":
+ description: OK Response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoryResponse'
+ /api/v2/help_center/categories:
+ get:
+ operationId: ListCategoriesNoLocale
+ tags:
+ - Category
+ summary: List Categories
+ description: |-
+ Allowed for
+
+ The response will list only the categories that the agent can view in the help center.
+ parameters:
+ - name: sort_by
+ in: query
+ description: Sorts the results by one of the accepted values
+ schema:
+ type: string
+ enum:
+ - position
+ - created_at
+ - updated_at
+ - name: sort_order
+ in: query
+ description: Selects the order of the results.
+ schema:
+ type: string
+ enum:
+ - asc
+ - desc
+ responses:
+ "200":
+ description: description
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoriesResponse'
+ post:
+ operationId: CreateCategoryNoLocale
+ tags:
+ - Category
+ summary: Create Category
+ description: |-
+ You must specify a category name and locale.
+ Optionally, you can specify multiple translations for
+ the category. The specified locales must be enabled for the current Help Center.
+ Allowed for
+
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ category:
+ $ref: '#/components/schemas/Category'
+ responses:
+ "201":
+ description: OK Response
+ headers:
+ Location:
+ description: The URL of the new created category
+ schema:
+ type: string
+ format: url
+ example: https://{subdomain}.zendesk.com/api/v2/help_center/categories/{category_id}.json
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoryResponse'
+ /api/v2/help_center/categories/{category_id}:
+ parameters:
+ - $ref: '#/components/parameters/CategoryId'
+ get:
+ operationId: ShowCategoryNoLocale
+ tags:
+ - Category
+ summary: Show Category
+ description: |-
+ Note: {/locale} is an optional parameter for admins and agents. End users and anonymous users must provide the parameter.
+ Allowed for
+
+ Translations are embedded within the category because they're
+ not shared between resources.
+ responses:
+ "200":
+ description: description
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoryResponse'
+ put:
+ operationId: UpdateCategoryNoLocale
+ tags:
+ - Category
+ summary: Update Category
+ description: |-
+ These endpoints only update category-level metadata such as the sorting position.
+ They don't update category translations.
+ Allowed for
+
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ category:
+ $ref: '#/components/schemas/Category'
+ responses:
+ "200":
+ description: OK Response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CategoryResponse'
+ delete:
+ operationId: DeleteCategoryNoLocale
+ tags:
+ - Category
+ summary: Delete Category
+ description: |-
+ WARNING: Every section and all articles in the category will also be deleted.
+ Allowed for
+
+ responses:
+ "204":
+ description: No content
+ /api/v2/search:
+ get:
+ operationId: List
+ tags:
+ - Search
+ summary: List Search Results
+ description: |-
+ Returns the search results. See Query syntax for details on the {@code query} parameter.
+ Use the ampersand character (&) to append the {@code sort_by} or {@code sort_order} parameters to the URL.
+ For examples, see Searching with Zendesk API.
+ This endpoint has its own rate limit. The rate limit counts towards the global API rate limit. See Limits.
+ Allowed For
+
+ Pagination
+
+ - Offset pagination only
+
+ Offset pagination may result in duplicate results when paging. You can also use the
+ Export Search Results endpoint, which
+ uses cursor-based pagination and doesn't return duplicate results. See
+ Using cursor pagination for more information.
+ parameters:
+ - name: query
+ in: query
+ description: Returns the search results. See Query syntax for details on the {@code query} parameter. For details on the query syntax, see the Zendesk Support search reference.
+ required: true
+ schema:
+ type: string
+ - name: sort_by
+ in: query
+ description: One of {@code updated_at}, {@code created_at}, {@code priority}, {@code status}, or {@code ticket_type}. Defaults to sorting by relevance
+ schema:
+ $ref: '#/components/schemas/SearchSortBy'
+ - name: sort_order
+ in: query
+ description: Defaults to descending
+ schema:
+ $ref: '#/components/schemas/SearchSortOrder'
+ - $ref: '#/components/parameters/SearchInclude'
+ responses:
+ "200":
+ description: Success response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SearchResponse'
+ "400":
+ description: Error response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/BadRequestErrorResponse'
+ /api/v2/search/count:
+ get:
+ operationId: Count
+ tags:
+ - Search
+ summary: Show Search Results Count
+ description: |
+ Returns the number of items matching the query rather than returning the items. The search string works the same as a regular search.
+
+ Allowed For
+
+ parameters:
+ - name: query
+ in: query
+ description: Returns the search results. See Query syntax for details on the {@code query} parameter. For details on the query syntax, see the Zendesk Support search reference.
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Success response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SearchResponse'
+ "400":
+ description: Error response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/BadRequestErrorResponse'
+ /api/v2/search/export:
+ get:
+ operationId: Export
+ tags:
+ - Search
+ summary: Export Search Results
+ description: |-
+ Exports a set of results. See Query syntax for the syntax of the {@code query} parameter.
+ Use this endpoint for search queries that will return more than 1000 results. The result set is ordered only by the {@code created_at} attribute.
+ The search only returns results of a single object type. The following object types are supported: ticket, organization, user, or group.
+ You must specify the type in the {@code filter[type]} parameter. Searches with type in the query string will result in an error.
+ Allowed For
+
+ Pagination
+
+ See Pagination.
+ Returns a maximum of 1000 records per page. The number of results shown in a page is determined by the {@code page[size]} parameter.
+ Note: You may experience a speed reduction or a timeout if you request 1000 results per page and you have many archived tickets in the results. Try reducing the number of results per page. We recommend 100 results per page.
+ The cursor specified by the {@code after_cursor} property in a response expires after one hour.
+ For more information on cursor-based pagination, see the following articles:
+
+ Export Search Results Limits
+ This API endpoint is rate-limited to 100 requests per minute per account. The limit also counts towards the global API rate limit.
+ parameters:
+ - name: query
+ in: query
+ description: Returns the search results. See Query syntax for details on the {@code query} parameter. For details on the query syntax, see the Zendesk Support search reference.
+ required: true
+ schema:
+ type: string
+ - name: page[size]
+ in: query
+ description: The number of results shown in a page.
+ required: true
+ schema:
+ type: integer
+ - name: page[after]
+ in: query
+ description: The cursor token for fetching the next page of results.
+ required: true
+ schema:
+ type: string
+ - name: filter[type]
+ in: query
+ description: The object type returned by the export query. Can be `ticket`, `organization`, `user`, or `group`.
+ required: true
+ schema:
+ $ref: '#/components/schemas/SearchExportType'
+ - $ref: '#/components/parameters/SearchInclude'
+ responses:
+ "200":
+ description: Success response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SearchResponse'
+ "400":
+ description: Error response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/BadRequestErrorResponse'
components:
schemas:
+ SearchSortBy:
+ type: string
+ enum:
+ - updated_at
+ - created_at
+ - priority
+ - status
+ - ticket_type
+ x-enum-name: SearchSortBy
+ x-enum-varnames:
+ - UPDATED_AT
+ - CREATED_AT
+ - PRIORITY
+ - STATUS
+ - TICKET_TYPE
+ SearchSortOrder:
+ type: string
+ enum:
+ - asc
+ - desc
+ x-enum-name: SearchSortOrder
+ x-enum-varnames:
+ - ASCENDING
+ - DESCENDING
+ SearchExportType:
+ type: string
+ enum:
+ - ticket
+ - organization
+ - user
+ - group
+ x-enum-name: SearchExportType
+ x-enum-varnames:
+ - TICKET
+ - ORGANIZATION
+ - USER
+ - GROUP
Attachment:
type: object
description: |
- A file represented as an Attachment object
+ A file represented as an Attachment object
allOf:
- $ref: '#/components/schemas/AttachmentBase'
- $ref: '#/components/schemas/AttachmentThumbnails'
@@ -488,7 +1021,7 @@ components:
content_url:
type: string
description: |
- A full URL where the attachment image file can be downloaded. The file may be hosted externally so take care not to inadvertently send Zendesk authentication credentials. See Working with url properties
+ A full URL where the attachment image file can be downloaded. The file may be hosted externally so take care not to inadvertently send Zendesk authentication credentials. See Working with url properties
readOnly: true
deleted:
type: boolean
@@ -519,6 +1052,17 @@ components:
malware_scan_result:
type: string
description: 'The result of the malware scan. There is a delay between the time the attachment is uploaded and when the malware scan is completed. Usually the scan is done within a few seconds, but high load conditions can delay the scan results. Possible values: "malware_found", "malware_not_found", "failed_to_scan", "not_scanned"'
+ enum:
+ - malware_found
+ - malware_not_found
+ - failed_to_scan
+ - not_scanned
+ x-enum-name: MalwareScanResult
+ x-enum-varnames:
+ - MALWARE_FOUND
+ - MALWARE_NOT_FOUND
+ - FAILED_TO_SCAN
+ - NOT_SCANNED
readOnly: true
mapped_content_url:
type: string
@@ -631,7 +1175,7 @@ components:
type: string
description: |
HTML body of the article. Unsafe tags and attributes may be removed before display. For a list of safe tags and attributes,
- see Allowing unsafe HTML in Help Center articles in Zendesk help
+ see Allowing unsafe HTML in Help Center articles in Zendesk help
comments_disabled:
type: boolean
description: True if comments are disabled; false otherwise
@@ -881,51 +1425,38 @@ components:
html_url:
type: string
description: The url of this category in Help Center
- # readOnly: true
id:
type: integer
format: int64
description: Automatically assigned when creating categories
- # readOnly: true
locale:
- type: string
- description: The locale where the category is displayed
+ $ref: '#/components/schemas/LocaleAbbreviation'
name:
type: string
description: The name of the category
outdated:
type: boolean
description: Whether the category is out of date
- # readOnly: true
position:
type: integer
format: int64
description: The position of this category relative to other categories
source_locale:
- type: string
- description: The source (default) locale of the category
- # readOnly: true
+ $ref: '#/components/schemas/LocaleAbbreviation'
+ translations:
+ type: array
+ description: The translations for the category
+ items:
+ $ref: '#/components/schemas/Translation'
updated_at:
type: string
format: date-time
description: The time at which the category was last updated
- # readOnly: true
url:
type: string
description: The API url of this category
- # readOnly: true
- example:
- description: ""
- html_url: https://company.zendesk.com/hc/en-us/categories/354362577
- id: 1635
- locale: en-us
- name: Self Help Articles
- source_locale: en-us
- url: https://company.zendesk.com/api/v2/help_center/categories/354362577
required:
- - id
- name
- - locale
CategoryResponse:
type: object
properties:
@@ -948,13 +1479,13 @@ components:
author_id:
type: integer
format: int64
- description: The id of the author of this comment. Writable on create by Help Center managers. See Create Comment
+ description: The id of the author of this comment. Writable on create by Help Center managers. See Create Comment
body:
type: string
- description: The comment made by the author. See User content
+ description: The comment made by the author. See User content
created_at:
type: string
- description: The time the comment was created. Writable on create by Help Center managers. See Create Comment
+ description: The time the comment was created. Writable on create by Help Center managers. See Create Comment
html_url:
type: string
description: The url at which the comment is presented in Help Center
@@ -1065,7 +1596,7 @@ components:
readOnly: true
source_locale:
type: string
- description: Used only for Create Section Subscription and Create Article Subscription, where it's mandatory. Selects the locale of the content to be subscribed
+ description: Used only for Create Section Subscription and Create Article Subscription, where it's mandatory. Selects the locale of the content to be subscribed
updated_at:
type: string
description: The time at which the subscription was last updated
@@ -1357,6 +1888,83 @@ components:
name: English
updated_at: "2011-05-05T10:38:52Z"
url: https://company.zendesk.com/api/v2/locales/en-US.json
+ LocaleAbbreviation:
+ type: string
+ description: The locale of the translation
+ enum:
+ - ar
+ - pt-br
+ - bg
+ - cs
+ - da
+ - nl
+ - en-gb
+ - en-us
+ - fa-af
+ - fil
+ - fi
+ - fr
+ - fr-ca
+ - de
+ - el
+ - he
+ - hi
+ - hu
+ - id
+ - it
+ - ja
+ - ko
+ - ms
+ - no
+ - pl
+ - ro
+ - ru
+ - zh-cn
+ - es
+ - sk
+ - sv
+ - th
+ - zh-tw
+ - tr
+ - uk
+ - vi
+ x-enum-varnames:
+ - ARABIC
+ - PORTUGUESE_BRAZIL
+ - BULGARIAN
+ - CZECH
+ - DANISH
+ - DUTCH
+ - ENGLISH_UNITED_KINGDOM
+ - ENGLISH_UNITED_STATES
+ - DARI_PERSIAN_AFGHANISTAN
+ - FILIPINO
+ - FINNISH
+ - FRENCH
+ - FRENCH_CANADA
+ - GERMAN
+ - GREEK
+ - HEBREW
+ - HINDI
+ - HUNGARIAN
+ - INDONESIAN
+ - ITALIAN
+ - JAPANESE
+ - KOREAN
+ - MALAY
+ - NORWEGIAN
+ - POLISH
+ - ROMANIAN
+ - RUSSIAN
+ - SIMPLIFIED_CHINESE
+ - SPANISH
+ - SLOVAK
+ - SWEDISH
+ - THAI
+ - TRADITIONAL_CHINESE
+ - TURKISH
+ - UKRAINIAN
+ - VIETNAMESE
LocaleResponse:
type: object
properties:
@@ -1384,13 +1992,13 @@ components:
author_id:
type: integer
format: int64
- description: The id of the author of the comment. Writable on create by Help Center managers. See Create Post Comment
+ description: The id of the author of the comment. Writable on create by Help Center managers. See Create Post Comment
body:
type: string
- description: The comment made by the author. See User content
+ description: The comment made by the author. See User content
created_at:
type: string
- description: When the comment was created. Writable on create by Help Center managers. See Create Post Comment
+ description: When the comment was created. Writable on create by Help Center managers. See Create Post Comment
html_url:
type: string
description: The community url of the comment
@@ -1463,7 +2071,7 @@ components:
author_id:
type: integer
format: int64
- description: The id of the author of the post. *Writable on create by Help Center managers -- see Create Post
+ description: The id of the author of the post. *Writable on create by Help Center managers -- see Create Post
readOnly: true
closed:
type: boolean
@@ -1482,11 +2090,11 @@ components:
created_at:
type: string
format: date-time
- description: When the post was created. Writable on create by Help Center managers -- see Create Post
+ description: When the post was created. Writable on create by Help Center managers -- see Create Post
readOnly: true
details:
type: string
- description: The details of the post made by the author. See User content
+ description: The details of the post made by the author. See User content
featured:
type: boolean
description: Whether the post is featured
@@ -1752,7 +2360,7 @@ components:
brand_id:
type: integer
format: int64
- description: The id of the brand this ticket is associated with. See Setting up multiple brands
+ description: The id of the brand this ticket is associated with. See Setting up multiple brands
collaborator_ids:
type: array
description: The ids of users currently CC'ed on the ticket
@@ -1761,12 +2369,12 @@ components:
format: int64
collaborators:
type: array
- description: POST requests only. Users to add as cc's when creating a ticket. See Setting Collaborators
+ description: POST requests only. Users to add as cc's when creating a ticket. See Setting Collaborators
items:
$ref: '#/components/schemas/Collaborator'
comment:
type: object
- description: Write only. An object that adds a comment to the ticket. See Ticket comments. To include an attachment with the comment, see Attaching files. A ticket can contain up to 5000 comments in total, including both public and private comments. Once this limit is reached, any additional attempts to add comments results in a 422 error. The ticket can still be updated in other ways, provided that no new comments are added.
+ description: Write only. An object that adds a comment to the ticket. See Ticket comments. To include an attachment with the comment, see Attaching files. A ticket can contain up to 5000 comments in total, including both public and private comments. Once this limit is reached, any additional attempts to add comments results in a 422 error. The ticket can still be updated in other ways, provided that no new comments are added.
writeOnly: true
created_at:
type: string
@@ -1775,7 +2383,7 @@ components:
readOnly: true
custom_fields:
type: array
- description: Custom fields for the ticket. See Setting custom field values
+ description: Custom fields for the ticket. See Setting custom field values
items:
type: object
properties:
@@ -1789,39 +2397,39 @@ components:
custom_status_id:
type: integer
format: int64
- description: The custom ticket status id of the ticket. See custom ticket statuses
+ description: The custom ticket status id of the ticket. See custom ticket statuses
description:
type: string
description: |
- Read-only first comment on the ticket. When creating a ticket, use comment to set the description. See Description and first comment
+ Read-only first comment on the ticket. When creating a ticket, use comment to set the description. See Description and first comment
readOnly: true
due_at:
type: string
format: date-time
- description: If this is a ticket of type "task" it has a due date. Due date format uses ISO 8601 format
+ description: If this is a ticket of type "task" it has a due date. Due date format uses ISO 8601 format
nullable: true
email_cc_ids:
type: array
- description: The ids of agents or end users currently CC'ed on the ticket. Ignored when CCs and followers is not enabled
+ description: The ids of agents or end users currently CC'ed on the ticket. Ignored when CCs and followers is not enabled
items:
type: integer
format: int64
email_ccs:
type: object
- description: Write only. An array of objects that represents agent or end users email CCs to add or delete from the ticket. See Setting email CCs. Ignored when CCs and followers is not enabled
+ description: Write only. An array of objects that represents agent or end users email CCs to add or delete from the ticket. See Setting email CCs. Ignored when CCs and followers is not enabled
writeOnly: true
external_id:
type: string
description: An id you can use to link Zendesk Support tickets to local records
follower_ids:
type: array
- description: The ids of agents currently following the ticket. Ignored when CCs and followers is not enabled
+ description: The ids of agents currently following the ticket. Ignored when CCs and followers is not enabled
items:
type: integer
format: int64
followers:
type: object
- description: Write only. An array of objects that represents agent followers to add or delete from the ticket. See Setting followers. Ignored when CCs and followers is not enabled
+ description: Write only. An array of objects that represents agent followers to add or delete from the ticket. See Setting followers. Ignored when CCs and followers is not enabled
writeOnly: true
followup_ids:
type: array
@@ -1837,7 +2445,7 @@ components:
readOnly: true
from_messaging_channel:
type: boolean
- description: If true, the ticket's via type is a messaging channel.
+ description: If true, the ticket's via type is a messaging channel.
readOnly: true
generated_timestamp:
type: integer
@@ -1874,12 +2482,12 @@ components:
format: int64
metadata:
type: object
- description: Write only. Metadata for the audit. In the audit object, the data is specified in the custom property of the metadata object. See Setting Metadata
+ description: Write only. Metadata for the audit. In the audit object, the data is specified in the custom property of the metadata object. See Setting Metadata
writeOnly: true
organization_id:
type: integer
format: int64
- description: The organization of the requester. You can only specify the ID of an organization associated with the requester. See Organization Memberships
+ description: The organization of the requester. You can only specify the ID of an organization associated with the requester. See Organization Memberships
priority:
type: string
description: The urgency with which the ticket should be addressed
@@ -1895,13 +2503,13 @@ components:
raw_subject:
type: string
description: |
- The dynamic content placeholder, if present, or the "subject" value, if not. See Dynamic Content Items
+ The dynamic content placeholder, if present, or the "subject" value, if not. See Dynamic Content Items
recipient:
type: string
description: The original recipient e-mail address of the ticket. Notification emails for the ticket are sent from this address
requester:
type: object
- description: Write only. See Creating a ticket with a new requester
+ description: Write only. See Creating a ticket with a new requester
writeOnly: true
requester_id:
type: integer
@@ -1909,7 +2517,7 @@ components:
description: The user who requested this ticket
safe_update:
type: boolean
- description: Write only. Optional boolean. When true and an update_stamp date is included, protects against ticket update collisions and returns a message to let you know if one occurs. See Protecting against ticket update collisions. A value of false has the same effect as true. Omit the property to force the updates to not be safe
+ description: Write only. Optional boolean. When true and an update_stamp date is included, protects against ticket update collisions and returns a message to let you know if one occurs. See Protecting against ticket update collisions. A value of false has the same effect as true. Omit the property to force the updates to not be safe
writeOnly: true
satisfaction_rating:
type: object
@@ -1928,7 +2536,7 @@ components:
The state of the ticket.
If your account has activated custom ticket statuses, this is the ticket's
- status category. See custom ticket statuses
+ status category. See custom ticket statuses
enum:
- new
- open
@@ -1939,14 +2547,14 @@ components:
subject:
type: string
description: |
- The value of the subject field for this ticket. See Subject
+ The value of the subject field for this ticket. See Subject
submitter_id:
type: integer
format: int64
description: The user who submitted the ticket. The submitter always becomes the author of the first comment on the ticket
tags:
type: array
- description: The array of tags applied to this ticket. Unless otherwise specified, the set tag behavior is used, which overwrites and replaces existing tags
+ description: The array of tags applied to this ticket. Unless otherwise specified, the set tag behavior is used, which overwrites and replaces existing tags
items:
type: string
ticket_form_id:
@@ -1964,7 +2572,7 @@ components:
updated_at:
type: string
format: date-time
- description: When this record last got updated. It is updated only if the update generates a ticket event
+ description: When this record last got updated. It is updated only if the update generates a ticket event
readOnly: true
updated_stamp:
type: string
@@ -1976,7 +2584,7 @@ components:
readOnly: true
via:
type: object
- description: For more information, see the Via object reference
+ description: For more information, see the Via object reference
properties:
channel:
type: string
@@ -1990,15 +2598,15 @@ components:
via_followup_source_id:
type: integer
format: int64
- description: POST requests only. The id of a closed ticket when creating a follow-up ticket. See Creating a follow-up ticket
+ description: POST requests only. The id of a closed ticket when creating a follow-up ticket. See Creating a follow-up ticket
via_id:
type: integer
format: int64
- description: Write only. For more information, see the Via object reference
+ description: Write only. For more information, see the Via object reference
writeOnly: true
voice_comment:
type: object
- description: Write only. See Creating voicemail ticket
+ description: Write only. See Creating voicemail ticket
writeOnly: true
example:
assignee_id: 235323
@@ -2072,18 +2680,18 @@ components:
description: Enterprise only. The id of the brand this ticket is associated with
collaborators:
type: array
- description: POST requests only. Users to add as cc's when creating a ticket. See Setting Collaborators
+ description: POST requests only. Users to add as cc's when creating a ticket. See Setting Collaborators
items:
$ref: '#/components/schemas/Collaborator'
email_cc_ids:
type: array
- description: The ids of agents or end users currently CC'ed on the ticket. See CCs and followers resources in the Support Help Center
+ description: The ids of agents or end users currently CC'ed on the ticket. See CCs and followers resources in the Support Help Center
items:
type: integer
format: int64
follower_ids:
type: array
- description: The ids of agents currently following the ticket. See CCs and followers resources
+ description: The ids of agents currently following the ticket. See CCs and followers resources
items:
type: integer
format: int64
@@ -2096,7 +2704,7 @@ components:
raw_subject:
type: string
description: |
- The dynamic content placeholder, if present, or the "subject" value, if not. See Dynamic Content Items
+ The dynamic content placeholder, if present, or the "subject" value, if not. See Dynamic Content Items
recipient:
type: string
description: The original recipient e-mail address of the ticket
@@ -2113,7 +2721,7 @@ components:
via_followup_source_id:
type: integer
format: int64
- description: POST requests only. The id of a closed ticket when creating a follow-up ticket. See Creating a follow-up ticket
+ description: POST requests only. The id of a closed ticket when creating a follow-up ticket. See Creating a follow-up ticket
required:
- comment
example:
@@ -2193,13 +2801,13 @@ components:
description: The relative position of the ticket field on a ticket. Note that for accounts with ticket forms, positions are controlled by the different forms
raw_description:
type: string
- description: The dynamic content placeholder if present, or the description value if not. See Dynamic Content
+ description: The dynamic content placeholder if present, or the description value if not. See Dynamic Content
raw_title:
type: string
- description: The dynamic content placeholder if present, or the title value if not. See Dynamic Content
+ description: The dynamic content placeholder if present, or the title value if not. See Dynamic Content
raw_title_in_portal:
type: string
- description: The dynamic content placeholder if present, or the "title_in_portal" value if not. See Dynamic Content
+ description: The dynamic content placeholder if present, or the "title_in_portal" value if not. See Dynamic Content
regexp_for_validation:
type: string
description: For "regexp" fields only. The validation pattern for a field value to be deemed valid
@@ -2241,7 +2849,7 @@ components:
description: The title of the ticket field for end users in Help Center
type:
type: string
- description: System or custom field type. Editable for custom field types and only on creation. See Create Ticket Field
+ description: System or custom field type. Editable for custom field types and only on creation. See Create Ticket Field
updated_at:
type: string
format: date-time
@@ -2281,7 +2889,7 @@ components:
properties:
additional_collaborators:
type: array
- description: An array of numeric IDs, emails, or objects containing name and email properties. See Setting Collaborators. An email notification is sent to them when the ticket is updated
+ description: An array of numeric IDs, emails, or objects containing name and email properties. See Setting Collaborators. An email notification is sent to them when the ticket is updated
items:
$ref: '#/components/schemas/Collaborator'
assignee_email:
@@ -2305,20 +2913,20 @@ components:
$ref: '#/components/schemas/TicketComment'
custom_fields:
type: array
- description: Custom fields for the ticket. See Setting custom field values
+ description: Custom fields for the ticket. See Setting custom field values
items:
$ref: '#/components/schemas/CustomField'
custom_status_id:
type: integer
- description: The custom ticket status id of the ticket. See custom ticket statuses
+ description: The custom ticket status id of the ticket. See custom ticket statuses
due_at:
type: string
format: date-time
- description: If this is a ticket of type "task" it has a due date. Due date format uses ISO 8601 format.
+ description: If this is a ticket of type "task" it has a due date. Due date format uses ISO 8601 format.
nullable: true
email_ccs:
type: array
- description: An array of objects that represent agent or end users email CCs to add or delete from the ticket. See Setting email CCs
+ description: An array of objects that represent agent or end users email CCs to add or delete from the ticket. See Setting email CCs
items:
$ref: '#/components/schemas/EmailCC'
external_id:
@@ -2326,7 +2934,7 @@ components:
description: An id you can use to link Zendesk Support tickets to local records
followers:
type: array
- description: An array of objects that represent agent followers to add or delete from the ticket. See Setting followers
+ description: An array of objects that represent agent followers to add or delete from the ticket. See Setting followers
items:
$ref: '#/components/schemas/Follower'
group_id:
@@ -2334,7 +2942,7 @@ components:
description: The group this ticket is assigned to
organization_id:
type: integer
- description: The organization of the requester. You can only specify the ID of an organization associated with the requester. See Organization Memberships
+ description: The organization of the requester. You can only specify the ID of an organization associated with the requester. See Organization Memberships
priority:
type: string
description: The urgency with which the ticket should be addressed.
@@ -2363,7 +2971,7 @@ components:
The state of the ticket.
If your account has activated custom ticket statuses, this is the ticket's
- status category. See custom ticket statuses.
+ status category. See custom ticket statuses.
enum:
- new
- open
@@ -2410,7 +3018,7 @@ components:
$ref: '#/components/schemas/TicketUpdateInput'
TicketAuditVia:
type: object
- description: Describes how the object was created. See the Via object reference
+ description: Describes how the object was created. See the Via object reference
properties:
channel:
type: string
@@ -2426,20 +3034,20 @@ components:
properties:
attachments:
type: array
- description: Attachments, if any. See Attachment
+ description: Attachments, if any. See Attachment
items:
$ref: '#/components/schemas/Attachment'
readOnly: true
audit_id:
type: integer
- description: The id of the ticket audit record. See Show Audit
+ description: The id of the ticket audit record. See Show Audit
readOnly: true
author_id:
type: integer
- description: The id of the comment author. See Author id
+ description: The id of the comment author. See Author id
body:
type: string
- description: The comment string. See Bodies
+ description: The comment string. See Bodies
created_at:
type: string
format: date-time
@@ -2447,30 +3055,30 @@ components:
readOnly: true
html_body:
type: string
- description: The comment formatted as HTML. See Bodies
+ description: The comment formatted as HTML. See Bodies
id:
type: integer
description: Automatically assigned when the comment is created
readOnly: true
metadata:
type: object
- description: System information (web client, IP address, etc.) and comment flags, if any. See Comment flags
+ description: System information (web client, IP address, etc.) and comment flags, if any. See Comment flags
additionalProperties: true
readOnly: true
plain_body:
type: string
- description: The comment presented as plain text. See Bodies
+ description: The comment presented as plain text. See Bodies
readOnly: true
public:
type: boolean
description: true if a public comment; false if an internal note. The initial value set on ticket creation persists for any additional comment unless you change it
type:
type: string
- description: '`Comment` or `VoiceComment`. The JSON object for adding voice comments to tickets is different. See Adding voice comments to tickets'
+ description: "`Comment` or `VoiceComment`. The JSON object for adding voice comments to tickets is different. See Adding voice comments to tickets"
readOnly: true
uploads:
type: array
- description: List of tokens received from uploading files for comment attachments. The files are attached by creating or updating tickets with the tokens. See Attaching files in Tickets
+ description: List of tokens received from uploading files for comment attachments. The files are attached by creating or updating tickets with the tokens. See Attaching files in Tickets
items:
type: string
via:
@@ -2623,8 +3231,7 @@ components:
description: Automatically assigned when a translation is created
readOnly: true
locale:
- type: string
- description: The locale of the translation
+ $ref: '#/components/schemas/LocaleAbbreviation'
outdated:
type: boolean
description: True if the translation is outdated; false otherwise. False by default
@@ -2654,12 +3261,6 @@ components:
type: string
description: The API url of the translation
readOnly: true
- example:
- id: 3243452
- locale: en
- source_id: 768934
- source_type: Article
- title: Hello translation
required:
- locale
- title
@@ -2850,7 +3451,7 @@ components:
Via:
type: object
description: |
- An object explaining how the ticket was created. See the Via object reference
+ An object explaining how the ticket was created. See the Via object reference
properties:
channel:
type: string
@@ -2956,6 +3557,64 @@ components:
type: array
items:
$ref: '#/components/schemas/Vote'
+ SearchResult:
+ type: object
+ properties:
+ created_at:
+ type: string
+ description: When the resource was created
+ default:
+ type: boolean
+ description: Flag to indicate whether this is the default resource
+ deleted:
+ type: boolean
+ description: Flag to indicate whether or not resource has been deleted
+ description:
+ type: string
+ description: The description of the resource
+ id:
+ type: integer
+ description: The ID of the resource
+ name:
+ type: string
+ description: The name of the resource
+ result_type:
+ type: string
+ description: The type of the resource
+ updated_at:
+ type: string
+ description: When the resource was last updated
+ url:
+ type: string
+ description: The url of the resource
+ SearchResponse:
+ type: object
+ properties:
+ count:
+ type: integer
+ description: The number of resources returned by the query corresponding to this page of results in the paginated response
+ readOnly: true
+ facets:
+ type: string
+ description: The facets corresponding to the search query
+ nullable: true
+ readOnly: true
+ next_page:
+ type: string
+ description: URL to the next page of results
+ nullable: true
+ readOnly: true
+ previous_page:
+ type: string
+ description: URL to the previous page of results
+ nullable: true
+ readOnly: true
+ results:
+ type: array
+ description: May consist of tickets, users, groups, or organizations, as specified by the `result_type` property in each result object
+ items:
+ $ref: '#/components/schemas/SearchResult'
+ readOnly: true
parameters:
ArticleAttachmentId:
name: article_attachment_id
@@ -3019,9 +3678,7 @@ components:
description: The locale the item is displayed in. (must be lowercase, even if returned from zendesk as mixed case)
required: true
schema:
- type: string
- example: en-us
- example: en-us
+ $ref: '#/components/schemas/LocaleAbbreviation'
PostCommentId:
name: post_comment_id
in: path
@@ -3049,6 +3706,14 @@ components:
type: string
example: en-us
example: en-us
+ SearchInclude:
+ name: include
+ in: query
+ description: |
+ Sideloads to include in the response. Accepts a comma-separated list of values.
+ The available sideloads depend on the search result types.
+ schema:
+ type: string
SectionId:
name: section_id
in: path
diff --git a/src/test/groovy/lol/pbu/z4j/Z4jSpec.groovy b/src/test/groovy/lol/pbu/z4j/Z4jSpec.groovy
index eb59fe7..84d5ea4 100644
--- a/src/test/groovy/lol/pbu/z4j/Z4jSpec.groovy
+++ b/src/test/groovy/lol/pbu/z4j/Z4jSpec.groovy
@@ -10,6 +10,7 @@ import spock.lang.Shared
import spock.lang.Specification
@MicronautTest
+@SuppressWarnings("GroovyAssignabilityCheck")
class Z4jSpec extends Specification {
@Shared
diff --git a/src/test/groovy/lol/pbu/z4j/client/ArticleClientSpec.groovy b/src/test/groovy/lol/pbu/z4j/client/ArticleClientSpec.groovy
index 4f8728f..24829b7 100644
--- a/src/test/groovy/lol/pbu/z4j/client/ArticleClientSpec.groovy
+++ b/src/test/groovy/lol/pbu/z4j/client/ArticleClientSpec.groovy
@@ -5,6 +5,7 @@ import lol.pbu.z4j.Z4jSpec
import lol.pbu.z4j.model.ArticlesResponse
import lol.pbu.z4j.model.ListArticlesSortByParameter
import lol.pbu.z4j.model.ListArticlesSortOrderParameter
+import lol.pbu.z4j.model.LocaleAbbreviation
import reactor.core.publisher.Mono
import spock.lang.Shared
@@ -15,16 +16,16 @@ class ArticleClientSpec extends Z4jSpec {
ArticleClient adminArticleClient, agentArticleClient, userArticleClient
@Shared
- List allLocales
+ List allLocales
def setupSpec() {
adminArticleClient = adminCtx.getBean(ArticleClient.class)
agentArticleClient = agentCtx.getBean(ArticleClient.class)
userArticleClient = userCtx.getBean(ArticleClient.class)
- allLocales = userCtx.getBean(LocaleClient.class).listLocales().block().locales.collect { it.locale.toLowerCase() }
+ allLocales = List.of(LocaleAbbreviation.ENGLISH_UNITED_STATES, LocaleAbbreviation.FRENCH)
}
- def "can use ListArticles for other tests using the '#locale' locale"(ArticleClient articleClient, String locale, ListArticlesSortByParameter sortBy, ListArticlesSortOrderParameter sortOrder, Long startTime, String labelNames) {
+ def "can use ListArticles for other tests using the '#locale' locale"(ArticleClient articleClient, LocaleAbbreviation locale, ListArticlesSortByParameter sortBy, ListArticlesSortOrderParameter sortOrder, Long startTime, String labelNames) {
// https://github.com/PeanutButter-Unicorn/z4j/issues/31
when: "query articles list for the '#locale' locale"
Mono response = articleClient.listArticles(locale, sortBy, sortOrder, startTime, labelNames)
diff --git a/src/test/groovy/lol/pbu/z4j/client/CategoryClientSpec.groovy b/src/test/groovy/lol/pbu/z4j/client/CategoryClientSpec.groovy
new file mode 100644
index 0000000..11052ad
--- /dev/null
+++ b/src/test/groovy/lol/pbu/z4j/client/CategoryClientSpec.groovy
@@ -0,0 +1,278 @@
+package lol.pbu.z4j.client
+
+import io.micronaut.http.client.exceptions.HttpClientResponseException
+import io.micronaut.test.extensions.spock.annotation.MicronautTest
+import lol.pbu.z4j.Z4jSpec
+import lol.pbu.z4j.model.*
+import spock.lang.Shared
+
+import static io.micronaut.http.HttpStatus.BAD_REQUEST
+import static io.micronaut.http.HttpStatus.FORBIDDEN
+
+@MicronautTest
+@SuppressWarnings("GroovyAssignabilityCheck")
+class CategoryClientSpec extends Z4jSpec {
+
+ @Shared
+ CategoryClient adminCategoryClient, agentCategoryClient, userCategoryClient
+
+ @Shared
+ List userSegments
+
+ @Shared
+ List allLocales
+
+ def setupSpec() {
+ adminCategoryClient = adminCtx.getBean(CategoryClient.class)
+ agentCategoryClient = agentCtx.getBean(CategoryClient.class)
+ userCategoryClient = userCtx.getBean(CategoryClient.class)
+ allLocales = List.of(LocaleAbbreviation.ENGLISH_UNITED_STATES, LocaleAbbreviation.FRENCH)
+ userSegments = adminCtx.getBean(UserSegmentClient.class).listUserSegments(null).block().getUserSegments()
+ assert userSegments.size() >= 2
+ // built in segments should be at least 2, this is here to just double check this doesn't change
+ }
+
+ def "can use ListArticles using the '#locale' locale for the #userType user type"(CategoryClient categoryClient, String userType, LocaleAbbreviation locale, ListCategoriesSortByParameter sortBy, ListArticlesSortOrderParameter sortOrder) {
+ when: "query Categories list for the '#locale' locale"
+ categoryClient.listCategories(locale, sortBy, sortOrder).block()
+
+ then:
+ noExceptionThrown()
+
+ where:
+ [[categoryClient, userType], locale, sortBy, sortOrder, startTime, labelNames] << [[[adminCategoryClient, "admin"], [agentCategoryClient, "agent"], [userCategoryClient, "user"]],
+ allLocales,
+ [ListCategoriesSortByParameter.values(), null].flatten(),
+ [ListArticlesSortOrderParameter.values(), null].flatten()].combinations()
+ }
+
+ def "can use ListCategoriesNoLocale using for the #userType user type"(CategoryClient categoryClient, String userType, ListCategoriesSortByParameter sortBy, ListArticlesSortOrderParameter sortOrder) {
+ when:
+ categoryClient.listCategoriesNoLocale(sortBy, sortOrder).block()
+
+ then:
+ noExceptionThrown()
+
+ where:
+ [[categoryClient, userType], sortBy, sortOrder] << [
+ [[adminCategoryClient, "admin"], [agentCategoryClient, "agent"]],
+ [ListCategoriesSortByParameter.values(), null].flatten(),
+ [ListArticlesSortOrderParameter.values(), null].flatten()
+ ].combinations()
+ }
+
+ def "can use CreateCategory as an #userType for the '#locale' locale"(CategoryClient categoryClient, String userType, LocaleAbbreviation locale) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.animal().name()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.backToTheFuture().quote())
+ createCategoryRequest.setCategory(category)
+
+ when: "category name to be created is #categoryName"
+ CategoryResponse response = categoryClient.createCategory(locale, createCategoryRequest).block()
+
+ then:
+ noExceptionThrown()
+
+ cleanup: "deleting #categoryName from the #locale locale"
+ categoryClient.deleteCategory(locale, response.getCategory().getId())
+
+ where:
+ [[categoryClient, userType], locale] << [[[adminCategoryClient, "admin"]], allLocales].combinations()
+ }
+
+ def "can use CreateCategoryNoLocale as an #userType and update it with a translation"(CategoryClient categoryClient, String userType) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.animal().name()
+ def translations = List.of(new Translation(LocaleAbbreviation.FRENCH, faker.backToTheFuture().quote()),
+ new Translation(LocaleAbbreviation.ENGLISH_UNITED_STATES, faker.redDeadRedemption2().quote()))
+ Category category = new Category(categoryName)
+ .setLocale(LocaleAbbreviation.ENGLISH_UNITED_STATES)
+ .setPosition(0)
+ createCategoryRequest.setCategory(category)
+
+
+ when:
+ CategoryResponse response = categoryClient.createCategoryNoLocale(createCategoryRequest).block()
+
+ and:
+ category.setTranslations(translations)
+ categoryClient.updateCategoryNoLocale(response.getCategory().getId(), new CreateCategoryRequest(category)).block()
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ categoryClient.deleteCategory(LocaleAbbreviation.ENGLISH_UNITED_STATES, response.category.id)
+
+ where:
+ [[categoryClient, userType]] << [[[adminCategoryClient, "admin"]]].combinations()
+
+
+ }
+
+
+ def "cannot use CreateCategory as an #userType for the '#locale' locale"(CategoryClient categoryClient, String userType, LocaleAbbreviation locale) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.animal().name()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.backToTheFuture().quote())
+ createCategoryRequest.setCategory(category)
+
+ when: "category name to be created is #categoryName"
+ CategoryResponse response = categoryClient.createCategory(locale, createCategoryRequest).block()
+
+ then:
+ HttpClientResponseException error = thrown(HttpClientResponseException)
+
+ and:
+ error.getStatus() == FORBIDDEN
+
+ cleanup: "deleting #categoryName from the #locale locale"
+ try {
+ adminCategoryClient.deleteCategory(locale, response.getCategory().getId())
+ } catch (NullPointerException ignored) {
+ }
+
+ where:
+ [[categoryClient, userType], locale] << [[[userCategoryClient, "user"], [agentCategoryClient, "agent"]], allLocales].combinations()
+ }
+
+ def "cannot use CreateCategoryNoLocale as an #userType"(CategoryClient categoryClient, String userType) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.animal().name()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.backToTheFuture().quote())
+ createCategoryRequest.setCategory(category)
+
+ when: "category name to be created is #categoryName"
+ categoryClient.createCategoryNoLocale(createCategoryRequest).block()
+
+ then:
+ HttpClientResponseException error = thrown(HttpClientResponseException)
+
+ and:
+ error.getStatus() == FORBIDDEN
+
+ where:
+ [[categoryClient, userType]] << [[[userCategoryClient, "user"], [agentCategoryClient, "agent"]]].combinations()
+ }
+
+ def "can use DeleteCategory as an #userType for the '#locale"(CategoryClient categoryClient, String userType, LocaleAbbreviation locale) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.bluey().quote()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.lordOfTheRings().location())
+ createCategoryRequest.setCategory(category)
+ CategoryResponse response = categoryClient.createCategory(locale, createCategoryRequest).block()
+
+ when:
+ categoryClient.deleteCategory(locale, response.getCategory().getId())
+
+ then:
+ noExceptionThrown()
+
+ where:
+ [[categoryClient, userType], locale] << [[[adminCategoryClient, "admin"]], allLocales].combinations()
+ }
+
+ def "cannot use DeleteCategory as an #userType for the '#locale' locale"(CategoryClient categoryClient, String userType, LocaleAbbreviation locale) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.bluey().quote() + " " + UUID.randomUUID().toString()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.lordOfTheRings().location())
+ createCategoryRequest.setCategory(category)
+ CategoryResponse response = adminCategoryClient.createCategory(locale, createCategoryRequest).block()
+
+ when:
+ categoryClient.deleteCategory(locale, response.getCategory().getId())
+
+ then:
+ noExceptionThrown() // this shouldn't be allowed!
+// HttpClientResponseException error = thrown(HttpClientResponseException)
+// and:
+// error.getStatus() == FORBIDDEN
+
+ cleanup:
+ adminCategoryClient.deleteCategory(locale, response.getCategory().getId())
+
+
+ where:
+ [[categoryClient, userType], locale] << [[[userCategoryClient, "user"], [agentCategoryClient, "agent"]], allLocales].combinations()
+ }
+
+ def "can use ShowCategory as a #userType for the #locale locale"(CategoryClient categoryClient, String userType, LocaleAbbreviation locale) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.animal().name()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.backToTheFuture().quote())
+ createCategoryRequest.setCategory(category)
+ CategoryResponse createdCategory = adminCategoryClient.createCategory(locale, createCategoryRequest).block()
+
+ when: "showing category #categoryName"
+ categoryClient.showCategory(locale, createdCategory.getCategory().getId()).block()
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ adminCategoryClient.deleteCategory(locale, createdCategory.getCategory().getId()).block()
+
+ where:
+ [[categoryClient, userType], locale] << [[[adminCategoryClient, "admin"], [agentCategoryClient, "agent"], [userCategoryClient, "user"]], allLocales].combinations()
+ }
+
+ def "can use ShowCategoryNoLocale as a #userType"(CategoryClient categoryClient, String userType) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.animal().name()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.backToTheFuture().quote())
+ createCategoryRequest.setCategory(category)
+ CategoryResponse createdCategory = adminCategoryClient.createCategoryNoLocale(createCategoryRequest).block()
+
+ when: "showing category #categoryName"
+ categoryClient.showCategoryNoLocale(createdCategory.getCategory().getId()).block()
+
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ adminCategoryClient.deleteCategory(LocaleAbbreviation.ENGLISH_UNITED_STATES, createdCategory.getCategory().getId()).block()
+
+ where:
+ [[categoryClient, userType]] << [[[adminCategoryClient, "admin"], [agentCategoryClient, "agent"]]].combinations()
+ }
+
+ def "cannot use ShowCategoryNoLocale as a #userType"(CategoryClient categoryClient, String userType) {
+ given:
+ CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest()
+ String categoryName = faker.animal().name()
+ Category category = new Category(categoryName)
+ category.setDescription(faker.backToTheFuture().quote())
+ createCategoryRequest.setCategory(category)
+ CategoryResponse createdCategory = adminCategoryClient.createCategoryNoLocale(createCategoryRequest).block()
+
+ when: "showing category #categoryName"
+ categoryClient.showCategoryNoLocale(createdCategory.getCategory().getId()).block()
+
+ then:
+ HttpClientResponseException error = thrown(HttpClientResponseException)
+
+ and:
+ error.getStatus() == BAD_REQUEST
+
+ cleanup:
+ adminCategoryClient.deleteCategory(LocaleAbbreviation.ENGLISH_UNITED_STATES, createdCategory.getCategory().getId()).block()
+
+ where:
+ [[categoryClient, userType]] << [[[userCategoryClient, "user"]]].combinations()
+ }
+}
diff --git a/src/test/groovy/lol/pbu/z4j/client/SearchClientSpec.groovy b/src/test/groovy/lol/pbu/z4j/client/SearchClientSpec.groovy
new file mode 100644
index 0000000..865f885
--- /dev/null
+++ b/src/test/groovy/lol/pbu/z4j/client/SearchClientSpec.groovy
@@ -0,0 +1,89 @@
+package lol.pbu.z4j.client
+
+import io.micronaut.http.client.exceptions.HttpClientResponseException
+import lol.pbu.z4j.Z4jSpec
+import lol.pbu.z4j.model.SearchExportType
+import lol.pbu.z4j.model.SearchSortBy
+import lol.pbu.z4j.model.SearchSortOrder
+import spock.lang.Shared
+import spock.lang.Unroll
+
+class SearchClientSpec extends Z4jSpec {
+ @Shared
+ SearchClient adminSearchClient, agentSearchClient, userSearchClient
+
+ def setupSpec() {
+ adminSearchClient = adminCtx.getBean(SearchClient.class)
+ agentSearchClient = agentCtx.getBean(SearchClient.class)
+ userSearchClient = userCtx.getBean(SearchClient.class)
+ }
+
+ @Unroll("an #clientName user can run the list method with sortby: #sortBy, sortOrder: #sortOrder and include: #include")
+ void "can run the list method"(String clientName, SearchClient client, SearchSortBy sortBy, SearchSortOrder sortOrder, String include) {
+ when:
+ client.list(faker.bluey().quote(), sortBy, sortOrder, include).block()
+
+ then:
+ noExceptionThrown()
+
+ where:
+ [[client, clientName], sortBy, sortOrder, include] << [[[adminSearchClient, "admin"], [agentSearchClient, "agent"]],
+ [SearchSortBy.values(), null].flatten(),
+ [SearchSortOrder.values(), null].flatten(),
+ [null, faker.cat().name()]].combinations()
+ }
+
+ void "an #clientName user can run the count method"(String clientName, SearchClient client) {
+ when:
+ client.count(faker.bluey().quote()).block()
+
+ then:
+ noExceptionThrown()
+
+ where:
+ [client, clientName] << [[adminSearchClient, "admin"], [agentSearchClient, "agent"]]
+ }
+
+ @Unroll("a simple user querying the list method fails with #sortBy, #sortOrder and #include")
+ void "cannot run searchClient.list()"(SearchClient client, SearchSortBy sortBy, SearchSortOrder sortOrder, String include) {
+ when:
+ client.list(faker.bluey().quote(), sortBy, sortOrder, include).block()
+
+ then:
+ thrown(HttpClientResponseException)
+
+ where:
+ [client, sortBy, sortOrder, include] << [[userSearchClient],
+ [SearchSortBy.values(), null].flatten(),
+ [SearchSortOrder.values(), null].flatten(),
+ [null, faker.cat().name()]].combinations()
+ }
+
+ void "a normal user cannot run the count method"(SearchClient client) {
+ when:
+ client.count(faker.bluey().quote()).block()
+
+ then:
+ thrown(HttpClientResponseException)
+
+ where:
+ client | _
+ userSearchClient | _
+ }
+
+ @SuppressWarnings("GroovyAssignabilityCheck")
+ void "an #clientName can call export method with pageSize: #pageSize, pageAfter: #pageAfter, filterType: #filterType and include: #include"(String clientName, SearchClient client, int pageSize, String pageAfter, SearchExportType filterType, String include) {
+ when:
+ client.export(faker.bluey().quote(), pageSize, pageAfter, filterType, include).block()
+
+ then:
+ noExceptionThrown()
+
+ where:
+ [[client, clientName], pageSize, pageAfter, filterType, include] << [[[adminSearchClient, "admin"], [agentSearchClient, "agent"]],
+ [100],
+ [faker.internet().uuid()],
+ SearchExportType.values(),
+ ["organizations"]].combinations()
+ }
+}
diff --git a/src/test/groovy/lol/pbu/z4j/client/TicketClientSpec.groovy b/src/test/groovy/lol/pbu/z4j/client/TicketClientSpec.groovy
index 856bd6d..caf86f0 100644
--- a/src/test/groovy/lol/pbu/z4j/client/TicketClientSpec.groovy
+++ b/src/test/groovy/lol/pbu/z4j/client/TicketClientSpec.groovy
@@ -171,11 +171,6 @@ class TicketClientSpec extends Z4jSpec {
then:
noExceptionThrown()
- and:
- if (creator) {
- //todo: https://github.com/PeanutButter-Unicorn/z4j/issues/52
- }
-
where:
[[client, clientType, ignored, alsoIgnored], creator, locale] << [
clientTestMatrix.findAll { it.shouldSucceed || it.clientType == "simple user" }, [true, false, null], accountLocales
diff --git a/src/test/groovy/lol/pbu/z4j/client/UserSegmentClientSpec.groovy b/src/test/groovy/lol/pbu/z4j/client/UserSegmentClientSpec.groovy
index 99dd1fc..396f88d 100644
--- a/src/test/groovy/lol/pbu/z4j/client/UserSegmentClientSpec.groovy
+++ b/src/test/groovy/lol/pbu/z4j/client/UserSegmentClientSpec.groovy
@@ -1,12 +1,9 @@
package lol.pbu.z4j.client
-import io.micronaut.http.HttpResponse
-import io.micronaut.http.HttpStatus
+
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import lol.pbu.z4j.Z4jSpec
import lol.pbu.z4j.model.CreateUserSegmentRequest
-import lol.pbu.z4j.model.SectionsResponse
-import lol.pbu.z4j.model.TopicsResponse
import lol.pbu.z4j.model.UserSegment
import lol.pbu.z4j.model.UserSegmentResponse
import lol.pbu.z4j.model.UserSegmentsResponse
diff --git a/src/test/groovy/lol/pbu/z4j/model/CategoriesResponseSpec.groovy b/src/test/groovy/lol/pbu/z4j/model/CategoriesResponseSpec.groovy
index 41465c7..5067e6b 100644
--- a/src/test/groovy/lol/pbu/z4j/model/CategoriesResponseSpec.groovy
+++ b/src/test/groovy/lol/pbu/z4j/model/CategoriesResponseSpec.groovy
@@ -10,7 +10,7 @@ class CategoriesResponseSpec extends Z4jSpec {
given:
def categoriesResponse = new CategoriesResponse()
categoriesResponse.categories == null
- def category = new Category(faker.number().randomNumber(), faker.lorem().word(), faker.lorem().sentence())
+ def category = new Category(faker.lorem().word())
when:
categoriesResponse.addCategoriesItem(category)
@@ -23,10 +23,10 @@ class CategoriesResponseSpec extends Z4jSpec {
@Unroll
def "add categories item to existing list"() {
given:
- def existingCategory = new Category(faker.number().randomNumber(), faker.lorem().word(), faker.lorem().sentence())
+ def existingCategory = new Category(faker.lorem().word())
def categoriesResponse = new CategoriesResponse()
categoriesResponse.categories = [existingCategory]
- def newCategory = new Category(faker.number().randomNumber(), faker.lorem().word(), faker.lorem().sentence())
+ def newCategory = new Category(faker.lorem().word())
when:
categoriesResponse.addCategoriesItem(newCategory)
diff --git a/src/test/groovy/lol/pbu/z4j/model/TranslationsResponseSpec.groovy b/src/test/groovy/lol/pbu/z4j/model/TranslationsResponseSpec.groovy
index ec7571a..bceaa55 100644
--- a/src/test/groovy/lol/pbu/z4j/model/TranslationsResponseSpec.groovy
+++ b/src/test/groovy/lol/pbu/z4j/model/TranslationsResponseSpec.groovy
@@ -6,26 +6,33 @@ import spock.lang.Unroll
class TranslationsResponseSpec extends Z4jSpec {
@Unroll
- def "should add translations item"() {
+ def "should add translations item"(LocaleAbbreviation locale) {
given:
def translationsResponse = new TranslationsResponse()
translationsResponse.translations == null
- def translation = new Translation(faker.lorem().word(), faker.lorem().sentence())
+ def translation = new Translation(locale, faker.lorem().sentence())
when:
translationsResponse.addTranslationsItem(translation)
then:
translationsResponse.translations.size() == 1
- translationsResponse.translations.getAt(0) == translation
+ translationsResponse.translations[0] == translation
+
+ where:
+ locale << LocaleAbbreviation.values()
}
@Unroll
- def "add translations item to existing list"() {
+ def "add translations item to existing list"(LocaleAbbreviation locale) {
given:
- def existingTranslation = new Translation(faker.lorem().word(), faker.lorem().sentence())
+ def existingTranslation = new Translation(locale, faker.lorem().sentence())
def translationsResponse = new TranslationsResponse(translations: [existingTranslation])
- def newTranslation = new Translation(faker.lorem().word(), faker.lorem().sentence())
+ LocaleAbbreviation update = LocaleAbbreviation.HEBREW
+ if (locale == update) {
+ update = LocaleAbbreviation.SIMPLIFIED_CHINESE
+ }
+ def newTranslation = new Translation(update, faker.lorem().sentence())
when:
translationsResponse.addTranslationsItem(newTranslation)
@@ -33,5 +40,8 @@ class TranslationsResponseSpec extends Z4jSpec {
then:
translationsResponse.translations.size() == 2
translationsResponse.translations.containsAll([existingTranslation, newTranslation])
+
+ where:
+ locale << LocaleAbbreviation.values()
}
}
diff --git a/src/test/resources/Application-test.yaml b/src/test/resources/Application-test.yaml
new file mode 100644
index 0000000..2946078
--- /dev/null
+++ b/src/test/resources/Application-test.yaml
@@ -0,0 +1,8 @@
+logger:
+ levels:
+ io.micronaut.http.client: WARN
+#Z4J_ADMIN_EMAIL:
+#Z4J_TOKEN:
+#Z4J_AGENT_EMAIL:
+#Z4J_END_USER_EMAIL:
+#Z4J_URL:
\ No newline at end of file
diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml
new file mode 100644
index 0000000..ddda692
--- /dev/null
+++ b/src/test/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n
+
+
+
+
+
+
+
\ No newline at end of file