From ac7f6df49395c68b9559700a449c0aab7b0a96bc Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Thu, 2 Nov 2023 15:10:17 +1100 Subject: [PATCH 01/11] adds support to CBP request on TicketAudits --- README.md | 8 +++++-- .../Interfaces/Ticket/ITicketAuditResource.cs | 1 + .../Resources/Ticket/TicketAuditResource.cs | 13 ++++++++++ .../Ticket/TicketAuditCursorResponse.cs | 15 ++++++++++++ .../Resources/TicketAuditResourceTests.cs | 24 +++++++++++++++++++ 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/ZendeskApi.Client/Responses/Ticket/TicketAuditCursorResponse.cs diff --git a/README.md b/README.md index 193db736..c2123bed 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A .netstandard NuGet package for use with the Zendesk v2 API. #### The deprecation and replacement of Status API endpoints -More detailed information on the exact changes and motivation can be found [here](https://support.zendesk.com/hc/en-us/articles/5414949730842). +More detailed information on the exact changes and motivation can be found [here](https://support.zendesk.com/hc/en-us/articles/5414949730842). For the sake of this library, it means the following methods have been removed: @@ -50,6 +50,7 @@ Groups: Help Center: - GET api/v2/help_center/articles - GET api/v2/help_center/categories +- GET api/v2/help_center/sections Organization: - GET /api/v2/organization_fields @@ -63,11 +64,14 @@ Tickets: - GET /api/v2/tickets - GET /api/v2/tickets/{ticketId}/comments - GET /api/v2/ticket_fields -- GET /api/v2/ticket_audits - [Cursor Variant](https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_audits/#pagination) +- GET /api/v2/ticket_audits Satisfaction ratings: - GET /api/v2/satisfaction_ratings +Requests +- GET /api/v2/requests + [Further reading on Zendesk Pagination changes](https://support.zendesk.com/hc/en-us/articles/4402610093338-Introducing-Pagination-Changes-Zendesk-API) ## 3.x.x diff --git a/src/ZendeskApi.Client/Resources/Interfaces/Ticket/ITicketAuditResource.cs b/src/ZendeskApi.Client/Resources/Interfaces/Ticket/ITicketAuditResource.cs index 39a8f84d..bf2a342c 100644 --- a/src/ZendeskApi.Client/Resources/Interfaces/Ticket/ITicketAuditResource.cs +++ b/src/ZendeskApi.Client/Resources/Interfaces/Ticket/ITicketAuditResource.cs @@ -8,6 +8,7 @@ namespace ZendeskApi.Client.Resources public interface ITicketAuditResource { Task GetAllAsync(CursorPagerVariant pager = null, CancellationToken cancellationToken = default); + Task GetAllAsync(CursorPager pager, CancellationToken cancellationToken = default); Task GetAllByTicketAsync(long ticketId, CancellationToken cancellationToken = default); Task Get(int ticketId, int auditId, CancellationToken cancellationToken = default); } diff --git a/src/ZendeskApi.Client/Resources/Ticket/TicketAuditResource.cs b/src/ZendeskApi.Client/Resources/Ticket/TicketAuditResource.cs index 5169c792..5f687ebd 100644 --- a/src/ZendeskApi.Client/Resources/Ticket/TicketAuditResource.cs +++ b/src/ZendeskApi.Client/Resources/Ticket/TicketAuditResource.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -17,6 +18,7 @@ public TicketAuditResource(IZendeskApiClient apiClient, ILogger logger) : base(a { } + [Obsolete("Use `GetAllAsync` with CursorPager parameter instead.")] public async Task GetAllAsync(CursorPagerVariant pager = null, CancellationToken cancellationToken = default) { return await GetAsync( @@ -27,6 +29,17 @@ public async Task GetAllAsync(CursorPagerVariant pager = nu cancellationToken); } + public async Task GetAllAsync(CursorPager pager, CancellationToken cancellationToken = default) + { + return await GetAsync( + ResourceUri, + "list-all-ticket-audits", + "GetAllAsync", + pager, + null, + cancellationToken); + } + public async Task GetAllByTicketAsync(long ticketId, CancellationToken cancellationToken = default) { return await GetAsync( diff --git a/src/ZendeskApi.Client/Responses/Ticket/TicketAuditCursorResponse.cs b/src/ZendeskApi.Client/Responses/Ticket/TicketAuditCursorResponse.cs new file mode 100644 index 00000000..a3be0fe2 --- /dev/null +++ b/src/ZendeskApi.Client/Responses/Ticket/TicketAuditCursorResponse.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using ZendeskApi.Client.Models; + +namespace ZendeskApi.Client.Responses +{ + [JsonObject] + public class TicketAuditCursorResponse : CursorPaginationResponse + { + [JsonProperty("audits")] + public IEnumerable Audits { get; set; } + + protected override IEnumerable Enumerable => Audits; + } +} diff --git a/test/ZendeskApi.Client.IntegrationTests/Resources/TicketAuditResourceTests.cs b/test/ZendeskApi.Client.IntegrationTests/Resources/TicketAuditResourceTests.cs index 64e39447..0019197f 100644 --- a/test/ZendeskApi.Client.IntegrationTests/Resources/TicketAuditResourceTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/Resources/TicketAuditResourceTests.cs @@ -27,5 +27,29 @@ public async Task GetAllAsync_WhenCalledWithCursorVariantPagination_ShouldReturn Assert.NotNull(results); Assert.Equal(100, results.Count()); } + + [Fact] + public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatable() + { + var client = _clientFactory.GetClient(); + + var cursorPager = new CursorPager { Size = 2 }; + var auditsPageOne = await client + .TicketAudits.GetAllAsync(cursorPager); + + Assert.NotNull(auditsPageOne); + Assert.Equal(2, auditsPageOne.Count()); + Assert.True(auditsPageOne.Meta.HasMore); + + cursorPager.AfterCursor = auditsPageOne.Meta.AfterCursor; + + var auditsPageTwo = await client.TicketAudits.GetAllAsync(cursorPager); + Assert.NotNull(auditsPageTwo); + Assert.Equal(2, auditsPageTwo.Count()); + + var auditIdsPageOne = auditsPageOne.Select(tag => tag.Id).ToList(); + var auditIdsPageTwo = auditsPageTwo.Select(tag => tag.Id).ToList(); + Assert.NotEqual(auditIdsPageOne, auditIdsPageTwo); + } } } \ No newline at end of file From f28acfe958b4f9cd171f965cd07b926c08922eb6 Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Thu, 2 Nov 2023 15:54:35 +1100 Subject: [PATCH 02/11] adds support to CBP requests on JobStatusResource --- README.md | 3 ++ .../Interfaces/IJobStatusResource.cs | 6 ++- .../Resources/JobStatusResource.cs | 14 ++++++- .../JobStatus/JobStatusListCursorResponse.cs | 15 +++++++ .../Resources/JobStatusResourceTests.cs | 42 +++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/ZendeskApi.Client/Responses/JobStatus/JobStatusListCursorResponse.cs create mode 100644 test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs diff --git a/README.md b/README.md index c2123bed..51a26e71 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,9 @@ Satisfaction ratings: Requests - GET /api/v2/requests +Job Statuses +- GET /api/v2/job_statuses + [Further reading on Zendesk Pagination changes](https://support.zendesk.com/hc/en-us/articles/4402610093338-Introducing-Pagination-Changes-Zendesk-API) ## 3.x.x diff --git a/src/ZendeskApi.Client/Resources/Interfaces/IJobStatusResource.cs b/src/ZendeskApi.Client/Resources/Interfaces/IJobStatusResource.cs index 3508f885..07105386 100644 --- a/src/ZendeskApi.Client/Resources/Interfaces/IJobStatusResource.cs +++ b/src/ZendeskApi.Client/Resources/Interfaces/IJobStatusResource.cs @@ -13,7 +13,7 @@ public interface IJobStatusResource /// /// Shows the current statuses for background jobs running. /// - [Obsolete("Use `GetAllAsync` instead.")] + [Obsolete("Use `GetAllAsync` with CursorPager instead.")] Task> ListAsync( PagerParameters pagerParameters = null, CancellationToken cancellationToken = default(CancellationToken)); @@ -21,10 +21,14 @@ Task> ListAsync( /// /// Shows the current statuses for background jobs running. /// + [Obsolete("Use `GetAllAsync` with CursorPager instead.")] Task> GetAllAsync( PagerParameters pagerParameters = null, CancellationToken cancellationToken = default(CancellationToken)); + Task> GetAllAsync( + CursorPager pagerParameters = null, + CancellationToken cancellationToken = default(CancellationToken)); #endregion #region Show diff --git a/src/ZendeskApi.Client/Resources/JobStatusResource.cs b/src/ZendeskApi.Client/Resources/JobStatusResource.cs index da69f854..f711185e 100644 --- a/src/ZendeskApi.Client/Resources/JobStatusResource.cs +++ b/src/ZendeskApi.Client/Resources/JobStatusResource.cs @@ -19,7 +19,7 @@ public JobStatusResource( : base(apiClient, logger, "job_statuses") { } - [Obsolete("Use `GetAllAsync` instead.")] + [Obsolete("Use `GetAllAsync` with CursorPager instead.")] public async Task> ListAsync( PagerParameters pagerParameters = null, CancellationToken cancellationToken = default(CancellationToken)) @@ -29,6 +29,18 @@ public async Task> ListAsync( cancellationToken); } + public async Task> GetAllAsync(CursorPager pagerParameters, CancellationToken cancellationToken = default) + { + return await GetAsync( + ResourceUri, + "list-job-statuses", + "ListAsync", + pagerParameters, + null, + cancellationToken: cancellationToken); + } + + [Obsolete("Use `GetAllAsync` with CursorPager instead.")] public async Task> GetAllAsync( PagerParameters pagerParameters = null, CancellationToken cancellationToken = default(CancellationToken)) diff --git a/src/ZendeskApi.Client/Responses/JobStatus/JobStatusListCursorResponse.cs b/src/ZendeskApi.Client/Responses/JobStatus/JobStatusListCursorResponse.cs new file mode 100644 index 00000000..0ab75d09 --- /dev/null +++ b/src/ZendeskApi.Client/Responses/JobStatus/JobStatusListCursorResponse.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using ZendeskApi.Client.Models; + +namespace ZendeskApi.Client.Responses +{ + [JsonObject] + public class JobStatusListCursorResponse : CursorPaginationResponse + { + [JsonProperty("job_statuses")] + public IEnumerable JobStatuses { get; set; } + + protected override IEnumerable Enumerable => JobStatuses; + } +} \ No newline at end of file diff --git a/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs b/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs new file mode 100644 index 00000000..7d698df2 --- /dev/null +++ b/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using ZendeskApi.Client.IntegrationTests.Factories; +using ZendeskApi.Client.Models; +using ZendeskApi.Client.Responses; + +namespace ZendeskApi.Client.IntegrationTests.Resources +{ + public class JobStatusResourceTests : IClassFixture + { + private readonly ZendeskClientFactory _clientFactory; + + public JobStatusResourceTests( + ZendeskClientFactory clientFactory) + { + _clientFactory = clientFactory; + } + + + [Fact] + public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatable() + { + var client = _clientFactory.GetClient(); + + var results = await client + .JobStatuses.GetAllAsync(new CursorPager() + { + Size = 2 + }); + var iterator = new CursorPaginatedIterator(results, client); + + Assert.NotNull(results); + Assert.Equal(2, iterator.Count()); + + await iterator.NextPage(); + Assert.True(iterator.Count() <= 2); + } + + } +} \ No newline at end of file From f3484a6621a7700d1ca6fc504d908322f9d9a2c1 Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Thu, 2 Nov 2023 17:02:20 +1100 Subject: [PATCH 03/11] adds support to CBP on Request resources --- README.md | 2 ++ .../Resources/Interfaces/IRequestsResource.cs | 9 +++++++ .../Resources/RequestsResource.cs | 24 +++++++++++++++++++ .../Request/RequestsCursorResponse.cs | 15 ++++++++++++ .../Resources/RequestsResourceTests.cs | 20 ++++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 src/ZendeskApi.Client/Responses/Request/RequestsCursorResponse.cs diff --git a/README.md b/README.md index 51a26e71..b0beff83 100644 --- a/README.md +++ b/README.md @@ -65,12 +65,14 @@ Tickets: - GET /api/v2/tickets/{ticketId}/comments - GET /api/v2/ticket_fields - GET /api/v2/ticket_audits +- GET Satisfaction ratings: - GET /api/v2/satisfaction_ratings Requests - GET /api/v2/requests +- GET /api/v2/requests/{requestId}/comments Job Statuses - GET /api/v2/job_statuses diff --git a/src/ZendeskApi.Client/Resources/Interfaces/IRequestsResource.cs b/src/ZendeskApi.Client/Resources/Interfaces/IRequestsResource.cs index 561633c7..6d13cdbf 100644 --- a/src/ZendeskApi.Client/Resources/Interfaces/IRequestsResource.cs +++ b/src/ZendeskApi.Client/Resources/Interfaces/IRequestsResource.cs @@ -14,6 +14,10 @@ Task> GetAllAsync( PagerParameters pager = null, CancellationToken cancellationToken = default); + Task> GetAllAsync( + CursorPager pager, + CancellationToken cancellationToken = default); + Task GetAsync( long requestId, CancellationToken cancellationToken = default); @@ -29,6 +33,11 @@ Task> GetAllComments( PagerParameters pager = null, CancellationToken cancellationToken = default); + Task> GetAllComments( + long requestId, + CursorPager pager, + CancellationToken cancellationToken = default); + Task GetTicketCommentAsync( long requestId, long commentId, diff --git a/src/ZendeskApi.Client/Resources/RequestsResource.cs b/src/ZendeskApi.Client/Resources/RequestsResource.cs index e86c34e7..159df405 100644 --- a/src/ZendeskApi.Client/Resources/RequestsResource.cs +++ b/src/ZendeskApi.Client/Resources/RequestsResource.cs @@ -34,6 +34,18 @@ public async Task> GetAllAsync( cancellationToken: cancellationToken); } + public async Task> GetAllAsync( + CursorPager pager, + CancellationToken cancellationToken = default) + { + return await GetAsync( + ResourceUri, + "list-requests", + "GetAllAsync", + pager, + cancellationToken: cancellationToken); + } + public async Task GetAsync( long requestId, @@ -79,6 +91,17 @@ public async Task> GetAllComments( cancellationToken); } + public async Task> GetAllComments(long requestId, CursorPager pager, CancellationToken cancellationToken = default) + { + return await GetWithNotFoundCheckAsync( + string.Format(CommentsResourceUri, requestId), + "getting-comments", + $"GetAllComments({requestId})", + $"Could not find any comments for request {requestId} as request was not found", + pager, + cancellationToken); + } + public async Task GetTicketCommentAsync( long requestId, long commentId, @@ -121,5 +144,6 @@ public async Task UpdateAsync( return response? .Request; } + } } diff --git a/src/ZendeskApi.Client/Responses/Request/RequestsCursorResponse.cs b/src/ZendeskApi.Client/Responses/Request/RequestsCursorResponse.cs new file mode 100644 index 00000000..d6868573 --- /dev/null +++ b/src/ZendeskApi.Client/Responses/Request/RequestsCursorResponse.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using ZendeskApi.Client.Models; + +namespace ZendeskApi.Client.Responses +{ + [JsonObject] + public class RequestsCursorResponse : CursorPaginationResponse + { + [JsonProperty("requests")] + public IEnumerable Requests { get; set; } + + protected override IEnumerable Enumerable => Requests; + } +} \ No newline at end of file diff --git a/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs b/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs index 55352495..258606f0 100644 --- a/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs @@ -244,5 +244,25 @@ public async Task UpdateAsync_WhenCalled_ShouldUpdateRequest() comments, comment => comment.Body.Contains($"ZendeskApi.Client.IntegrationTests {updatedId}")); } + + [Fact] + public async Task GetAllAsync_And_GetAllComments_ShouldBePaginatable() + { + var client = _clientFactory.GetClient(); + var cursor = new CursorPager { Size = 1 }; + var requestsResponse = await client.Requests.GetAllAsync(cursor); + + var requestsIterator = new CursorPaginatedIterator(requestsResponse, client); + Assert.Equal(1, requestsIterator.Count()); + + var commentsResponse = await client.Requests.GetAllComments((long)requestsIterator.First().Id, cursor); + Assert.Equal(1, commentsResponse.Count()); + + await requestsIterator.NextPage(); + Assert.Equal(1, requestsIterator.Count()); + commentsResponse = await client.Requests.GetAllComments((long)requestsIterator.First().Id, cursor); + Assert.Equal(1, commentsResponse.Count()); + } + } } From 1ef97bd2771249d22a8580b3284c5986493f79d1 Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Mon, 13 Nov 2023 14:56:09 +1100 Subject: [PATCH 04/11] add support to an iterator --- .../Extensions/HttpClientExtensions.cs | 6 ++ src/ZendeskApi.Client/IZendeskClient.cs | 3 +- .../Models/CursorPaginatedIterator.cs | 75 +++++++++++++++++++ .../Interfaces/IPaginatedResource.cs | 14 ++++ .../Resources/PaginatedResource.cs | 24 ++++++ .../Responses/ICursorPaginationResponse.cs | 1 + src/ZendeskApi.Client/ZendeskClient.cs | 3 + .../CBPSupport/CBPSupportTests.cs | 62 +++++++++++++++ 8 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs create mode 100644 src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs create mode 100644 src/ZendeskApi.Client/Resources/PaginatedResource.cs create mode 100644 test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs diff --git a/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs b/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs index 7def0b43..176b61ff 100644 --- a/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs +++ b/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs @@ -73,5 +73,11 @@ public static Task GetAsync(this HttpClient client, string return client.GetAsync(requestUri, cancellationToken); } + + // to be used within the PaginatedResource, where the next page is a complete URL with cursors already predefined in the query string. + public static Task GetPageAsync(this HttpClient client, string requestUri, CancellationToken cancellationToken = default) + { + return client.GetAsync(requestUri, cancellationToken); + } } } diff --git a/src/ZendeskApi.Client/IZendeskClient.cs b/src/ZendeskApi.Client/IZendeskClient.cs index 88507495..d7f0ab9c 100644 --- a/src/ZendeskApi.Client/IZendeskClient.cs +++ b/src/ZendeskApi.Client/IZendeskClient.cs @@ -28,5 +28,6 @@ public interface IZendeskClient IHelpCenterResource HelpCenter { get; } ILocaleResource Locales { get; } ITagsResource Tags { get; } + IPaginatedResource PaginatedResource { get; } } -} \ No newline at end of file +} diff --git a/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs b/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs new file mode 100644 index 00000000..c6041cab --- /dev/null +++ b/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json; +using ZendeskApi.Client; +using ZendeskApi.Client.Responses; + +public class CursorPaginatedIterator : IEnumerable +{ + + public ICursorPagination Response { get; set; } + + private IZendeskClient client; + + + private string ResponseType { get; } + + public CursorPaginatedIterator(ICursorPagination response, IZendeskClient client) + { + Response = response; + this.client = client; + ResponseType = response.GetType().FullName; + } + + public bool HasMore() => Response.Meta.HasMore; + + public IEnumerator GetEnumerator() + { + return Response.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return Response.GetEnumerator(); + } + + + public async Task NextPage() + { + Console.WriteLine("fetching the next page... "); + await ExecuteRequest(Response.Links.Next); + } + + public async Task PrevPage() + { + await ExecuteRequest(Response.Links.Prev); + } + + public async IAsyncEnumerable All() + { + foreach (var item in Response) + { + yield return item; + } + while (HasMore()) + { + await NextPage(); + foreach (var item in Response) + { + yield return item; + } + } + yield break; + } + + private async Task ExecuteRequest(string requestUrl) + { + var httpResponseMessage = await client.PaginatedResource.GetPage(requestUrl); + var responseBody = await httpResponseMessage.Content.ReadAsStringAsync(); + Response = (ICursorPagination)JsonConvert.DeserializeObject(responseBody, Type.GetType(ResponseType)); + } + +} \ No newline at end of file diff --git a/src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs b/src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs new file mode 100644 index 00000000..17bf25fb --- /dev/null +++ b/src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs @@ -0,0 +1,14 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace ZendeskApi.Client.Resources.Interfaces +{ + public interface IPaginatedResource + { + Task GetPage( + string url, + CancellationToken cancellationToken = default); + } +} + diff --git a/src/ZendeskApi.Client/Resources/PaginatedResource.cs b/src/ZendeskApi.Client/Resources/PaginatedResource.cs new file mode 100644 index 00000000..4217fac6 --- /dev/null +++ b/src/ZendeskApi.Client/Resources/PaginatedResource.cs @@ -0,0 +1,24 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using ZendeskApi.Client.Resources.Interfaces; + +namespace ZendeskApi.Client.Resources +{ + public class PaginatedResource : AbstractBaseResource, IPaginatedResource + { + public PaginatedResource( + IZendeskApiClient apiClient, + ILogger logger) + : base(apiClient, logger, "") + { } + + public async Task GetPage(string url, CancellationToken cancellationToken = default) + { + using var client = ApiClient.CreateClient(); + return await client.GetAsync(url); + } + } +} + diff --git a/src/ZendeskApi.Client/Responses/ICursorPaginationResponse.cs b/src/ZendeskApi.Client/Responses/ICursorPaginationResponse.cs index 4c3b7078..1a00f91c 100644 --- a/src/ZendeskApi.Client/Responses/ICursorPaginationResponse.cs +++ b/src/ZendeskApi.Client/Responses/ICursorPaginationResponse.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using Newtonsoft.Json; diff --git a/src/ZendeskApi.Client/ZendeskClient.cs b/src/ZendeskApi.Client/ZendeskClient.cs index 477ec6e2..5ae53eb4 100644 --- a/src/ZendeskApi.Client/ZendeskClient.cs +++ b/src/ZendeskApi.Client/ZendeskClient.cs @@ -89,5 +89,8 @@ public ZendeskClient(IZendeskApiClient apiClient, ILogger logger = null) private Lazy TagsLazy => new Lazy(() => new TagsResource(_apiClient, _logger)); public ITagsResource Tags => TagsLazy.Value; + + private Lazy PaginatedResourceLazy => new Lazy(() => new PaginatedResource(_apiClient, _logger)); + public IPaginatedResource PaginatedResource => PaginatedResourceLazy.Value; } } diff --git a/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs b/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs new file mode 100644 index 00000000..39a77e68 --- /dev/null +++ b/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs @@ -0,0 +1,62 @@ +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using ZendeskApi.Client.IntegrationTests.Factories; +using ZendeskApi.Client.Models; + +namespace ZendeskApi.Client.IntegrationTests.CBPSupport +{ + public class CBPSupportTests : IClassFixture + { + private readonly ZendeskClientFactory _clientFactory; + + public CBPSupportTests( + ZendeskClientFactory clientFactory) + { + _clientFactory = clientFactory; + } + + [Fact] + public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatableByReplacingTheCursor() + { + var client = _clientFactory.GetClient(); + + var cursorPager = new CursorPager { Size = 5 }; + var ticketsPageOne = await client + .Tickets.GetAllAsync(cursorPager); + + Assert.NotNull(ticketsPageOne); + Assert.Equal(5, ticketsPageOne.Count()); + Assert.True(ticketsPageOne.Meta.HasMore); + + cursorPager.AfterCursor = ticketsPageOne.Meta.AfterCursor; + + var ticketsPageTwo = await client.Tickets.GetAllAsync(cursorPager); + Assert.NotNull(ticketsPageTwo); + Assert.Equal(5, ticketsPageTwo.Count()); + + var ticketIdsPageOne = ticketsPageOne.Select(ticket => ticket.Id).ToList(); + var ticketIdsPageTwo = ticketsPageTwo.Select(ticket => ticket.Id).ToList(); + Assert.NotEqual(ticketIdsPageOne, ticketIdsPageTwo); + } + + [Fact] + public async Task CursorPaginatedIterator_ShouldBePaginatableByCallingNextPage() + { + var client = _clientFactory.GetClient(); + + var cursorPager = new CursorPager { Size = 2 }; + var ticketsResponse = await client + .Tickets.GetAllAsync(cursorPager); + + var iterator = new CursorPaginatedIterator(ticketsResponse, client); + Assert.True(iterator.HasMore()); + Assert.Equal(2, iterator.Count()); + var ticketIdsPageOne = iterator.Select(ticket => ticket.Id).ToList(); + await iterator.NextPage(); + Assert.Equal(2, iterator.Count()); + var ticketIdsPageTwo = iterator.Select(ticket => ticket.Id).ToList(); + Assert.NotEqual(ticketIdsPageOne, ticketIdsPageTwo); + } + } +} From 69f86c340a678fccee507180fbf98e7e84a8ef74 Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Thu, 16 Nov 2023 17:45:37 +1100 Subject: [PATCH 05/11] remove PaginatedResource and insert ApiClient dependency into the CursorPaginatedIterator --- .../Extensions/HttpClientExtensions.cs | 6 ----- src/ZendeskApi.Client/IZendeskClient.cs | 1 - .../Models/CursorPaginatedIterator.cs | 11 ++++----- .../Interfaces/IPaginatedResource.cs | 14 ----------- .../Resources/PaginatedResource.cs | 24 ------------------- src/ZendeskApi.Client/ZendeskClient.cs | 3 --- .../CBPSupport/CBPSupportTests.cs | 3 ++- .../Factories/ZendeskClientFactory.cs | 16 +++++++++---- .../Resources/JobStatusResourceTests.cs | 3 ++- .../Resources/RequestsResourceTests.cs | 3 ++- 10 files changed, 22 insertions(+), 62 deletions(-) delete mode 100644 src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs delete mode 100644 src/ZendeskApi.Client/Resources/PaginatedResource.cs diff --git a/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs b/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs index 176b61ff..7def0b43 100644 --- a/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs +++ b/src/ZendeskApi.Client/Extensions/HttpClientExtensions.cs @@ -73,11 +73,5 @@ public static Task GetAsync(this HttpClient client, string return client.GetAsync(requestUri, cancellationToken); } - - // to be used within the PaginatedResource, where the next page is a complete URL with cursors already predefined in the query string. - public static Task GetPageAsync(this HttpClient client, string requestUri, CancellationToken cancellationToken = default) - { - return client.GetAsync(requestUri, cancellationToken); - } } } diff --git a/src/ZendeskApi.Client/IZendeskClient.cs b/src/ZendeskApi.Client/IZendeskClient.cs index d7f0ab9c..f6d2fa76 100644 --- a/src/ZendeskApi.Client/IZendeskClient.cs +++ b/src/ZendeskApi.Client/IZendeskClient.cs @@ -28,6 +28,5 @@ public interface IZendeskClient IHelpCenterResource HelpCenter { get; } ILocaleResource Locales { get; } ITagsResource Tags { get; } - IPaginatedResource PaginatedResource { get; } } } diff --git a/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs b/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs index c6041cab..d6a3f67c 100644 --- a/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs +++ b/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs @@ -12,12 +12,12 @@ public class CursorPaginatedIterator : IEnumerable public ICursorPagination Response { get; set; } - private IZendeskClient client; + private IZendeskApiClient client; private string ResponseType { get; } - public CursorPaginatedIterator(ICursorPagination response, IZendeskClient client) + public CursorPaginatedIterator(ICursorPagination response, IZendeskApiClient client) { Response = response; this.client = client; @@ -39,7 +39,6 @@ IEnumerator IEnumerable.GetEnumerator() public async Task NextPage() { - Console.WriteLine("fetching the next page... "); await ExecuteRequest(Response.Links.Next); } @@ -61,15 +60,15 @@ public async IAsyncEnumerable All() { yield return item; } - } + } yield break; } private async Task ExecuteRequest(string requestUrl) { - var httpResponseMessage = await client.PaginatedResource.GetPage(requestUrl); + var httpResponseMessage = await client.CreateClient().GetAsync(requestUrl); var responseBody = await httpResponseMessage.Content.ReadAsStringAsync(); Response = (ICursorPagination)JsonConvert.DeserializeObject(responseBody, Type.GetType(ResponseType)); } -} \ No newline at end of file +} diff --git a/src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs b/src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs deleted file mode 100644 index 17bf25fb..00000000 --- a/src/ZendeskApi.Client/Resources/Interfaces/IPaginatedResource.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; - -namespace ZendeskApi.Client.Resources.Interfaces -{ - public interface IPaginatedResource - { - Task GetPage( - string url, - CancellationToken cancellationToken = default); - } -} - diff --git a/src/ZendeskApi.Client/Resources/PaginatedResource.cs b/src/ZendeskApi.Client/Resources/PaginatedResource.cs deleted file mode 100644 index 4217fac6..00000000 --- a/src/ZendeskApi.Client/Resources/PaginatedResource.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using ZendeskApi.Client.Resources.Interfaces; - -namespace ZendeskApi.Client.Resources -{ - public class PaginatedResource : AbstractBaseResource, IPaginatedResource - { - public PaginatedResource( - IZendeskApiClient apiClient, - ILogger logger) - : base(apiClient, logger, "") - { } - - public async Task GetPage(string url, CancellationToken cancellationToken = default) - { - using var client = ApiClient.CreateClient(); - return await client.GetAsync(url); - } - } -} - diff --git a/src/ZendeskApi.Client/ZendeskClient.cs b/src/ZendeskApi.Client/ZendeskClient.cs index 5ae53eb4..477ec6e2 100644 --- a/src/ZendeskApi.Client/ZendeskClient.cs +++ b/src/ZendeskApi.Client/ZendeskClient.cs @@ -89,8 +89,5 @@ public ZendeskClient(IZendeskApiClient apiClient, ILogger logger = null) private Lazy TagsLazy => new Lazy(() => new TagsResource(_apiClient, _logger)); public ITagsResource Tags => TagsLazy.Value; - - private Lazy PaginatedResourceLazy => new Lazy(() => new PaginatedResource(_apiClient, _logger)); - public IPaginatedResource PaginatedResource => PaginatedResourceLazy.Value; } } diff --git a/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs b/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs index 39a77e68..8aa42adc 100644 --- a/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs @@ -44,12 +44,13 @@ public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatable public async Task CursorPaginatedIterator_ShouldBePaginatableByCallingNextPage() { var client = _clientFactory.GetClient(); + var apiClient = _clientFactory.GetApiClient(); var cursorPager = new CursorPager { Size = 2 }; var ticketsResponse = await client .Tickets.GetAllAsync(cursorPager); - var iterator = new CursorPaginatedIterator(ticketsResponse, client); + var iterator = new CursorPaginatedIterator(ticketsResponse, apiClient); Assert.True(iterator.HasMore()); Assert.Equal(2, iterator.Count()); var ticketIdsPageOne = iterator.Select(ticket => ticket.Id).ToList(); diff --git a/test/ZendeskApi.Client.IntegrationTests/Factories/ZendeskClientFactory.cs b/test/ZendeskApi.Client.IntegrationTests/Factories/ZendeskClientFactory.cs index 5ae20f19..78667cc2 100644 --- a/test/ZendeskApi.Client.IntegrationTests/Factories/ZendeskClientFactory.cs +++ b/test/ZendeskApi.Client.IntegrationTests/Factories/ZendeskClientFactory.cs @@ -7,20 +7,26 @@ namespace ZendeskApi.Client.IntegrationTests.Factories { public class ZendeskClientFactory { + public static IZendeskClient zendeskClient; public IZendeskClient GetClient() { - var settings = new ZendeskSettings(); + zendeskClient ??= new ZendeskClient(GetApiClient()); + return zendeskClient; + } - return new ZendeskClient( - new ZendeskApiClient( + public static ZendeskApiClient apiClient; + public ZendeskApiClient GetApiClient() + { + var settings = new ZendeskSettings(); + apiClient ??= new ZendeskApiClient( new OptionsWrapper(new ZendeskOptions { EndpointUri = settings.Url, Username = settings.Username, Token = settings.Token }) - ) - ); + ); + return apiClient; } } } diff --git a/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs b/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs index 7d698df2..67a322aa 100644 --- a/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs @@ -23,13 +23,14 @@ public JobStatusResourceTests( public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatable() { var client = _clientFactory.GetClient(); + var apiClient = _clientFactory.GetApiClient(); var results = await client .JobStatuses.GetAllAsync(new CursorPager() { Size = 2 }); - var iterator = new CursorPaginatedIterator(results, client); + var iterator = new CursorPaginatedIterator(results, apiClient); Assert.NotNull(results); Assert.Equal(2, iterator.Count()); diff --git a/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs b/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs index 258606f0..51e55237 100644 --- a/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs @@ -249,10 +249,11 @@ public async Task UpdateAsync_WhenCalled_ShouldUpdateRequest() public async Task GetAllAsync_And_GetAllComments_ShouldBePaginatable() { var client = _clientFactory.GetClient(); + var apiClient = _clientFactory.GetApiClient(); var cursor = new CursorPager { Size = 1 }; var requestsResponse = await client.Requests.GetAllAsync(cursor); - var requestsIterator = new CursorPaginatedIterator(requestsResponse, client); + var requestsIterator = new CursorPaginatedIterator(requestsResponse, apiClient); Assert.Equal(1, requestsIterator.Count()); var commentsResponse = await client.Requests.GetAllComments((long)requestsIterator.First().Id, cursor); From 8d03f2ecb2cdc2b144d65763c1f91594dfd90a79 Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Wed, 6 Dec 2023 16:25:06 +1100 Subject: [PATCH 06/11] wip --- .../Models/CursorPaginatedIteratorFactory.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs diff --git a/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs b/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs new file mode 100644 index 00000000..c095db0a --- /dev/null +++ b/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs @@ -0,0 +1,22 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using ZendeskApi.Client.Responses; + +namespace ZendeskApi.Client.Models +{ + public class CursorPaginatedIteratorFactory + { + private static IZendeskApiClient ApiClient; + + public CursorPaginatedIteratorFactory(IZendeskApiClient apiClient) + { + ApiClient = apiClient; + } + + public static CursorPaginatedIterator GetPaginatedIterator(ICursorPagination response) + { + return new CursorPaginatedIterator(response, ApiClient); + } + } +} + From 5d26c02e0262a2968e906c144629e5ced81bca2e Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Thu, 7 Dec 2023 16:11:00 +1100 Subject: [PATCH 07/11] Refactor Iterator factory and add to the list of registered services --- README.md | 37 +++++++++++++++++++ .../Extensions/ServiceCollectionExtensions.cs | 2 + .../Models/CursorPaginatedIteratorFactory.cs | 17 ++++++--- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b0beff83..cfbb05f1 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,43 @@ await client.Search.SearchAsync(q => ); ``` +## Using Cursor Based Pagination +You can use the `CursorPaginatedIterator` to loop through multiple pages as shown below: +```c# + +var services = new ServiceCollection(); +services.AddZendeskClientWithHttpClientFactory("https://yoursubomain.zendesk.com", "your@email.com", "your_token_"); +var serviceProvider = services.BuildServiceProvider(); +var client = serviceProvider.GetRequiredService(); + +var ticketCursorResponse = await client.Tickets.GetAllAsync(new CursorPager { Size = 5 }); // low page number to force pagination + +var iteratorFactory = serviceProvider.GetRequiredService(); +// creates the iterator with the response object of the first request +var iterator = iteratorFactory.Create(ticketCursorResponse); + +foreach (var ticket in iterator) +{ + Console.WriteLine("the id of this ticket is:" + ticket.Id); +} // this loop will stop at the first page + +while (iterator.HasMore()) // to loop through all pages +{ + await iterator.NextPage(); + foreach (var ticket in iterator) + { + Console.WriteLine("the id of this ticket is:" + ticket.Id); + } +} + +// alternatively you can use .All() from the iterator +await foreach (var ticket in iterator.All()) +{ + Console.WriteLine("the id of this ticket is:" + ticket.Id); +} + +``` + ## The Zendesk API The zendesk api documentation is available at http://developer.zendesk.com/documentation/rest_api/introduction.html diff --git a/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs b/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs index 2cdd386e..de0ce42c 100644 --- a/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs +++ b/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Net.Http; using Microsoft.Extensions.DependencyInjection; +using ZendeskApi.Client.Models; using ZendeskApi.Client.Options; #pragma warning disable 618 @@ -33,6 +34,7 @@ public static IServiceCollection AddZendeskClientWithHttpClientFactory(this ISer { services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddHttpClient("zendeskApiClient", c => { diff --git a/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs b/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs index c095db0a..c5b387d9 100644 --- a/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs +++ b/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs @@ -4,18 +4,23 @@ namespace ZendeskApi.Client.Models { - public class CursorPaginatedIteratorFactory + public interface ICursorPaginatedIteratorFactory { - private static IZendeskApiClient ApiClient; + CursorPaginatedIterator Create(ICursorPagination response); + } + + public class CursorPaginatedIteratorFactory : ICursorPaginatedIteratorFactory + { + private static IServiceProvider serviceProvider; - public CursorPaginatedIteratorFactory(IZendeskApiClient apiClient) + public CursorPaginatedIteratorFactory(IServiceProvider _serviceProvider) { - ApiClient = apiClient; + serviceProvider = _serviceProvider; } - public static CursorPaginatedIterator GetPaginatedIterator(ICursorPagination response) + public CursorPaginatedIterator Create(ICursorPagination response) { - return new CursorPaginatedIterator(response, ApiClient); + return new CursorPaginatedIterator(response, serviceProvider.GetRequiredService()); } } } From ab871267b40e8ef75d47e4343b7ca4e7b6717c6c Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Tue, 12 Dec 2023 15:22:29 +1100 Subject: [PATCH 08/11] small refactoring, addressing comments --- .../Extensions/ServiceCollectionExtensions.cs | 1 + .../CursorPaginatedIteratorFactory.cs | 10 +++++----- src/ZendeskApi.Client/ZendeskApi.Client.csproj | 6 ++++++ 3 files changed, 12 insertions(+), 5 deletions(-) rename src/ZendeskApi.Client/{Models => Pagination}/CursorPaginatedIteratorFactory.cs (57%) diff --git a/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs b/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs index de0ce42c..d4382c01 100644 --- a/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs +++ b/src/ZendeskApi.Client/Extensions/ServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using ZendeskApi.Client.Models; using ZendeskApi.Client.Options; +using ZendeskApi.Client.Pagination; #pragma warning disable 618 namespace ZendeskApi.Client.Extensions diff --git a/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs b/src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs similarity index 57% rename from src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs rename to src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs index c5b387d9..fcffa3d9 100644 --- a/src/ZendeskApi.Client/Models/CursorPaginatedIteratorFactory.cs +++ b/src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using ZendeskApi.Client.Responses; -namespace ZendeskApi.Client.Models +namespace ZendeskApi.Client.Pagination { public interface ICursorPaginatedIteratorFactory { @@ -11,16 +11,16 @@ public interface ICursorPaginatedIteratorFactory public class CursorPaginatedIteratorFactory : ICursorPaginatedIteratorFactory { - private static IServiceProvider serviceProvider; + private readonly IZendeskApiClient zendeskApiClient; - public CursorPaginatedIteratorFactory(IServiceProvider _serviceProvider) + public CursorPaginatedIteratorFactory(IZendeskApiClient _zendeskApiClient) { - serviceProvider = _serviceProvider; + zendeskApiClient = _zendeskApiClient; } public CursorPaginatedIterator Create(ICursorPagination response) { - return new CursorPaginatedIterator(response, serviceProvider.GetRequiredService()); + return new CursorPaginatedIterator(response, zendeskApiClient); } } } diff --git a/src/ZendeskApi.Client/ZendeskApi.Client.csproj b/src/ZendeskApi.Client/ZendeskApi.Client.csproj index e0816341..47554757 100644 --- a/src/ZendeskApi.Client/ZendeskApi.Client.csproj +++ b/src/ZendeskApi.Client/ZendeskApi.Client.csproj @@ -17,4 +17,10 @@ + + + + + + From 0af94f4ab51df4da2a789ccdb748eaeca6f81f56 Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Wed, 13 Dec 2023 16:15:13 +1100 Subject: [PATCH 09/11] address comments and add new factory to the tests --- .../CursorPaginatedIterator.cs | 3 +-- .../CursorPaginatedIteratorFactory.cs | 2 -- .../ZendeskApi.Client.csproj | 10 ++------- .../CBPSupport/CBPSupportTests.cs | 18 +++++++++------- .../CursorPaginatedIteratorFactory.cs | 21 +++++++++++++++++++ .../Resources/JobStatusResourceTests.cs | 18 +++++++--------- .../Resources/RequestsResourceTests.cs | 5 +++-- 7 files changed, 45 insertions(+), 32 deletions(-) rename src/ZendeskApi.Client/{Models => Pagination}/CursorPaginatedIterator.cs (97%) create mode 100644 test/ZendeskApi.Client.IntegrationTests/Factories/CursorPaginatedIteratorFactory.cs diff --git a/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs b/src/ZendeskApi.Client/Pagination/CursorPaginatedIterator.cs similarity index 97% rename from src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs rename to src/ZendeskApi.Client/Pagination/CursorPaginatedIterator.cs index d6a3f67c..6fa075d5 100644 --- a/src/ZendeskApi.Client/Models/CursorPaginatedIterator.cs +++ b/src/ZendeskApi.Client/Pagination/CursorPaginatedIterator.cs @@ -1,12 +1,11 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Newtonsoft.Json; -using ZendeskApi.Client; using ZendeskApi.Client.Responses; +namespace ZendeskApi.Client.Pagination; public class CursorPaginatedIterator : IEnumerable { diff --git a/src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs b/src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs index fcffa3d9..53a5723c 100644 --- a/src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs +++ b/src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs @@ -1,5 +1,3 @@ -using System; -using Microsoft.Extensions.DependencyInjection; using ZendeskApi.Client.Responses; namespace ZendeskApi.Client.Pagination diff --git a/src/ZendeskApi.Client/ZendeskApi.Client.csproj b/src/ZendeskApi.Client/ZendeskApi.Client.csproj index 47554757..4818fc22 100644 --- a/src/ZendeskApi.Client/ZendeskApi.Client.csproj +++ b/src/ZendeskApi.Client/ZendeskApi.Client.csproj @@ -1,7 +1,7 @@ - + - + netstandard2.0;net6.0 A Zendesk Api Client for use with the ZendeskApi v2 @@ -17,10 +17,4 @@ - - - - - - diff --git a/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs b/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs index 8aa42adc..bca9ff07 100644 --- a/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/CBPSupport/CBPSupportTests.cs @@ -3,23 +3,26 @@ using Xunit; using ZendeskApi.Client.IntegrationTests.Factories; using ZendeskApi.Client.Models; +using CursorPaginatedIteratorFactory = ZendeskApi.Client.IntegrationTests.Factories.CursorPaginatedIteratorFactory; namespace ZendeskApi.Client.IntegrationTests.CBPSupport { public class CBPSupportTests : IClassFixture { - private readonly ZendeskClientFactory _clientFactory; + private readonly ZendeskClientFactory clientFactory; + private readonly CursorPaginatedIteratorFactory cursorPaginatedIteratorFactory; public CBPSupportTests( - ZendeskClientFactory clientFactory) + ZendeskClientFactory _clientFactory) { - _clientFactory = clientFactory; + clientFactory = _clientFactory; + cursorPaginatedIteratorFactory = new Factories.CursorPaginatedIteratorFactory(clientFactory); } [Fact] public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatableByReplacingTheCursor() { - var client = _clientFactory.GetClient(); + var client = clientFactory.GetClient(); var cursorPager = new CursorPager { Size = 5 }; var ticketsPageOne = await client @@ -43,14 +46,13 @@ public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatable [Fact] public async Task CursorPaginatedIterator_ShouldBePaginatableByCallingNextPage() { - var client = _clientFactory.GetClient(); - var apiClient = _clientFactory.GetApiClient(); - + var client = clientFactory.GetClient(); + var cursorPager = new CursorPager { Size = 2 }; var ticketsResponse = await client .Tickets.GetAllAsync(cursorPager); - var iterator = new CursorPaginatedIterator(ticketsResponse, apiClient); + var iterator = cursorPaginatedIteratorFactory.Create(ticketsResponse); Assert.True(iterator.HasMore()); Assert.Equal(2, iterator.Count()); var ticketIdsPageOne = iterator.Select(ticket => ticket.Id).ToList(); diff --git a/test/ZendeskApi.Client.IntegrationTests/Factories/CursorPaginatedIteratorFactory.cs b/test/ZendeskApi.Client.IntegrationTests/Factories/CursorPaginatedIteratorFactory.cs new file mode 100644 index 00000000..bc1684ed --- /dev/null +++ b/test/ZendeskApi.Client.IntegrationTests/Factories/CursorPaginatedIteratorFactory.cs @@ -0,0 +1,21 @@ +using System; +using ZendeskApi.Client.Pagination; +using ZendeskApi.Client.Responses; + +namespace ZendeskApi.Client.IntegrationTests.Factories +{ + public class CursorPaginatedIteratorFactory + { + private readonly ZendeskClientFactory zendeskClientFactory; + public CursorPaginatedIteratorFactory(ZendeskClientFactory _zendeskClientFactory) + { + zendeskClientFactory = _zendeskClientFactory; + } + + public CursorPaginatedIterator Create(ICursorPagination response) + { + return new CursorPaginatedIterator(response, zendeskClientFactory.GetApiClient()); + } + } +} + diff --git a/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs b/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs index 67a322aa..df8f1f08 100644 --- a/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/Resources/JobStatusResourceTests.cs @@ -1,36 +1,34 @@ -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Xunit; using ZendeskApi.Client.IntegrationTests.Factories; using ZendeskApi.Client.Models; -using ZendeskApi.Client.Responses; namespace ZendeskApi.Client.IntegrationTests.Resources { public class JobStatusResourceTests : IClassFixture { - private readonly ZendeskClientFactory _clientFactory; - + private readonly ZendeskClientFactory clientFactory; + private readonly CursorPaginatedIteratorFactory cursorPaginatedIteratorFactory; public JobStatusResourceTests( - ZendeskClientFactory clientFactory) + ZendeskClientFactory _clientFactory) { - _clientFactory = clientFactory; + clientFactory = _clientFactory; + cursorPaginatedIteratorFactory = new CursorPaginatedIteratorFactory(clientFactory); } [Fact] public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatable() { - var client = _clientFactory.GetClient(); - var apiClient = _clientFactory.GetApiClient(); + var client = clientFactory.GetClient(); var results = await client .JobStatuses.GetAllAsync(new CursorPager() { Size = 2 }); - var iterator = new CursorPaginatedIterator(results, apiClient); + var iterator = cursorPaginatedIteratorFactory.Create(results); Assert.NotNull(results); Assert.Equal(2, iterator.Count()); @@ -40,4 +38,4 @@ public async Task GetAllAsync_WhenCalledWithCursorPagination_ShouldBePaginatable } } -} \ No newline at end of file +} diff --git a/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs b/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs index 51e55237..ba025307 100644 --- a/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs +++ b/test/ZendeskApi.Client.IntegrationTests/Resources/RequestsResourceTests.cs @@ -12,6 +12,7 @@ public class RequestsResourceTests : IClassFixture { private readonly ITestOutputHelper _output; private readonly ZendeskClientFactory _clientFactory; + private readonly CursorPaginatedIteratorFactory cursorPaginatedIteratorFactory; public RequestsResourceTests( ITestOutputHelper output, @@ -19,6 +20,7 @@ public RequestsResourceTests( { _output = output; _clientFactory = clientFactory; + cursorPaginatedIteratorFactory = new CursorPaginatedIteratorFactory(clientFactory); } [Fact] @@ -249,11 +251,10 @@ public async Task UpdateAsync_WhenCalled_ShouldUpdateRequest() public async Task GetAllAsync_And_GetAllComments_ShouldBePaginatable() { var client = _clientFactory.GetClient(); - var apiClient = _clientFactory.GetApiClient(); var cursor = new CursorPager { Size = 1 }; var requestsResponse = await client.Requests.GetAllAsync(cursor); - var requestsIterator = new CursorPaginatedIterator(requestsResponse, apiClient); + var requestsIterator = cursorPaginatedIteratorFactory.Create(requestsResponse); Assert.Equal(1, requestsIterator.Count()); var commentsResponse = await client.Requests.GetAllComments((long)requestsIterator.First().Id, cursor); From 12dab12b9c574212e610bba49b0c630883788bfb Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Wed, 10 Jan 2024 15:47:04 +1100 Subject: [PATCH 10/11] bump version --- src/ZendeskApi.Build/ZendeskApi.Commons.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZendeskApi.Build/ZendeskApi.Commons.props b/src/ZendeskApi.Build/ZendeskApi.Commons.props index 8c512508..9456e83e 100644 --- a/src/ZendeskApi.Build/ZendeskApi.Commons.props +++ b/src/ZendeskApi.Build/ZendeskApi.Commons.props @@ -23,7 +23,7 @@ 7 0 - 6 + 7 $(Major).$(Minor).$(Revision) From 20dd4ae3bda67f12d7d69cc4b1e5a3b9e4dfd58a Mon Sep 17 00:00:00 2001 From: Fabio Vilela Date: Mon, 22 Jan 2024 14:08:29 +1100 Subject: [PATCH 11/11] fix tests regarding mmethod that had been made obsolete which caused a build failure. --- .../Resources/TicketAuditResourceTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/ZendeskApi.Client.Tests/Resources/TicketAuditResourceTests.cs b/test/ZendeskApi.Client.Tests/Resources/TicketAuditResourceTests.cs index 03971c7e..7233520c 100644 --- a/test/ZendeskApi.Client.Tests/Resources/TicketAuditResourceTests.cs +++ b/test/ZendeskApi.Client.Tests/Resources/TicketAuditResourceTests.cs @@ -21,6 +21,7 @@ public TicketAuditResourceTests() } [Fact] + [Obsolete] public async Task GetAllAsync_WhenCalled_ShouldGetAllTicketAudits() { var results = await _resource.GetAllAsync(); @@ -29,6 +30,7 @@ public async Task GetAllAsync_WhenCalled_ShouldGetAllTicketAudits() } [Fact] + [Obsolete] public async Task GetAllAsync_WhenCalledAndLimitSet_ShouldGetAllTicketAudits() { var results = await _resource.GetAllAsync(new CursorPagerVariant