Skip to content

Commit

Permalink
Merge pull request #343 from alfhenrik/user-followers-api
Browse files Browse the repository at this point in the history
Implement User Followers API
  • Loading branch information
haacked committed Feb 2, 2014
2 parents 955c680 + 0965696 commit 5eebdfa
Show file tree
Hide file tree
Showing 21 changed files with 1,161 additions and 0 deletions.
96 changes: 96 additions & 0 deletions Octokit.Reactive/Clients/IObservableFollowersClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reactive;
using System.Text;
using System.Threading.Tasks;

namespace Octokit.Reactive
{
public interface IObservableFollowersClient
{
/// <summary>
/// List the authenticated user’s followers
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-followers-of-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that follow the authenticated user.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<User> GetAllForCurrent();

/// <summary>
/// List a user’s followers
/// </summary>
/// <param name="login">The login name for the user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-followers-of-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that follow the passed user.</returns>
IObservable<User> GetAll(string login);

/// <summary>
/// List who the authenticated user is following
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-users-followed-by-another-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that the authenticated user follows.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IObservable<User> GetFollowingForCurrent();

/// <summary>
/// List who a user is following
/// </summary>
/// <param name="login">The login name of the user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-users-followed-by-another-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that the passed user follows.</returns>
IObservable<User> GetFollowing(string login);

/// <summary>
/// Check if the authenticated user follows another user
/// </summary>
/// <param name="following">The login name of the other user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <c>bool</c> representing the success of the operation.</returns>
IObservable<bool> IsFollowingForCurrent(string following);

/// <summary>
/// Check if one user follows another user
/// </summary>
/// <param name="login">The login name of the user</param>
/// <param name="following">The login name of the other user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#check-if-one-user-follows-another">API documentation</a> for more information.
/// </remarks>
/// <returns>A <c>bool</c> representing the success of the operation.</returns>
IObservable<bool> IsFollowing(string login, string following);

/// <summary>
/// Follow a user
/// </summary>
/// <param name="login">The login name of the user to follow</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#follow-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <c>bool</c> representing the success of the operation.</returns>
IObservable<bool> Follow(string login);

/// <summary>
/// Unfollow a user
/// </summary>
/// <param name="login">The login name of the user to unfollow</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#unfollow-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns></returns>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unfollow",
Justification = "Unfollow is consistent with the GitHub website")]
IObservable<Unit> Unfollow(string login);
}
}
141 changes: 141 additions & 0 deletions Octokit.Reactive/Clients/ObservableFollowersClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using System;
using System.Reactive;
using System.Reactive.Threading.Tasks;
using Octokit.Reactive.Internal;

namespace Octokit.Reactive
{
public class ObservableFollowersClient : IObservableFollowersClient
{
readonly IFollowersClient _client;
readonly IConnection _connection;

/// <summary>
/// Initializes a new User Followers API client.
/// </summary>
/// <param name="client">An <see cref="IGitHubClient" /> used to make the requests</param>
public ObservableFollowersClient(IGitHubClient client)
{
Ensure.ArgumentNotNull(client, "client");

_client = client.User.Followers;
_connection = client.Connection;
}

/// <summary>
/// List the authenticated user’s followers
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-followers-of-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that follow the authenticated user.</returns>
public IObservable<User> GetAllForCurrent()
{
return _connection.GetAndFlattenAllPages<User>(ApiUrls.Followers());
}

/// <summary>
/// List a user’s followers
/// </summary>
/// <param name="login">The login name for the user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-followers-of-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that follow the passed user.</returns>
public IObservable<User> GetAll(string login)
{
Ensure.ArgumentNotNullOrEmptyString(login, "login");

return _connection.GetAndFlattenAllPages<User>(ApiUrls.Followers(login));
}

/// <summary>
/// List who the authenticated user is following
/// </summary>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-users-followed-by-another-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that the authenticated user follows.</returns>
public IObservable<User> GetFollowingForCurrent()
{
return _connection.GetAndFlattenAllPages<User>(ApiUrls.Following());
}

/// <summary>
/// List who a user is following
/// </summary>
/// <param name="login">The login name of the user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#list-users-followed-by-another-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <see cref="IReadOnlyList{User}"/> of <see cref="User"/>s that the passed user follows.</returns>
public IObservable<User> GetFollowing(string login)
{
Ensure.ArgumentNotNullOrEmptyString(login, "login");

return _connection.GetAndFlattenAllPages<User>(ApiUrls.Following(login));
}

/// <summary>
/// Check if the authenticated user follows another user
/// </summary>
/// <param name="following">The login name of the other user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <c>bool</c> representing the success of the operation.</returns>
public IObservable<bool> IsFollowingForCurrent(string following)
{
Ensure.ArgumentNotNullOrEmptyString(following, "following");

return _client.IsFollowingForCurrent(following).ToObservable();
}

/// <summary>
/// Check if one user follows another user
/// </summary>
/// <param name="login">The login name of the user</param>
/// <param name="following">The login name of the other user</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#check-if-one-user-follows-another">API documentation</a> for more information.
/// </remarks>
/// <returns>A <c>bool</c> representing the success of the operation.</returns>
public IObservable<bool> IsFollowing(string login, string following)
{
Ensure.ArgumentNotNullOrEmptyString(login, "login");
Ensure.ArgumentNotNullOrEmptyString(following, "following");

return _client.IsFollowing(login, following).ToObservable();
}

/// <summary>
/// Follow a user
/// </summary>
/// <param name="login">The login name of the user to follow</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#follow-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns>A <c>bool</c> representing the success of the operation.</returns>
public IObservable<bool> Follow(string login)
{
Ensure.ArgumentNotNullOrEmptyString(login, "login");

return _client.Follow(login).ToObservable();
}

/// <summary>
/// Unfollow a user
/// </summary>
/// <param name="login">The login name of the user to unfollow</param>
/// <remarks>
/// See the <a href="http://developer.github.com/v3/users/followers/#unfollow-a-user">API documentation</a> for more information.
/// </remarks>
/// <returns></returns>
public IObservable<System.Reactive.Unit> Unfollow(string login)
{
Ensure.ArgumentNotNullOrEmptyString(login, "login");

return _client.Unfollow(login).ToObservable();
}
}
}
2 changes: 2 additions & 0 deletions Octokit.Reactive/Octokit.Reactive-Mono.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
<Compile Include="Clients\ObservableSearchClient.cs" />
<Compile Include="Clients\IObservableWatchedClient.cs" />
<Compile Include="Clients\ObservableWatchedClient.cs" />
<Compile Include="Clients\IObservableFollowersClient.cs" />
<Compile Include="Clients\ObservableFollowersClient.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
<Compile Include="Clients\ObservableSearchClient.cs" />
<Compile Include="Clients\IObservableWatchedClient.cs" />
<Compile Include="Clients\ObservableWatchedClient.cs" />
<Compile Include="Clients\IObservableFollowersClient.cs" />
<Compile Include="Clients\ObservableFollowersClient.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@
<Compile Include="Clients\ObservableSearchClient.cs" />
<Compile Include="Clients\IObservableWatchedClient.cs" />
<Compile Include="Clients\ObservableWatchedClient.cs" />
<Compile Include="Clients\IObservableFollowersClient.cs" />
<Compile Include="Clients\ObservableFollowersClient.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions Octokit.Reactive/Octokit.Reactive.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<Link>Properties\SolutionInfo.cs</Link>
</Compile>
<Compile Include="Clients\IObservableWatchedClient.cs" />
<Compile Include="Clients\IObservableFollowersClient.cs" />
<Compile Include="Clients\ObservableSearchClient.cs" />
<Compile Include="Clients\IObservableBlobClient.cs" />
<Compile Include="Clients\IObservableGistCommentsClient.cs" />
Expand Down Expand Up @@ -120,6 +121,7 @@
<Compile Include="Clients\ObservableStarredClient.cs" />
<Compile Include="Clients\ObservableTagsClient.cs" />
<Compile Include="Clients\ObservableTreesClient.cs" />
<Compile Include="Clients\ObservableFollowersClient.cs" />
<Compile Include="Clients\ObservableUsersClient.cs" />
<Compile Include="Clients\IObservableAssigneesClient.cs" />
<Compile Include="Clients\IObservableNotificationsClient.cs" />
Expand Down
110 changes: 110 additions & 0 deletions Octokit.Tests.Integration/Clients/FollowersClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Octokit;
using Octokit.Tests.Integration;
using Xunit;

public class FollowersClientTests : IDisposable
{
readonly GitHubClient _github;
readonly User _currentUser;

public FollowersClientTests()
{
_github = new GitHubClient(new ProductHeaderValue("OctokitTests"))
{
Credentials = Helper.Credentials
};
_currentUser = _github.User.Current().Result;
}

[IntegrationTest]
public async Task ReturnsUsersTheCurrentUserIsFollowing()
{
await _github.User.Followers.Follow("alfhenrik");

var following = await _github.User.Followers.GetFollowingForCurrent();

Assert.NotNull(following);
Assert.True(following.Any(f => f.Login == "alfhenrik"));
}

[IntegrationTest]
public async Task ReturnsUsersTheUserIsFollowing()
{
var following = await _github.User.Followers.GetFollowing("alfhenrik");

Assert.NotNull(following);
Assert.NotEmpty(following);
}

[IntegrationTest]
public async Task ReturnsUsersFollowingTheUser()
{
await _github.User.Followers.Follow("alfhenrik");

var followers = await _github.User.Followers.GetAll("alfhenrik");

Assert.NotEmpty(followers);
Assert.True(followers.Any(f => f.Login == _currentUser.Login));
}

[IntegrationTest]
public async Task ChecksIfIsFollowingUserWhenFollowingUser()
{
await _github.User.Followers.Follow("alfhenrik");

var isFollowing = await _github.User.Followers.IsFollowingForCurrent("alfhenrik");

Assert.True(isFollowing);
}

[IntegrationTest]
public async Task ChecksIfIsFollowingUserWhenNotFollowingUser()
{
var isFollowing = await _github.User.Followers.IsFollowingForCurrent("alfhenrik");

Assert.False(isFollowing);
}

[IntegrationTest]
public async Task FollowUserNotBeingFollowedByTheUser()
{
var result = await _github.User.Followers.Follow("alfhenrik");
var following = await _github.User.Followers.GetFollowingForCurrent();

Assert.True(result);
Assert.NotEmpty(following);
Assert.True(following.Any(f => f.Login == "alfhenrik"));
}

[IntegrationTest]
public async Task UnfollowUserBeingFollowedByTheUser()
{
await _github.User.Followers.Follow("alfhenrik");
var followers = await _github.User.Followers.GetAll("alfhenrik");
Assert.True(followers.Any(f => f.Login == _currentUser.Login));

await _github.User.Followers.Unfollow("alfhenrik");
followers = await _github.User.Followers.GetAll("alfhenrik");
Assert.False(followers.Any(f => f.Login == _currentUser.Login));
}

[IntegrationTest]
public async Task UnfollowUserNotBeingFollowedTheUser()
{
var followers = await _github.User.Followers.GetAll("alfhenrik");
Assert.False(followers.Any(f => f.Login == _currentUser.Login));

await _github.User.Followers.Unfollow("alfhenrik");
}

public void Dispose()
{
_github.User.Followers.Unfollow("alfhenrik");
}
}
Loading

0 comments on commit 5eebdfa

Please sign in to comment.