Skip to content

Commit

Permalink
Merge pull request #327 from justeat/develop
Browse files Browse the repository at this point in the history
develop -> master ([RED-2026])
  • Loading branch information
Ud0o authored Jan 22, 2024
2 parents 621cde8 + 1e66e47 commit 969bf09
Show file tree
Hide file tree
Showing 24 changed files with 450 additions and 13 deletions.
50 changes: 48 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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
Expand All @@ -63,11 +64,19 @@ 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
- 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

[Further reading on Zendesk Pagination changes](https://support.zendesk.com/hc/en-us/articles/4402610093338-Introducing-Pagination-Changes-Zendesk-API)

## 3.x.x
Expand Down Expand Up @@ -126,6 +135,43 @@ await client.Search.SearchAsync<Ticket>(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<IZendeskClient>();

var ticketCursorResponse = await client.Tickets.GetAllAsync(new CursorPager { Size = 5 }); // low page number to force pagination
var iteratorFactory = serviceProvider.GetRequiredService<ICursorPaginatedIteratorFactory>();
// creates the iterator with the response object of the first request
var iterator = iteratorFactory.Create<Ticket>(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
Expand Down
2 changes: 1 addition & 1 deletion src/ZendeskApi.Build/ZendeskApi.Commons.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<PropertyGroup>
<Major>7</Major>
<Minor>0</Minor>
<Revision>6</Revision>
<Revision>7</Revision>
<PackageVersion>$(Major).$(Minor).$(Revision)</PackageVersion>
</PropertyGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using ZendeskApi.Client.Models;
using ZendeskApi.Client.Options;
using ZendeskApi.Client.Pagination;
#pragma warning disable 618

namespace ZendeskApi.Client.Extensions
Expand Down Expand Up @@ -33,6 +35,7 @@ public static IServiceCollection AddZendeskClientWithHttpClientFactory(this ISer
{
services.AddScoped<IZendeskClient, ZendeskClient>();
services.AddScoped<IZendeskApiClient, ZendeskApiClientFactory>();
services.AddScoped<ICursorPaginatedIteratorFactory, CursorPaginatedIteratorFactory>();

services.AddHttpClient("zendeskApiClient", c =>
{
Expand Down
2 changes: 1 addition & 1 deletion src/ZendeskApi.Client/IZendeskClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ public interface IZendeskClient
ILocaleResource Locales { get; }
ITagsResource Tags { get; }
}
}
}
73 changes: 73 additions & 0 deletions src/ZendeskApi.Client/Pagination/CursorPaginatedIterator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
using ZendeskApi.Client.Responses;

namespace ZendeskApi.Client.Pagination;
public class CursorPaginatedIterator<T> : IEnumerable<T>
{

public ICursorPagination<T> Response { get; set; }

private IZendeskApiClient client;


private string ResponseType { get; }

public CursorPaginatedIterator(ICursorPagination<T> response, IZendeskApiClient client)
{
Response = response;
this.client = client;
ResponseType = response.GetType().FullName;
}

public bool HasMore() => Response.Meta.HasMore;

public IEnumerator<T> GetEnumerator()
{
return Response.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return Response.GetEnumerator();
}


public async Task NextPage()
{
await ExecuteRequest(Response.Links.Next);
}

public async Task PrevPage()
{
await ExecuteRequest(Response.Links.Prev);
}

public async IAsyncEnumerable<T> 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.CreateClient().GetAsync(requestUrl);
var responseBody = await httpResponseMessage.Content.ReadAsStringAsync();
Response = (ICursorPagination<T>)JsonConvert.DeserializeObject(responseBody, Type.GetType(ResponseType));
}

}
25 changes: 25 additions & 0 deletions src/ZendeskApi.Client/Pagination/CursorPaginatedIteratorFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using ZendeskApi.Client.Responses;

namespace ZendeskApi.Client.Pagination
{
public interface ICursorPaginatedIteratorFactory
{
CursorPaginatedIterator<T> Create<T>(ICursorPagination<T> response);
}

public class CursorPaginatedIteratorFactory : ICursorPaginatedIteratorFactory
{
private readonly IZendeskApiClient zendeskApiClient;

public CursorPaginatedIteratorFactory(IZendeskApiClient _zendeskApiClient)
{
zendeskApiClient = _zendeskApiClient;
}

public CursorPaginatedIterator<T> Create<T>(ICursorPagination<T> response)
{
return new CursorPaginatedIterator<T>(response, zendeskApiClient);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,22 @@ public interface IJobStatusResource
/// <summary>
/// Shows the current statuses for background jobs running.
/// </summary>
[Obsolete("Use `GetAllAsync` instead.")]
[Obsolete("Use `GetAllAsync` with CursorPager instead.")]
Task<IPagination<JobStatusResponse>> ListAsync(
PagerParameters pagerParameters = null,
CancellationToken cancellationToken = default(CancellationToken));

/// <summary>
/// Shows the current statuses for background jobs running.
/// </summary>
[Obsolete("Use `GetAllAsync` with CursorPager instead.")]
Task<IPagination<JobStatusResponse>> GetAllAsync(
PagerParameters pagerParameters = null,
CancellationToken cancellationToken = default(CancellationToken));

Task<ICursorPagination<JobStatusResponse>> GetAllAsync(
CursorPager pagerParameters = null,
CancellationToken cancellationToken = default(CancellationToken));
#endregion

#region Show
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Task<IPagination<Request>> GetAllAsync(
PagerParameters pager = null,
CancellationToken cancellationToken = default);

Task<ICursorPagination<Request>> GetAllAsync(
CursorPager pager,
CancellationToken cancellationToken = default);

Task<Request> GetAsync(
long requestId,
CancellationToken cancellationToken = default);
Expand All @@ -29,6 +33,11 @@ Task<IPagination<TicketComment>> GetAllComments(
PagerParameters pager = null,
CancellationToken cancellationToken = default);

Task<ICursorPagination<TicketComment>> GetAllComments(
long requestId,
CursorPager pager,
CancellationToken cancellationToken = default);

Task<TicketComment> GetTicketCommentAsync(
long requestId,
long commentId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace ZendeskApi.Client.Resources
public interface ITicketAuditResource
{
Task<TicketAuditResponse> GetAllAsync(CursorPagerVariant pager = null, CancellationToken cancellationToken = default);
Task<TicketAuditCursorResponse> GetAllAsync(CursorPager pager, CancellationToken cancellationToken = default);
Task<TicketAuditResponse> GetAllByTicketAsync(long ticketId, CancellationToken cancellationToken = default);
Task<SingleTicketAuditResponse> Get(int ticketId, int auditId, CancellationToken cancellationToken = default);
}
Expand Down
14 changes: 13 additions & 1 deletion src/ZendeskApi.Client/Resources/JobStatusResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public JobStatusResource(
: base(apiClient, logger, "job_statuses")
{ }

[Obsolete("Use `GetAllAsync` instead.")]
[Obsolete("Use `GetAllAsync` with CursorPager instead.")]
public async Task<IPagination<JobStatusResponse>> ListAsync(
PagerParameters pagerParameters = null,
CancellationToken cancellationToken = default(CancellationToken))
Expand All @@ -29,6 +29,18 @@ public async Task<IPagination<JobStatusResponse>> ListAsync(
cancellationToken);
}

public async Task<ICursorPagination<JobStatusResponse>> GetAllAsync(CursorPager pagerParameters, CancellationToken cancellationToken = default)
{
return await GetAsync<JobStatusListCursorResponse>(
ResourceUri,
"list-job-statuses",
"ListAsync",
pagerParameters,
null,
cancellationToken: cancellationToken);
}

[Obsolete("Use `GetAllAsync` with CursorPager instead.")]
public async Task<IPagination<JobStatusResponse>> GetAllAsync(
PagerParameters pagerParameters = null,
CancellationToken cancellationToken = default(CancellationToken))
Expand Down
24 changes: 24 additions & 0 deletions src/ZendeskApi.Client/Resources/RequestsResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ public async Task<IPagination<Request>> GetAllAsync(
cancellationToken: cancellationToken);
}

public async Task<ICursorPagination<Request>> GetAllAsync(
CursorPager pager,
CancellationToken cancellationToken = default)
{
return await GetAsync<RequestsCursorResponse>(
ResourceUri,
"list-requests",
"GetAllAsync",
pager,
cancellationToken: cancellationToken);
}


public async Task<Request> GetAsync(
long requestId,
Expand Down Expand Up @@ -79,6 +91,17 @@ public async Task<IPagination<TicketComment>> GetAllComments(
cancellationToken);
}

public async Task<ICursorPagination<TicketComment>> GetAllComments(long requestId, CursorPager pager, CancellationToken cancellationToken = default)
{
return await GetWithNotFoundCheckAsync<TicketCommentsListCursorResponse>(
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<TicketComment> GetTicketCommentAsync(
long requestId,
long commentId,
Expand Down Expand Up @@ -121,5 +144,6 @@ public async Task<Request> UpdateAsync(
return response?
.Request;
}

}
}
13 changes: 13 additions & 0 deletions src/ZendeskApi.Client/Resources/Ticket/TicketAuditResource.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
Expand All @@ -17,6 +18,7 @@ public TicketAuditResource(IZendeskApiClient apiClient, ILogger logger) : base(a
{
}

[Obsolete("Use `GetAllAsync` with CursorPager parameter instead.")]
public async Task<TicketAuditResponse> GetAllAsync(CursorPagerVariant pager = null, CancellationToken cancellationToken = default)
{
return await GetAsync<TicketAuditResponse>(
Expand All @@ -27,6 +29,17 @@ public async Task<TicketAuditResponse> GetAllAsync(CursorPagerVariant pager = nu
cancellationToken);
}

public async Task<TicketAuditCursorResponse> GetAllAsync(CursorPager pager, CancellationToken cancellationToken = default)
{
return await GetAsync<TicketAuditCursorResponse>(
ResourceUri,
"list-all-ticket-audits",
"GetAllAsync",
pager,
null,
cancellationToken);
}

public async Task<TicketAuditResponse> GetAllByTicketAsync(long ticketId, CancellationToken cancellationToken = default)
{
return await GetAsync<TicketAuditResponse>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using ZendeskApi.Client.Models;

namespace ZendeskApi.Client.Responses
{
[JsonObject]
public class JobStatusListCursorResponse : CursorPaginationResponse<JobStatusResponse>
{
[JsonProperty("job_statuses")]
public IEnumerable<JobStatusResponse> JobStatuses { get; set; }

protected override IEnumerable<JobStatusResponse> Enumerable => JobStatuses;
}
}
Loading

0 comments on commit 969bf09

Please sign in to comment.