diff --git a/Octokit.Tests/Clients/AuthorizationsClientTests.cs b/Octokit.Tests/Clients/AuthorizationsClientTests.cs index af18967e..1a05b4f4 100644 --- a/Octokit.Tests/Clients/AuthorizationsClientTests.cs +++ b/Octokit.Tests/Clients/AuthorizationsClientTests.cs @@ -35,7 +35,7 @@ namespace Octokit.Tests.Clients client.Received().GetAll( Arg.Is(u => u.ToString() == "authorizations"), - null); + Arg.Is>(d => d == null)); } } diff --git a/Octokit.Tests/Http/ApiConnectionTests.cs b/Octokit.Tests/Http/ApiConnectionTests.cs index f0dd7b6d..5f3b7d22 100644 --- a/Octokit.Tests/Http/ApiConnectionTests.cs +++ b/Octokit.Tests/Http/ApiConnectionTests.cs @@ -90,13 +90,13 @@ namespace Octokit.Tests.Http new Response(), new List { new object(), new object() }); var connection = Substitute.For(); - connection.Get>(Args.Uri, null, null).Returns(Task.FromResult(response)); + connection.Get>(Args.Uri, Args.EmptyDictionary, null).Returns(Task.FromResult(response)); var apiConnection = new ApiConnection(connection); var data = await apiConnection.GetAll(getAllUri); Assert.Equal(2, data.Count); - connection.Received().Get>(getAllUri, null, null); + connection.Received().Get>(getAllUri, Args.EmptyDictionary, null); } [Fact] diff --git a/Octokit/Clients/AuthorizationsClient.cs b/Octokit/Clients/AuthorizationsClient.cs index 440918a5..e7fd862e 100644 --- a/Octokit/Clients/AuthorizationsClient.cs +++ b/Octokit/Clients/AuthorizationsClient.cs @@ -36,7 +36,7 @@ namespace Octokit /// A list of s. public Task> GetAll() { - return ApiConnection.GetAll(ApiUrls.Authorizations(), null); + return ApiConnection.GetAll(ApiUrls.Authorizations(), (IDictionary)null); } /// diff --git a/Octokit/Helpers/ApiExtensions.cs b/Octokit/Helpers/ApiExtensions.cs index 5a3c9a15..81b1ab8e 100644 --- a/Octokit/Helpers/ApiExtensions.cs +++ b/Octokit/Helpers/ApiExtensions.cs @@ -26,7 +26,7 @@ namespace Octokit Ensure.ArgumentNotNull(connection, "connection"); Ensure.ArgumentNotNull(uri, "uri"); - return connection.GetAll(uri, null); + return connection.GetAll(uri, ApiOptions.None); } /// diff --git a/Octokit/Http/ApiConnection.cs b/Octokit/Http/ApiConnection.cs index 5821e327..179d898d 100644 --- a/Octokit/Http/ApiConnection.cs +++ b/Octokit/Http/ApiConnection.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; +using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -115,7 +117,20 @@ namespace Octokit /// Thrown when an API error occurs. public Task> GetAll(Uri uri) { - return GetAll(uri, null, null); + return GetAll(uri, ApiOptions.None); + } + + /// + /// Gets all API resources in the list at the specified URI. + /// + /// Type of the API resource in the list. + /// URI of the API resource to get + /// Options for changing the API response + /// of the The API resources in the list. + /// Thrown when an API error occurs. + public Task> GetAll(Uri uri, ApiOptions options) + { + return GetAll(uri, null, null, options); } /// @@ -128,7 +143,21 @@ namespace Octokit /// Thrown when an API error occurs. public Task> GetAll(Uri uri, IDictionary parameters) { - return GetAll(uri, parameters, null); + return GetAll(uri, parameters, null, ApiOptions.None); + } + + /// + /// Gets all API resources in the list at the specified URI. + /// + /// Type of the API resource in the list. + /// URI of the API resource to get + /// Parameters to add to the API request + /// Options for changing the API response + /// of the The API resources in the list. + /// Thrown when an API error occurs. + public Task> GetAll(Uri uri, IDictionary parameters, ApiOptions options) + { + return GetAll(uri, parameters, null, options); } /// @@ -148,6 +177,27 @@ namespace Octokit .ConfigureAwait(false), uri); } + public Task> GetAll(Uri uri, IDictionary parameters, string accepts, ApiOptions options) + { + Ensure.ArgumentNotNull(uri, "uri"); + Ensure.ArgumentNotNull(options, "options"); + + parameters = parameters ?? new Dictionary(); + + if (options.PageSize.HasValue) + { + parameters.Add("per_page", options.PageSize.Value.ToString(CultureInfo.InvariantCulture)); + } + + if (options.StartPage.HasValue) + { + parameters.Add("page", options.StartPage.Value.ToString(CultureInfo.InvariantCulture)); + } + + return _pagination.GetAllPages(async () => await GetPage(uri, parameters, accepts, options) + .ConfigureAwait(false), uri); + } + /// /// Creates a new API resource in the list at the specified URI. /// @@ -483,5 +533,61 @@ namespace Octokit response, nextPageUri => Connection.Get>(nextPageUri, parameters, accepts)); } + + async Task> GetPage( + Uri uri, + IDictionary parameters, + string accepts, + ApiOptions options) + { + Ensure.ArgumentNotNull(uri, "uri"); + + var connection = Connection; + + var response = await connection.Get>(uri, parameters, accepts).ConfigureAwait(false); + return new ReadOnlyPagedCollection( + response, + nextPageUri => + { + if (nextPageUri.Query.Contains("page=") && options.PageCount.HasValue) + { + var allValues = ToQueryStringDictionary(nextPageUri); + + string pageValue; + if (allValues.TryGetValue("page", out pageValue)) + { + var startPage = options.StartPage ?? 1; + var pageCount = options.PageCount.Value; + + var endPage = startPage + pageCount; + if (pageValue.Equals(endPage.ToString(), StringComparison.OrdinalIgnoreCase)) + { + return null; + } + } + } + + return connection.Get>(nextPageUri, parameters, accepts); + }); + } + + static Dictionary ToQueryStringDictionary(Uri uri) + { + return uri.Query.Split('&') + .Select(keyValue => + { + var indexOf = keyValue.IndexOf('='); + if (indexOf > 0) + { + var key = keyValue.Substring(0, indexOf); + var value = keyValue.Substring(indexOf + 1); + return new KeyValuePair(key, value); + } + + //just a plain old value, return it + return new KeyValuePair(keyValue, null); + }) + .ToDictionary(x => x.Key, x => x.Value); + } } } diff --git a/Octokit/Http/IApiConnection.cs b/Octokit/Http/IApiConnection.cs index c111707b..37239067 100644 --- a/Octokit/Http/IApiConnection.cs +++ b/Octokit/Http/IApiConnection.cs @@ -71,6 +71,16 @@ namespace Octokit /// Thrown when an API error occurs. Task> GetAll(Uri uri); + /// + /// Gets all API resources in the list at the specified URI. + /// + /// Type of the API resource in the list. + /// URI of the API resource to get + /// Options for changing the API response + /// of the The API resources in the list. + /// Thrown when an API error occurs. + Task> GetAll(Uri uri, ApiOptions options); + /// /// Gets all API resources in the list at the specified URI. /// @@ -81,6 +91,17 @@ namespace Octokit /// Thrown when an API error occurs. Task> GetAll(Uri uri, IDictionary parameters); + /// + /// Gets all API resources in the list at the specified URI. + /// + /// Type of the API resource in the list. + /// URI of the API resource to get + /// Parameters to add to the API request + /// Options for changing the API response + /// of the The API resources in the list. + /// Thrown when an API error occurs. + Task> GetAll(Uri uri, IDictionary parameters, ApiOptions options); + /// /// Gets all API resources in the list at the specified URI. /// @@ -92,6 +113,18 @@ namespace Octokit /// Thrown when an API error occurs. Task> GetAll(Uri uri, IDictionary parameters, string accepts); + /// + /// Gets all API resources in the list at the specified URI. + /// + /// Type of the API resource in the list. + /// URI of the API resource to get + /// Parameters to add to the API request + /// Accept header to use for the API request + /// Options for changing the API response + /// of the The API resources in the list. + /// Thrown when an API error occurs. + Task> GetAll(Uri uri, IDictionary parameters, string accepts, ApiOptions options); + /// /// Creates a new API resource in the list at the specified URI. ///