diff --git a/Octokit.Reactive/Clients/IObservableUserEmailsClient.cs b/Octokit.Reactive/Clients/IObservableUserEmailsClient.cs
new file mode 100644
index 0000000000..95f67d9e95
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableUserEmailsClient.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+
+namespace Octokit.Reactive
+{
+ ///
+ /// A client for GitHub's User Emails API.
+ ///
+ ///
+ /// See the User Emails API documentation for more information.
+ ///
+ public interface IObservableUserEmailsClient
+ {
+ ///
+ /// Gets all email addresses for the authenticated user.
+ ///
+ ///
+ /// http://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user
+ ///
+ /// The es for the authenticated user.
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
+ IObservable GetAll();
+
+ ///
+ /// Adds email addresses for the authenticated user.
+ ///
+ ///
+ /// http://developer.github.com/v3/users/emails/#add-email-addresses
+ ///
+ /// The email addresses to add.
+ /// Returns the added es.
+ IObservable Add(params string[] emailAddresses);
+ }
+}
diff --git a/Octokit.Reactive/Clients/IObservableUsersClient.cs b/Octokit.Reactive/Clients/IObservableUsersClient.cs
index ef319da01d..465739a2ad 100644
--- a/Octokit.Reactive/Clients/IObservableUsersClient.cs
+++ b/Octokit.Reactive/Clients/IObservableUsersClient.cs
@@ -27,12 +27,5 @@ public interface IObservableUsersClient
/// Thrown if the client is not authenticated.
/// A
IObservable Update(UserUpdate user);
-
- ///
- /// Returns emails for the current user.
- ///
- ///
- [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- IObservable GetEmails();
}
}
diff --git a/Octokit.Reactive/Clients/ObservableUserEmailsClient.cs b/Octokit.Reactive/Clients/ObservableUserEmailsClient.cs
new file mode 100644
index 0000000000..c50410aa29
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableUserEmailsClient.cs
@@ -0,0 +1,31 @@
+using Octokit.Reactive.Internal;
+using System;
+using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
+
+namespace Octokit.Reactive
+{
+ public class ObservableUserEmailsClient : IObservableUserEmailsClient
+ {
+ readonly IUserEmailsClient _client;
+ readonly IConnection _connection;
+
+ public ObservableUserEmailsClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, "client");
+
+ _client = client.User.Email;
+ _connection = client.Connection;
+ }
+
+ public IObservable GetAll()
+ {
+ return _connection.GetAndFlattenAllPages(ApiUrls.Emails());
+ }
+
+ public IObservable Add(params string[] emailAddresses)
+ {
+ return _client.Add(emailAddresses).ToObservable().SelectMany(a => a);
+ }
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableUsersClient.cs b/Octokit.Reactive/Clients/ObservableUsersClient.cs
index 5588e7376c..1648d8cc1d 100644
--- a/Octokit.Reactive/Clients/ObservableUsersClient.cs
+++ b/Octokit.Reactive/Clients/ObservableUsersClient.cs
@@ -1,20 +1,17 @@
using System;
using System.Reactive.Threading.Tasks;
-using Octokit.Reactive.Internal;
namespace Octokit.Reactive
{
public class ObservableUsersClient : IObservableUsersClient
{
readonly IUsersClient _client;
- readonly IConnection _connection;
public ObservableUsersClient(IGitHubClient client)
{
Ensure.ArgumentNotNull(client, "client");
_client = client.User;
- _connection = client.Connection;
}
///
@@ -50,14 +47,5 @@ public IObservable Update(UserUpdate user)
return _client.Update(user).ToObservable();
}
-
- ///
- /// Returns emails for the current user.
- ///
- ///
- public IObservable GetEmails()
- {
- return _connection.GetAndFlattenAllPages(ApiUrls.Emails());
- }
}
}
diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj
index 2f21b5e66a..c3dfc8ca03 100644
--- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj
@@ -122,6 +122,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
index cd6ab187ea..82cdcebb68 100644
--- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
@@ -131,6 +131,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
index 0f441e351f..d3e3504590 100644
--- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
@@ -126,6 +126,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj
index 6c5c7e71fc..f66a07f170 100644
--- a/Octokit.Reactive/Octokit.Reactive.csproj
+++ b/Octokit.Reactive/Octokit.Reactive.csproj
@@ -73,6 +73,7 @@
Properties\SolutionInfo.cs
+
@@ -122,6 +123,7 @@
+
diff --git a/Octokit.Tests.Integration/Clients/UserEmailsClientTests.cs b/Octokit.Tests.Integration/Clients/UserEmailsClientTests.cs
new file mode 100644
index 0000000000..347c1c9e36
--- /dev/null
+++ b/Octokit.Tests.Integration/Clients/UserEmailsClientTests.cs
@@ -0,0 +1,21 @@
+using System.Net.Http.Headers;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Integration.Clients
+{
+ public class UserEmailsClientTests
+ {
+ [IntegrationTest]
+ public async Task CanGetEmail()
+ {
+ var github = new GitHubClient(new ProductHeaderValue("OctokitTests"))
+ {
+ Credentials = Helper.Credentials
+ };
+
+ var emails = await github.User.Email.GetAll();
+ Assert.NotEmpty(emails);
+ }
+ }
+}
diff --git a/Octokit.Tests.Integration/Clients/UsersClientTests.cs b/Octokit.Tests.Integration/Clients/UsersClientTests.cs
index 23de66ecfa..c4e1bfd288 100644
--- a/Octokit.Tests.Integration/Clients/UsersClientTests.cs
+++ b/Octokit.Tests.Integration/Clients/UsersClientTests.cs
@@ -99,22 +99,4 @@ public async Task FailsWhenAuthenticatedWithBadCredentials()
Assert.Equal(HttpStatusCode.Unauthorized, e.StatusCode);
}
}
-
- public class TheGetEmailsMethod
- {
- [IntegrationTest]
- public async Task RetrievesEmailsForUser()
- {
- var github = new GitHubClient(new ProductHeaderValue("OctokitTests"))
- {
- Credentials = Helper.Credentials
- };
-
- var emails = await github.User.GetEmails();
-
- Assert.NotEmpty(emails);
- var email = emails.First();
- Assert.True(email.Primary);
- }
- }
}
diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
index 9587edf948..89dad30065 100644
--- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
+++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj
@@ -69,6 +69,7 @@
+
@@ -81,6 +82,7 @@
+
diff --git a/Octokit.Tests.Integration/Reactive/ObservableUserEmailsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableUserEmailsClientTests.cs
new file mode 100644
index 0000000000..fcb527b7c2
--- /dev/null
+++ b/Octokit.Tests.Integration/Reactive/ObservableUserEmailsClientTests.cs
@@ -0,0 +1,24 @@
+using Octokit.Reactive;
+using System.Net.Http.Headers;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Integration
+{
+ public class ObservableUserEmailsClientTests
+ {
+ [IntegrationTest]
+ public async Task CanGetEmail()
+ {
+ var github = new GitHubClient(new ProductHeaderValue("OctokitTests"))
+ {
+ Credentials = Helper.Credentials
+ };
+ var client = new ObservableUserEmailsClient(github);
+
+ var email = await client.GetAll();
+ Assert.NotNull(email);
+ }
+ }
+}
diff --git a/Octokit.Tests/Clients/UserEmailsClientTests.cs b/Octokit.Tests/Clients/UserEmailsClientTests.cs
new file mode 100644
index 0000000000..e699bc8a47
--- /dev/null
+++ b/Octokit.Tests/Clients/UserEmailsClientTests.cs
@@ -0,0 +1,66 @@
+using NSubstitute;
+using Octokit.Tests.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Octokit.Tests.Clients
+{
+ public class UserEmailsClientTests
+ {
+ public class TheGetAllMethod
+ {
+ [Fact]
+ public void GetsCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new UserEmailsClient(connection);
+
+ client.GetAll();
+
+ connection.Received(1)
+ .GetAll(Arg.Is(u => u.ToString() == "user/emails"));
+ }
+ }
+
+ public class TheAddMethod
+ {
+ [Fact]
+ public void PostsToCorrectUrl()
+ {
+ var connection = Substitute.For();
+ var client = new UserEmailsClient(connection);
+
+ client.Add("octocat@github.com");
+
+ connection.Received(1)
+ .Post>(Arg.Is(u => u.ToString() == "user/emails"), Arg.Any());
+ }
+
+ [Fact]
+ public void EnsuresNonNullArgument()
+ {
+ var client = new UserEmailsClient(Substitute.For());
+ Assert.Throws(() => client.Add(null));
+ }
+
+ [Fact]
+ public void EnsuresNoNullEmails()
+ {
+ var client = new UserEmailsClient(Substitute.For());
+ Assert.Throws(() => client.Add("octokit@github.com", null));
+ }
+ }
+
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresArguments()
+ {
+ Assert.Throws(
+ () => new UserEmailsClient(null));
+ }
+ }
+ }
+}
diff --git a/Octokit.Tests/Clients/UsersClientTests.cs b/Octokit.Tests/Clients/UsersClientTests.cs
index dcdc85de0f..783c49eb49 100644
--- a/Octokit.Tests/Clients/UsersClientTests.cs
+++ b/Octokit.Tests/Clients/UsersClientTests.cs
@@ -90,20 +90,5 @@ public async Task EnsuresArgumentsNotNull()
await AssertEx.Throws(() => userEndpoint.Update(null));
}
}
-
- public class TheGetEmailsMethod
- {
- [Fact]
- public void SendsUpdateToCorrectUrl()
- {
- var endpoint = new Uri("user/emails", UriKind.Relative);
- var client = Substitute.For();
- var usersClient = new UsersClient(client);
-
- usersClient.GetEmails();
-
- client.Received().GetAll(endpoint, null);
- }
- }
}
}
diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj
index 28ad4e8c0c..93e91ef64a 100644
--- a/Octokit.Tests/Octokit.Tests.csproj
+++ b/Octokit.Tests/Octokit.Tests.csproj
@@ -86,6 +86,7 @@
+
@@ -139,6 +140,7 @@
+
diff --git a/Octokit.Tests/Reactive/ObservableUserEmailsClientTests.cs b/Octokit.Tests/Reactive/ObservableUserEmailsClientTests.cs
new file mode 100644
index 0000000000..49ea1e8f81
--- /dev/null
+++ b/Octokit.Tests/Reactive/ObservableUserEmailsClientTests.cs
@@ -0,0 +1,81 @@
+using NSubstitute;
+using Octokit.Reactive;
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+namespace Octokit.Tests
+{
+ public class ObservableUserEmailsClientTests
+ {
+ private static ObservableUserEmailsClient CreateFixtureWithNonReactiveClient()
+ {
+ var nonreactiveClient = new UserEmailsClient(Substitute.For());
+ var github = Substitute.For();
+ github.User.Email.Returns(nonreactiveClient);
+ return new ObservableUserEmailsClient(github);
+ }
+
+ public class TheGetAllMethod
+ {
+ [Fact]
+ public void GetsCorrectUrl()
+ {
+ var expectedUri = new Uri("user/emails", UriKind.Relative);
+ var github = Substitute.For();
+ var client = new ObservableUserEmailsClient(github);
+
+ client.GetAll();
+
+ github.Connection.Received(1).GetAsync>(expectedUri);
+ }
+ }
+
+ public class TheAddMethod
+ {
+ public IGitHubClient GitHubClient;
+
+ public ObservableUserEmailsClient Client;
+
+ [Fact]
+ public void CallsAddOnClient()
+ {
+ var github = Substitute.For();
+ var client = new ObservableUserEmailsClient(github);
+ string email = "octo@github.com";
+
+ client.Add(email);
+
+ github.User.Email.Received(1).Add(Arg.Is(email));
+ }
+
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ var client = CreateFixtureWithNonReactiveClient();
+
+ Assert.Throws(() => client.Add(null));
+ Assert.Throws(() => client.Add("octo@github.com", null));
+ }
+
+ [Fact]
+ public void EnsuresNonEmptyArguments()
+ {
+ var client = CreateFixtureWithNonReactiveClient();
+
+ Assert.Throws(() => client.Add(""));
+ Assert.Throws(() => client.Add("octo@github.com", ""));
+ }
+ }
+
+ public class TheCtor
+ {
+ [Fact]
+ public void EnsuresNonNullArguments()
+ {
+ Assert.Throws(
+ () => new ObservableUserEmailsClient(null));
+ }
+ }
+ }
+}
diff --git a/Octokit/Clients/IUserEmailsClient.cs b/Octokit/Clients/IUserEmailsClient.cs
new file mode 100644
index 0000000000..9af896e31f
--- /dev/null
+++ b/Octokit/Clients/IUserEmailsClient.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+
+namespace Octokit
+{
+ ///
+ /// A client for GitHub's User Emails API.
+ ///
+ ///
+ /// See the User Emails API documentation for more information.
+ ///
+ public interface IUserEmailsClient
+ {
+ ///
+ /// Gets all email addresses for the authenticated user.
+ ///
+ ///
+ /// http://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user
+ ///
+ /// The es for the authenticated user.
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
+ Task> GetAll();
+
+ ///
+ /// Adds email addresses for the authenticated user.
+ ///
+ ///
+ /// http://developer.github.com/v3/users/emails/#add-email-addresses
+ ///
+ /// The email addresses to add.
+ /// Returns the added es.
+ Task> Add(params string[] emailAddresses);
+ }
+}
diff --git a/Octokit/Clients/IUsersClient.cs b/Octokit/Clients/IUsersClient.cs
index eddc0039ae..74762df1c6 100644
--- a/Octokit/Clients/IUsersClient.cs
+++ b/Octokit/Clients/IUsersClient.cs
@@ -12,6 +12,8 @@ namespace Octokit
///
public interface IUsersClient
{
+ IUserEmailsClient Email { get; }
+
///
/// Returns the user specified by the login.
///
@@ -35,13 +37,6 @@ public interface IUsersClient
/// A
Task Update(UserUpdate user);
- ///
- /// Returns emails for the current user.
- ///
- ///
- [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- Task> GetEmails();
-
///
/// A client for GitHub's User Followers API
///
diff --git a/Octokit/Clients/UserEmailsClient.cs b/Octokit/Clients/UserEmailsClient.cs
new file mode 100644
index 0000000000..a5a23629b5
--- /dev/null
+++ b/Octokit/Clients/UserEmailsClient.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Octokit
+{
+ ///
+ /// A client for GitHub's User Emails API.
+ ///
+ ///
+ /// See the User Emails API documentation for more information.
+ ///
+ public class UserEmailsClient : ApiClient, IUserEmailsClient
+ {
+ ///
+ /// Instantiates a new GitHub User Emails API client.
+ ///
+ /// An API connection
+ public UserEmailsClient(IApiConnection apiConnection)
+ : base(apiConnection)
+ { }
+
+ ///
+ /// Gets all email addresses for the authenticated user.
+ ///
+ ///
+ /// http://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user
+ ///
+ /// The es for the authenticated user.
+ public Task> GetAll()
+ {
+ return ApiConnection.GetAll(ApiUrls.Emails());
+ }
+
+ ///
+ /// Adds email addresses for the authenticated user.
+ ///
+ ///
+ /// http://developer.github.com/v3/users/emails/#add-email-addresses
+ ///
+ /// The email addresses to add.
+ /// Returns the added es.
+ public Task> Add(params string[] emailAddresses)
+ {
+ Ensure.ArgumentNotNull(emailAddresses, "emailAddresses");
+ if (emailAddresses.Any(String.IsNullOrWhiteSpace))
+ throw new ArgumentException("Cannot contain null, empty or whitespace values", "emailAddresses");
+
+ return ApiConnection.Post>(ApiUrls.Emails(), emailAddresses);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Octokit/Clients/UsersClient.cs b/Octokit/Clients/UsersClient.cs
index c68ece71f5..55cdd384e8 100644
--- a/Octokit/Clients/UsersClient.cs
+++ b/Octokit/Clients/UsersClient.cs
@@ -23,9 +23,12 @@ public class UsersClient : ApiClient, IUsersClient
/// An API connection
public UsersClient(IApiConnection apiConnection) : base(apiConnection)
{
+ Email = new UserEmailsClient(apiConnection);
Followers = new FollowersClient(apiConnection);
}
+ public IUserEmailsClient Email { get; private set; }
+
///
/// Returns the user specified by the login.
///
@@ -61,15 +64,6 @@ public Task Update(UserUpdate user)
return ApiConnection.Patch(_userEndpoint, user);
}
- ///
- /// Returns emails for the current user.
- ///
- ///
- public Task> GetEmails()
- {
- return ApiConnection.GetAll(ApiUrls.Emails(), null);
- }
-
///
/// A client for GitHub's User Followers API
///
diff --git a/Octokit/Models/Response/EmailAddress.cs b/Octokit/Models/Response/EmailAddress.cs
index 50e88d9dae..fa4e0b31ad 100644
--- a/Octokit/Models/Response/EmailAddress.cs
+++ b/Octokit/Models/Response/EmailAddress.cs
@@ -1,11 +1,40 @@
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+
namespace Octokit
{
+ ///
+ /// A users email
+ ///
+ [DebuggerDisplay("DebuggerDisplay,nq")]
public class EmailAddress
{
+ ///
+ /// The email address
+ ///
public string Email { get; set; }
+ ///
+ /// true if the email is verified; otherwise false
+ ///
public bool Verified { get; set; }
+ ///
+ /// true if this is the users primary email; otherwise false
+ ///
public bool Primary { get; set; }
+
+ [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
+ Justification="Used by DebuggerDisplayAttribute")]
+ private string DebuggerDisplay
+ {
+ get
+ {
+ return String.Format(CultureInfo.InvariantCulture,
+ "EmailAddress: Email: {0}; Primary: {1}, Verified: {2}", Email, Primary, Verified);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj
index 44aff67cb9..920e4a8dc3 100644
--- a/Octokit/Octokit-Mono.csproj
+++ b/Octokit/Octokit-Mono.csproj
@@ -252,6 +252,8 @@
+
+
diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj
index e2adfa432a..3f8356fcf6 100644
--- a/Octokit/Octokit-MonoAndroid.csproj
+++ b/Octokit/Octokit-MonoAndroid.csproj
@@ -258,6 +258,8 @@
+
+
diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj
index 3728fac7fe..75d85a12f2 100644
--- a/Octokit/Octokit-Monotouch.csproj
+++ b/Octokit/Octokit-Monotouch.csproj
@@ -253,6 +253,8 @@
+
+
diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj
index e59d2c0bf7..01b1ba2f1d 100644
--- a/Octokit/Octokit-netcore45.csproj
+++ b/Octokit/Octokit-netcore45.csproj
@@ -253,6 +253,8 @@
+
+
diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj
index 43c8793826..fcb0616040 100644
--- a/Octokit/Octokit.csproj
+++ b/Octokit/Octokit.csproj
@@ -54,6 +54,8 @@
Properties\SolutionInfo.cs
+
+