diff --git a/Octokit.Reactive/Clients/IObservableGistsClient.cs b/Octokit.Reactive/Clients/IObservableGistsClient.cs index 5bb29ede..31ea9da5 100644 --- a/Octokit.Reactive/Clients/IObservableGistsClient.cs +++ b/Octokit.Reactive/Clients/IObservableGistsClient.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Reactive; namespace Octokit.Reactive { @@ -16,6 +17,143 @@ namespace Octokit.Reactive /// The id of the gist [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "Method makes a network request")] - IObservable Get(string id); + IObservable Get(string id); + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + IObservable GetAll(); + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + IObservable GetAll(DateTimeOffset since); + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + IObservable GetAllPublic(); + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + IObservable GetAllPublic(DateTimeOffset since); + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + IObservable GetAllStarred(); + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + IObservable GetAllStarred(DateTimeOffset since); + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + IObservable GetAllForUser(string user); + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + /// Only gists updated at or after this time are returned + IObservable GetAllForUser(string user, DateTimeOffset since); + + /// + /// Creates a new gist + /// + /// + /// http://developer.github.com/v3/gists/#create-a-gist + /// + /// The new gist to create + IObservable Create(NewGist newGist); + + /// + /// Creates a fork of a gist + /// + /// + /// http://developer.github.com/v3/gists/#fork-a-gist + /// + /// The id of the gist to fork + IObservable Fork(string id); + + /// + /// Edits a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + /// The update to the gist + IObservable Edit(string id, GistUpdate gistUpdate); + + /// + /// Deletes a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + IObservable Delete(string id); + + /// + /// Stars a gist + /// + /// + /// http://developer.github.com/v3/gists/#star-a-gist + /// + /// The id of the gist + IObservable Star(string id); + + /// + /// Unstars a gist + /// + /// + /// http://developer.github.com/v3/gists/#unstar-a-gist + /// + /// The id of the gist + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unstar")] + IObservable Unstar(string id); + + /// + /// Checks if the gist is starred + /// + /// + /// http://developer.github.com/v3/gists/#check-if-a-gist-is-starred + /// + /// The id of the gist + IObservable IsStarred(string id); } } \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableGistsClient.cs b/Octokit.Reactive/Clients/ObservableGistsClient.cs index 63c2e6b7..8fe981b8 100644 --- a/Octokit.Reactive/Clients/ObservableGistsClient.cs +++ b/Octokit.Reactive/Clients/ObservableGistsClient.cs @@ -1,17 +1,22 @@ using System; using System.Reactive.Threading.Tasks; +using System.Reactive; +using System.Net; +using Octokit.Reactive.Internal; namespace Octokit.Reactive { public class ObservableGistsClient : IObservableGistsClient { readonly IGistsClient _client; + readonly IConnection _connection; public ObservableGistsClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); _client = client.Gist; + _connection = client.Connection; Comment = new ObservableGistCommentsClient(client); } @@ -31,5 +36,203 @@ namespace Octokit.Reactive return _client.Get(id).ToObservable(); } + + /// + /// Creates a new gist + /// + /// + /// http://developer.github.com/v3/gists/#create-a-gist + /// + /// The new gist to create + public IObservable Create(NewGist newGist) + { + Ensure.ArgumentNotNull(newGist, "newGist"); + + return _client.Create(newGist).ToObservable(); + } + + /// + /// Creates a fork of a gist + /// + /// + /// http://developer.github.com/v3/gists/#fork-a-gist + /// + /// The id of the gist to fork + public IObservable Fork(string id) + { + return _client.Fork(id).ToObservable(); + } + + /// + /// Deletes a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + public IObservable Delete(string id) + { + Ensure.ArgumentNotNull(id, "id"); + + return _client.Delete(id).ToObservable(); + } + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + public IObservable GetAll() + { + return _connection.GetAndFlattenAllPages(ApiUrls.Gist()); + } + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + public IObservable GetAll(DateTimeOffset since) + { + var request = new GistRequest(since); + return _connection.GetAndFlattenAllPages(ApiUrls.Gist(), request.ToParametersDictionary()); + } + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + public IObservable GetAllPublic() + { + return _connection.GetAndFlattenAllPages(ApiUrls.PublicGists()); + } + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + public IObservable GetAllPublic(DateTimeOffset since) + { + var request = new GistRequest(since); + return _connection.GetAndFlattenAllPages(ApiUrls.PublicGists(), request.ToParametersDictionary()); + } + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + public IObservable GetAllStarred() + { + return _connection.GetAndFlattenAllPages(ApiUrls.StarredGists()); + } + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + public IObservable GetAllStarred(DateTimeOffset since) + { + var request = new GistRequest(since); + return _connection.GetAndFlattenAllPages(ApiUrls.StarredGists(), request.ToParametersDictionary()); + } + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + public IObservable GetAllForUser(string user) + { + Ensure.ArgumentNotNull(user, "user"); + + return _connection.GetAndFlattenAllPages(ApiUrls.UsersGists(user)); + } + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + /// Only gists updated at or after this time are returned + public IObservable GetAllForUser(string user, DateTimeOffset since) + { + Ensure.ArgumentNotNull(user, "user"); + + var request = new GistRequest(since); + return _connection.GetAndFlattenAllPages(ApiUrls.UsersGists(user), request.ToParametersDictionary()); + } + + /// + /// Edits a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + /// The update to the gist + public IObservable Edit(string id, GistUpdate gistUpdate) + { + Ensure.ArgumentNotNull(id, "id"); + Ensure.ArgumentNotNull(gistUpdate, "gistUpdate"); + + return _client.Edit(id, gistUpdate).ToObservable(); + } + + /// + /// Stars a gist + /// + /// + /// http://developer.github.com/v3/gists/#star-a-gist + /// + /// The id of the gist + public IObservable Star(string id) + { + return _client.Star(id).ToObservable(); + } + + /// + /// Unstars a gist + /// + /// + /// http://developer.github.com/v3/gists/#unstar-a-gist + /// + /// The id of the gist + public IObservable Unstar(string id) + { + return _client.Unstar(id).ToObservable(); + } + + /// + /// Checks if the gist is starred + /// + /// + /// http://developer.github.com/v3/gists/#check-if-a-gist-is-starred + /// + /// The id of the gist + public IObservable IsStarred(string id) + { + Ensure.ArgumentNotNullOrEmptyString(id, "id"); + + return _client.IsStarred(id).ToObservable(); + } } } \ No newline at end of file diff --git a/Octokit.Tests.Integration/Clients/GistsClientTests.cs b/Octokit.Tests.Integration/Clients/GistsClientTests.cs index a5a49411..344431ff 100644 --- a/Octokit.Tests.Integration/Clients/GistsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/GistsClientTests.cs @@ -3,10 +3,15 @@ using System.Threading.Tasks; using Octokit; using Octokit.Tests.Integration; using Xunit; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System; +using System.Linq; public class GistsClientTests { readonly IGistsClient _fixture; + readonly string testGistId = "6305249"; public GistsClientTests() { @@ -21,7 +26,112 @@ public class GistsClientTests [IntegrationTest] public async Task CanGetGist() { - var retrieved = await _fixture.Get("6305249"); + var retrieved = await _fixture.Get(testGistId); Assert.NotNull(retrieved); } + + [IntegrationTest] + public async Task CanCreateEditAndDeleteAGist() + { + var newGist = new NewGist(); + newGist.Description = "my new gist"; + newGist.Public = true; + + newGist.Files.Add("myGistTestFile.cs", "new GistsClient(connection).Create();"); + + var createdGist = await _fixture.Create(newGist); + + Assert.NotNull(createdGist); + Assert.Equal(newGist.Description, createdGist.Description); + Assert.Equal(newGist.Public, createdGist.Public); + + var gistUpdate = new GistUpdate(); + gistUpdate.Description = "my newly updated gist"; + var gistFileUpdate = new GistFileUpdate + { + NewFileName = "myNewGistTestFile.cs", + Content = "new GistsClient(connection).Edit();" + }; + + gistUpdate.Files.Add("myGistTestFile.cs", gistFileUpdate); + + var updatedGist = await _fixture.Edit(createdGist.Id, gistUpdate); + + Assert.NotNull(updatedGist); + Assert.Equal(updatedGist.Description, gistUpdate.Description); + + Assert.DoesNotThrow(async () => { await _fixture.Delete(createdGist.Id); }); + } + + [IntegrationTest] + public async Task CanStarAndUnstarAGist() + { + Assert.DoesNotThrow(async () => { await _fixture.Star(testGistId); }); + + bool isStarredTrue = await _fixture.IsStarred(testGistId); + Assert.True(isStarredTrue); + + Assert.DoesNotThrow(async () => { await _fixture.Unstar(testGistId); }); + + bool isStarredFalse = await _fixture.IsStarred(testGistId); + Assert.False(isStarredFalse); + } + + [IntegrationTest] + public async Task CanForkAGist() + { + var forkedGist = await _fixture.Fork(testGistId); + + Assert.NotNull(forkedGist); + + await _fixture.Delete(forkedGist.Id); + } + + [IntegrationTest] + public async Task CanListGists() + { + // Time is tricky between local and remote, be leinent + var startTime = DateTimeOffset.Now.Subtract(TimeSpan.FromHours(1)); + var newGist = new NewGist(); + newGist.Description = "my new gist"; + newGist.Public = true; + + newGist.Files.Add("myGistTestFile.cs", "new GistsClient(connection).Create();"); + + var createdGist = await _fixture.Create(newGist); + + // Test get all Gists + var gists = await _fixture.GetAll(); + Assert.NotNull(gists); + + // Test get all Gists since startTime + gists = await _fixture.GetAll(startTime); + + Assert.NotNull(gists); + Assert.True(gists.Count > 0); + + // Make sure we can successfully request gists for another user + Assert.DoesNotThrow(async () => { await _fixture.GetAllForUser("FakeHaacked"); }); + Assert.DoesNotThrow(async () => { await _fixture.GetAllForUser("FakeHaacked", startTime); }); + + // Test public gists + var publicGists = await _fixture.GetAllPublic(); + Assert.True(publicGists.Count > 1); + + var publicGistsSinceStartTime = await _fixture.GetAllPublic(startTime); + Assert.True(publicGistsSinceStartTime.Count > 0); + + // Test starred gists + await _fixture.Star(createdGist.Id); + var starredGists = await _fixture.GetAllStarred(); + + Assert.NotNull(starredGists); + Assert.True(starredGists.Any(x => x.Id == createdGist.Id)); + + var starredGistsSinceStartTime = await _fixture.GetAllStarred(startTime); + Assert.NotNull(starredGistsSinceStartTime); + Assert.True(starredGistsSinceStartTime.Any(x => x.Id == createdGist.Id)); + + await _fixture.Delete(createdGist.Id); + } } \ No newline at end of file diff --git a/Octokit.Tests/Clients/GistsClientTests.cs b/Octokit.Tests/Clients/GistsClientTests.cs index ad3f6d76..3a3d8769 100644 --- a/Octokit.Tests/Clients/GistsClientTests.cs +++ b/Octokit.Tests/Clients/GistsClientTests.cs @@ -1,7 +1,14 @@ -using System; -using NSubstitute; +using NSubstitute; using Octokit; +using Octokit.Internal; +using Octokit.Tests.Helpers; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Net; +using System.Threading.Tasks; using Xunit; +using Xunit.Extensions; public class GistsClientTests { @@ -19,6 +26,247 @@ public class GistsClientTests } } + public class TheGetAllMethods + { + [Fact] + public void RequestsCorrectGetAllUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.GetAll(); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists")); + } + + [Fact] + public void RequestsCorrectGetAllWithSinceUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + DateTimeOffset since = DateTimeOffset.Now; + client.GetAll(since); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists"), + Arg.Is>(x => x.ContainsKey("since"))); + } + + [Fact] + public void RequestsCorrectGetAllPublicUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.GetAllPublic(); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists/public")); + } + + [Fact] + public void RequestsCorrectGetAllPublicWithSinceUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + DateTimeOffset since = DateTimeOffset.Now; + client.GetAllPublic(since); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists/public"), + Arg.Is>(x => x.ContainsKey("since"))); + } + + [Fact] + public void RequestsCorrectGetAllStarredUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.GetAllStarred(); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists/starred")); + } + + [Fact] + public void RequestsCorrectGetAllStarredWithSinceUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + DateTimeOffset since = DateTimeOffset.Now; + client.GetAllStarred(since); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists/starred"), + Arg.Is>(x => x.ContainsKey("since"))); + } + + [Fact] + public void RequestsCorrectGetGistsForAUserUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.GetAllForUser("octokit"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/octokit/gists")); + } + + [Fact] + public void RequestsCorrectGetGistsForAUserWithSinceUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + DateTimeOffset since = DateTimeOffset.Now; + client.GetAllForUser("octokit", since); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/octokit/gists"), + Arg.Is>(x => x.ContainsKey("since"))); + } + } + + public class TheCreateMethod + { + [Fact] + public void PostsToTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + var newGist = new NewGist(); + newGist.Description = "my new gist"; + newGist.Public = true; + + newGist.Files.Add("myGistTestFile.cs", "new GistsClient(connection).Create();"); + + client.Create(newGist); + + connection.Received().Post(Arg.Is(u => u.ToString() == "gists"), Arg.Any()); + } + } + + public class TheDeleteMethod + { + [Fact] + public void PostsToTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.Delete("1"); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "gists/1")); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + AssertEx.Throws(async () => await + client.Delete(null)); + } + } + + public class TheStarMethods + { + [Fact] + public void RequestsCorrectStarUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.Star("1"); + + connection.Received().Put(Arg.Is(u => u.ToString() == "gists/1/star")); + } + + [Fact] + public void RequestsCorrectUnstarUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.Unstar("1"); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "gists/1/star")); + } + + [Theory] + [InlineData(HttpStatusCode.NoContent, true)] + [InlineData(HttpStatusCode.NotFound, false)] + public async Task RequestsCorrectValueForStatusCode(HttpStatusCode status, bool expected) + { + var response = Task.Factory.StartNew>(() => + new ApiResponse { StatusCode = status }); + var connection = Substitute.For(); + connection.GetAsync(Arg.Is(u => u.ToString() == "gists/1/star"), + null, null).Returns(response); + var apiConnection = Substitute.For(); + apiConnection.Connection.Returns(connection); + var client = new GistsClient(apiConnection); + + var result = await client.IsStarred("1"); + + Assert.Equal(expected, result); + } + + [Fact] + public async Task ThrowsExceptionForInvalidStatusCode() + { + var response = Task.Factory.StartNew>(() => + new ApiResponse { StatusCode = HttpStatusCode.Conflict }); + var connection = Substitute.For(); + connection.GetAsync(Arg.Is(u => u.ToString() == "gists/1/star"), + null, null).Returns(response); + var apiConnection = Substitute.For(); + apiConnection.Connection.Returns(connection); + + var client = new GistsClient(apiConnection); + + AssertEx.Throws(async () => await client.IsStarred("1")); + } + } + + public class TheForkMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + client.Fork("1"); + + connection.Received().Post(Arg.Is(u => u.ToString() == "gists/1/forks"), + Arg.Any()); + } + } + + public class TheEditMethod + { + [Fact] + public void PostsToTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new GistsClient(connection); + + var updateGist = new GistUpdate(); + updateGist.Description = "my newly updated gist"; + var gistFileUpdate = new GistFileUpdate + { + NewFileName = "myNewGistTestFile.cs", + Content = "new GistsClient(connection).Edit();" + }; + + updateGist.Files.Add("myGistTestFile.cs", gistFileUpdate); + + client.Edit("1", updateGist); + + connection.Received().Patch(Arg.Is(u => u.ToString() == "gists/1"), Arg.Any()); + } + } + public class TheCtor { [Fact] diff --git a/Octokit/Clients/GistsClient.cs b/Octokit/Clients/GistsClient.cs index 44a62b69..e40bfb3c 100644 --- a/Octokit/Clients/GistsClient.cs +++ b/Octokit/Clients/GistsClient.cs @@ -1,4 +1,7 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; namespace Octokit { @@ -33,5 +36,243 @@ namespace Octokit { return ApiConnection.Get(ApiUrls.Gist(id)); } + + /// + /// Creates a new gist + /// + /// + /// http://developer.github.com/v3/gists/#create-a-gist + /// + /// The new gist to create + public Task Create(NewGist newGist) + { + Ensure.ArgumentNotNull(newGist, "newGist"); + + //Required to create anonymous object to match signature of files hash. + // Allowing the serializer to handle Dictionary + // will fail to match. + var filesAsJsonObject = new JsonObject(); + foreach(var kvp in newGist.Files) + { + filesAsJsonObject.Add(kvp.Key, new { Content = kvp.Value }); + } + + var gist = new { + Description = newGist.Description, + Public = newGist.Public, + Files = filesAsJsonObject + }; + + return ApiConnection.Post(ApiUrls.Gist(), gist); + } + + /// + /// Creates a fork of a gist + /// + /// + /// http://developer.github.com/v3/gists/#fork-a-gist + /// + /// The id of the gist to fork + public Task Fork(string id) + { + return ApiConnection.Post(ApiUrls.ForkGist(id), new object()); + } + + /// + /// Deletes a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + public Task Delete(string id) + { + Ensure.ArgumentNotNull(id, "id"); + + return ApiConnection.Delete(ApiUrls.Gist(id)); + } + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + public Task> GetAll() + { + return ApiConnection.GetAll(ApiUrls.Gist()); + } + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + public Task> GetAll(DateTimeOffset since) + { + var request = new GistRequest(since); + return ApiConnection.GetAll(ApiUrls.Gist(), request.ToParametersDictionary()); + } + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + public Task> GetAllPublic() + { + return ApiConnection.GetAll(ApiUrls.PublicGists()); + } + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + public Task> GetAllPublic(DateTimeOffset since) + { + var request = new GistRequest(since); + return ApiConnection.GetAll(ApiUrls.PublicGists(), request.ToParametersDictionary()); + } + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + public Task> GetAllStarred() + { + return ApiConnection.GetAll(ApiUrls.StarredGists()); + } + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + public Task> GetAllStarred(DateTimeOffset since) + { + var request = new GistRequest(since); + return ApiConnection.GetAll(ApiUrls.StarredGists(), request.ToParametersDictionary()); + } + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + public Task> GetAllForUser(string user) + { + Ensure.ArgumentNotNull(user, "user"); + + return ApiConnection.GetAll(ApiUrls.UsersGists(user)); + } + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + /// Only gists updated at or after this time are returned + public Task> GetAllForUser(string user, DateTimeOffset since) + { + Ensure.ArgumentNotNull(user, "user"); + + var request = new GistRequest(since); + return ApiConnection.GetAll(ApiUrls.UsersGists(user), request.ToParametersDictionary()); + } + + /// + /// Edits a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + /// The update to the gist + public Task Edit(string id, GistUpdate gistUpdate) + { + Ensure.ArgumentNotNull(id, "id"); + Ensure.ArgumentNotNull(gistUpdate, "gistUpdate"); + + var filesAsJsonObject = new JsonObject(); + foreach (var kvp in gistUpdate.Files) + { + filesAsJsonObject.Add(kvp.Key, new { Content = kvp.Value.Content, Filename = kvp.Value.NewFileName }); + } + + var gist = new + { + Description = gistUpdate.Description, + Files = filesAsJsonObject + }; + + return ApiConnection.Patch(ApiUrls.Gist(id), gist); + } + + /// + /// Stars a gist + /// + /// + /// http://developer.github.com/v3/gists/#star-a-gist + /// + /// The id of the gist + public Task Star(string id) + { + return ApiConnection.Put(ApiUrls.StarGist(id)); + } + + /// + /// Unstars a gist + /// + /// + /// http://developer.github.com/v3/gists/#unstar-a-gist + /// + /// The id of the gist + public Task Unstar(string id) + { + return ApiConnection.Delete(ApiUrls.StarGist(id)); + } + + /// + /// Checks if the gist is starred + /// + /// + /// http://developer.github.com/v3/gists/#check-if-a-gist-is-starred + /// + /// The id of the gist + public async Task IsStarred(string id) + { + Ensure.ArgumentNotNullOrEmptyString(id, "id"); + + try + { + var response = await Connection.GetAsync(ApiUrls.StarGist(id), null, null) + .ConfigureAwait(false); + if (response.StatusCode != HttpStatusCode.NotFound && response.StatusCode != HttpStatusCode.NoContent) + { + throw new ApiException("Invalid Status Code returned. Expected a 204 or a 404", response.StatusCode); + } + return response.StatusCode == HttpStatusCode.NoContent; + } + catch (NotFoundException) + { + return false; + } + } } } \ No newline at end of file diff --git a/Octokit/Clients/IGistsClient.cs b/Octokit/Clients/IGistsClient.cs index 3c1787a9..9ffdfbb5 100644 --- a/Octokit/Clients/IGistsClient.cs +++ b/Octokit/Clients/IGistsClient.cs @@ -1,4 +1,6 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit @@ -23,5 +25,142 @@ namespace Octokit [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "Method makes a network request")] Task Get(string id); + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + Task> GetAll(); + + /// + /// List the authenticated user’s gists or if called anonymously, + /// this will return all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + Task> GetAll(DateTimeOffset since); + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + Task> GetAllPublic(); + + /// + /// Lists all public gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + Task> GetAllPublic(DateTimeOffset since); + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + Task> GetAllStarred(); + + /// + /// List the authenticated user’s starred gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// Only gists updated at or after this time are returned + Task> GetAllStarred(DateTimeOffset since); + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + Task> GetAllForUser(string user); + + /// + /// List a user's gists + /// + /// + /// http://developer.github.com/v3/gists/#list-gists + /// + /// The user + /// Only gists updated at or after this time are returned + Task> GetAllForUser(string user, DateTimeOffset since); + + /// + /// Creates a new gist + /// + /// + /// http://developer.github.com/v3/gists/#create-a-gist + /// + /// The new gist to create + Task Create(NewGist newGist); + + /// + /// Creates a fork of a gist + /// + /// + /// http://developer.github.com/v3/gists/#fork-a-gist + /// + /// The id of the gist to fork + Task Fork(string id); + + /// + /// Edits a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + /// The update to the gist + Task Edit(string id, GistUpdate gistUpdate); + + /// + /// Deletes a gist + /// + /// + /// http://developer.github.com/v3/gists/#delete-a-gist + /// + /// The id of the gist + Task Delete(string id); + + /// + /// Stars a gist + /// + /// + /// http://developer.github.com/v3/gists/#star-a-gist + /// + /// The id of the gist + Task Star(string id); + + /// + /// Unstars a gist + /// + /// + /// http://developer.github.com/v3/gists/#unstar-a-gist + /// + /// The id of the gist + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unstar")] + Task Unstar(string id); + + /// + /// Checks if the gist is starred + /// + /// + /// http://developer.github.com/v3/gists/#check-if-a-gist-is-starred + /// + /// The id of the gist + Task IsStarred(string id); } } \ No newline at end of file diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index d7dd4a54..5956d371 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -605,6 +605,14 @@ namespace Octokit return "feeds".FormatUri(); } + /// + /// Returns the that returns the list of public gists. + /// + public static Uri Gist() + { + return "gists".FormatUri(); + } + /// /// Returns the for the specified commit. /// @@ -614,6 +622,31 @@ namespace Octokit return "gists/{0}".FormatUri(id); } + public static Uri ForkGist(string id) + { + return "gists/{0}/forks".FormatUri(id); + } + + public static Uri PublicGists() + { + return "gists/public".FormatUri(); + } + + public static Uri StarredGists() + { + return "gists/starred".FormatUri(); + } + + public static Uri UsersGists(string user) + { + return "users/{0}/gists".FormatUri(user); + } + + public static Uri StarGist(string id) + { + return "gists/{0}/star".FormatUri(id); + } + /// /// Returns the for the comments for the specified gist. /// diff --git a/Octokit/Models/Request/GistRequest.cs b/Octokit/Models/Request/GistRequest.cs new file mode 100644 index 00000000..86989c94 --- /dev/null +++ b/Octokit/Models/Request/GistRequest.cs @@ -0,0 +1,25 @@ +using System; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class GistRequest : RequestParameters + { + public GistRequest(DateTimeOffset since) + { + Since = since; + } + + public DateTimeOffset Since { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Since: {0}", Since); + } + } + } +} diff --git a/Octokit/Models/Request/GistUpdate.cs b/Octokit/Models/Request/GistUpdate.cs new file mode 100644 index 00000000..c16fc488 --- /dev/null +++ b/Octokit/Models/Request/GistUpdate.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class GistUpdate + { + public GistUpdate() + { + Files = new Dictionary(); + } + + public string Description { get; set; } + public IDictionary Files { get; private set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Description: {0}", Description); + } + } + } + + public class GistFileUpdate + { + public string NewFileName { get; set; } + public string Content { get; set; } + } +} diff --git a/Octokit/Models/Request/NewGist.cs b/Octokit/Models/Request/NewGist.cs new file mode 100644 index 00000000..71b7fad4 --- /dev/null +++ b/Octokit/Models/Request/NewGist.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; +using System; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewGist + { + public NewGist() + { + Files = new Dictionary(); + } + + /// + /// The description of the gist. + /// + public string Description { get; set; } + + /// + /// Indicates whether the gist is public + /// + public bool Public { get; set; } + + /// + /// Files that make up this gist using the key as Filename + /// and value as Content + /// + public IDictionary Files { get; private set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Description: {0}", Description); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 62434eae..a8b6e175 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -89,12 +89,15 @@ + + + diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 2f28263d..30fc8b52 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -308,6 +308,9 @@ + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 96608bc0..e75a3941 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -303,6 +303,9 @@ + + + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 09841236..c8803836 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -166,6 +166,8 @@ + + @@ -176,6 +178,7 @@ + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 5d0559fc..e672a525 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -99,6 +99,9 @@ + + +