diff --git a/Octokit.Reactive/Clients/IObservableUserAdministrationClient.cs b/Octokit.Reactive/Clients/IObservableUserAdministrationClient.cs index d893f91d8c..844a0e1598 100644 --- a/Octokit.Reactive/Clients/IObservableUserAdministrationClient.cs +++ b/Octokit.Reactive/Clients/IObservableUserAdministrationClient.cs @@ -5,7 +5,7 @@ namespace Octokit.Reactive { /// - /// A client for GitHub's User Administration API. + /// A client for GitHub's User Administration API (GitHub Enterprise) /// /// /// See the Administration API documentation for more details. @@ -13,43 +13,126 @@ namespace Octokit.Reactive public interface IObservableUserAdministrationClient { /// - /// Promotes ordinary user to a site administrator. + /// Create a new user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#promote-an-ordinary-user-to-a-site-administrator + /// See the API documentation + /// for more information. + /// + /// The object describing the user to create + /// The created object + IObservable Create(NewUser newUser); + + /// + /// Rename an existing user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// Note that this queues a request to rename a user, rather than execute it straight away + /// + /// The username to rename + /// The request, specifying the new login + /// A object indicating the queued task message and Url to the user + IObservable Rename(string login, UserRename userRename); + + /// + /// Create an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to impersonate + /// The request specifying the required scopes + /// An object containing the impersonation token + IObservable CreateImpersonationToken(string login, NewImpersonationToken newImpersonationToken); + + /// + /// Deletes an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to remove impersonation token from + /// + IObservable DeleteImpersonationToken(string login); + + /// + /// Promotes ordinary user to a site administrator (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. /// /// The user to promote to administrator. /// IObservable Promote(string login); /// - /// Demotes a site administrator to an ordinary user. + /// Demotes a site administrator to an ordinary user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#demote-a-site-administrator-to-an-ordinary-user + /// See the API documentation + /// for more information. /// /// The user to demote from administrator. /// IObservable Demote(string login); /// - /// Suspends a user. + /// Suspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#suspend-a-user + /// See the API documentation + /// for more information. /// /// The user to suspend. /// IObservable Suspend(string login); /// - /// Unsuspends a user. + /// Unsuspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#unsuspend-a-user + /// See the API documentation + /// for more information. /// /// The user to unsuspend. /// IObservable Unsuspend(string login); + + /// + /// List all public keys (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// + IObservable ListAllPublicKeys(); + + /// + /// Delete a user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to delete + /// + IObservable Delete(string login); + + /// + /// Delete a public key (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The key to delete + /// + IObservable DeletePublicKey(int keyId); } } diff --git a/Octokit.Reactive/Clients/ObservableUserAdministrationClient.cs b/Octokit.Reactive/Clients/ObservableUserAdministrationClient.cs index d76d7e9dad..bc0bf672e7 100644 --- a/Octokit.Reactive/Clients/ObservableUserAdministrationClient.cs +++ b/Octokit.Reactive/Clients/ObservableUserAdministrationClient.cs @@ -7,9 +7,16 @@ namespace Octokit.Reactive { + /// + /// A client for GitHub's User Administration API (GitHub Enterprise) + /// + /// + /// See the Administration API documentation for more details. + /// public class ObservableUserAdministrationClient : IObservableUserAdministrationClient { readonly IUserAdministrationClient _client; + readonly IConnection _connection; /// /// Initializes a new instance of the class. @@ -20,13 +27,74 @@ public ObservableUserAdministrationClient(IGitHubClient client) Ensure.ArgumentNotNull(client, "client"); _client = client.User.Administration; + _connection = client.Connection; } /// - /// Promotes ordinary user to a site administrator. + /// Create a new user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#promote-an-ordinary-user-to-a-site-administrator + /// See the API documentation + /// for more information. + /// + /// The object describing the user to create + /// The created object + public IObservable Create(NewUser newUser) + { + return _client.Create(newUser).ToObservable(); + } + + /// + /// Rename an existing user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// Note that this queues a request to rename a user, rather than execute it straight away + /// + /// The username to rename + /// The request, specifying the new login + /// A object indicating the queued task message and Url to the user + public IObservable Rename(string login, UserRename userRename) + { + return _client.Rename(login, userRename).ToObservable(); + } + + /// + /// Create an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to impersonate + /// The request specifying the required scopes + /// An object containing the impersonation token + public IObservable CreateImpersonationToken(string login, NewImpersonationToken newImpersonationToken) + { + return _client.CreateImpersonationToken(login, newImpersonationToken).ToObservable(); + } + + /// + /// Deletes an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to remove impersonation token from + /// + public IObservable DeleteImpersonationToken(string login) + { + return _client.DeleteImpersonationToken(login).ToObservable(); + } + + /// + /// Promotes ordinary user to a site administrator (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. /// /// The user to promote to administrator. /// @@ -36,10 +104,11 @@ public IObservable Promote(string login) } /// - /// Demotes a site administrator to an ordinary user. + /// Demotes a site administrator to an ordinary user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#demote-a-site-administrator-to-an-ordinary-user + /// See the API documentation + /// for more information. /// /// The user to demote from administrator. /// @@ -49,10 +118,11 @@ public IObservable Demote(string login) } /// - /// Suspends a user. + /// Suspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#suspend-a-user + /// See the API documentation + /// for more information. /// /// The user to suspend. /// @@ -62,10 +132,11 @@ public IObservable Suspend(string login) } /// - /// Unsuspends a user. + /// Unsuspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#unsuspend-a-user + /// See the API documentation + /// for more information. /// /// The user to unsuspend. /// @@ -73,5 +144,46 @@ public IObservable Unsuspend(string login) { return _client.Unsuspend(login).ToObservable(); } + + /// + /// List all public keys (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// + public IObservable ListAllPublicKeys() + { + return _connection.GetAndFlattenAllPages(ApiUrls.UserAdministrationPublicKeys()); + } + + /// + /// Delete a user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to delete + /// + public IObservable Delete(string login) + { + return _client.Delete(login).ToObservable(); + } + + /// + /// Delete a public key (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The key to delete + /// + public IObservable DeletePublicKey(int keyId) + { + return _client.DeletePublicKey(keyId).ToObservable(); + } } } diff --git a/Octokit.Tests.Integration/Clients/UserAdministrationClientTests.cs b/Octokit.Tests.Integration/Clients/UserAdministrationClientTests.cs new file mode 100644 index 0000000000..321017ac3d --- /dev/null +++ b/Octokit.Tests.Integration/Clients/UserAdministrationClientTests.cs @@ -0,0 +1,196 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Octokit.Tests.Integration.Helpers; +using Xunit; + +namespace Octokit.Tests.Integration.Clients +{ + public class UserAdministrationClientTests + { + readonly IGitHubClient _github; + + public UserAdministrationClientTests() + { + _github = EnterpriseHelper.GetAuthenticatedClient(); + } + + private NewUser GenerateNewUserDetails() + { + string username = Helper.MakeNameWithTimestamp("user"); + string email = string.Concat(username, "@company.com"); + return new NewUser(username, email); + } + + [GitHubEnterpriseTest] + public async Task CanCreateAndDelete() + { + User checkUser = null; + + // Create a new user + var newUser = GenerateNewUserDetails(); + + var user = await + _github.User.Administration.Create(newUser); + + // Check returned object (cant check email as it isn't public) + Assert.NotNull(user); + Assert.Equal(user.Login, newUser.Login); + + // Get user to check they exist + checkUser = await _github.User.Get(newUser.Login); + Assert.Equal(checkUser.Login, newUser.Login); + + // Delete the user + await _github.User.Administration.Delete(newUser.Login); + + // Ensure user doesnt exist + try + { + checkUser = await _github.User.Get(newUser.Login); + if (checkUser != null) + { + throw new Exception("User still exists!"); + } + } + catch (ApiException e) + { + if (e.StatusCode != System.Net.HttpStatusCode.NotFound) + { + throw; + } + } + } + + [GitHubEnterpriseTest] + public async Task CanRename() + { + string renamedUsername = Helper.MakeNameWithTimestamp("user-renamed"); + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + var response = await _github.User.Administration.Rename( + context.UserLogin, + new UserRename(renamedUsername)); + + Assert.NotNull(response); + Assert.StartsWith("Job queued to rename user", response.Message); + Assert.EndsWith(context.UserId.ToString(), response.Url); + } + + // Remove user if it was already renamed + EnterpriseHelper.DeleteUser(renamedUsername); + } + + [GitHubEnterpriseTest] + public async Task CanAddAndDeleteImpersonationToken() + { + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Create Impersonation token + var token = await _github.User.Administration.CreateImpersonationToken( + context.UserLogin, + new NewImpersonationToken(new string[] { "public_repo" })); + + Assert.NotNull(token); + Assert.True( + token.Scopes.Count() == 1 && + token.Scopes.All(s => s == "public_repo")); + + // Delete Impersonation token + await _github.User.Administration.DeleteImpersonationToken(context.UserLogin); + } + } + + [GitHubEnterpriseTest] + public async Task CanPromoteAndDemote() + { + User checkUser = null; + + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user is not site admin + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.SiteAdmin); + + // Promote to site admin + await _github.User.Administration.Promote(context.UserLogin); + + // Ensure user is site admin + checkUser = await _github.User.Get(context.UserLogin); + Assert.True(checkUser.SiteAdmin); + + // Demote user + await _github.User.Administration.Demote(context.UserLogin); + + // Ensure user is not site admin + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.SiteAdmin); + } + } + + [GitHubEnterpriseTest] + public async Task CanSuspendAndUnsuspend() + { + User checkUser = null; + + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user is not suspended + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.Suspended); + + // Suspend user + await _github.User.Administration.Suspend(context.UserLogin); + + // Ensure user is suspended + checkUser = await _github.User.Get(context.UserLogin); + Assert.True(checkUser.Suspended); + + // Unsuspend user + await _github.User.Administration.Unsuspend(context.UserLogin); + + // Ensure user is not suspended + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.Suspended); + } + } + + [GitHubEnterpriseTest(Skip = "Currently no way to add keys, so cant test listing keys")] + public async Task CanListAllPublicKeys() + { + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user has a key + //var key = await _github.User.Keys.Create(new NewPublicKey("title", "key")); + + // Get public keys + var keys = await _github.User.Administration.ListAllPublicKeys(); + + Assert.NotNull(keys); + Assert.True(keys.Count > 0); + + // Delete key + //await _github.User.Administration.DeletePublicKey(key.Id); + } + } + + [GitHubEnterpriseTest(Skip = "Currently no way to add keys, so cant test deleting keys")] + public async Task CanDeletePublicKey() + { + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user has a key + //var key = await _github.User.Keys.Create(new NewPublicKey("title", "key")); + + // Delete key + //await _github.User.Administration.DeletePublicKey(key.Id); + } + } + } +} diff --git a/Octokit.Tests.Integration/EnterpriseHelper.cs b/Octokit.Tests.Integration/EnterpriseHelper.cs index 63323012cc..7e03a604a2 100644 --- a/Octokit.Tests.Integration/EnterpriseHelper.cs +++ b/Octokit.Tests.Integration/EnterpriseHelper.cs @@ -140,6 +140,22 @@ public static void DeleteTeam(int teamId) catch { } } + public static void DeleteUser(User user) + { + if (user != null) + DeleteUser(user.Login); + } + + public static void DeleteUser(string username) + { + var api = GetAuthenticatedClient(); + try + { + api.User.Administration.Delete(username).Wait(TimeSpan.FromSeconds(15)); + } + catch { } + } + public static IGitHubClient GetAuthenticatedClient() { return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) diff --git a/Octokit.Tests.Integration/Helpers/EnterpriseUserContext.cs b/Octokit.Tests.Integration/Helpers/EnterpriseUserContext.cs new file mode 100644 index 0000000000..496fb52d3c --- /dev/null +++ b/Octokit.Tests.Integration/Helpers/EnterpriseUserContext.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Octokit.Tests.Integration.Helpers +{ + internal sealed class EnterpriseUserContext : IDisposable + { + internal EnterpriseUserContext(User user) + { + User = user; + UserId = user.Id; + UserLogin = user.Login; + UserEmail = user.Email; + } + + internal int UserId { get; private set; } + internal string UserLogin { get; private set; } + internal string UserEmail { get; private set; } + + internal User User { get; private set; } + + public void Dispose() + { + EnterpriseHelper.DeleteUser(User); + } + } +} diff --git a/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs b/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs index badd2b5623..e262aba0b6 100644 --- a/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs +++ b/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs @@ -36,5 +36,12 @@ internal async static Task CreateEnterpriseTeamContext(th return new EnterpriseTeamContext(team); } + + internal async static Task CreateEnterpriseUserContext(this IGitHubClient client, NewUser newUser) + { + var user = await client.User.Administration.Create(newUser); + + return new EnterpriseUserContext(user); + } } } \ No newline at end of file diff --git a/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs b/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs index 8a5919ade6..030795b0d0 100644 --- a/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs +++ b/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs @@ -27,5 +27,19 @@ internal async static Task CreateRepositoryContext(this IObse return new RepositoryContext(repo); } + + internal async static Task CreateEnterpriseTeamContext(this IObservableGitHubClient client, string organization, NewTeam newTeam) + { + var team = await client.Organization.Team.Create(organization, newTeam); + + return new EnterpriseTeamContext(team); + } + + internal async static Task CreateEnterpriseUserContext(this IObservableGitHubClient client, NewUser newUser) + { + var user = await client.User.Administration.Create(newUser); + + return new EnterpriseUserContext(user); + } } } \ No newline at end of file diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index d12eff12fd..3900738aca 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -105,6 +105,7 @@ + @@ -112,6 +113,7 @@ + @@ -143,6 +145,7 @@ + diff --git a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLdapClientTests.cs b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLdapClientTests.cs index 0880616259..dde932d8c9 100644 --- a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLdapClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLdapClientTests.cs @@ -20,11 +20,10 @@ public class ObservableEnterpriseLdapClientTests : IDisposable public ObservableEnterpriseLdapClientTests() { - var gitHub = EnterpriseHelper.GetAuthenticatedClient(); - _github = new ObservableGitHubClient(gitHub); + _github = new ObservableGitHubClient(EnterpriseHelper.GetAuthenticatedClient()); NewTeam newTeam = new NewTeam(Helper.MakeNameWithTimestamp("test-team")) { Description = "Test Team" }; - _context = gitHub.CreateEnterpriseTeamContext(EnterpriseHelper.Organization, newTeam).Result; + _context = _github.CreateEnterpriseTeamContext(EnterpriseHelper.Organization, newTeam).Result; } [GitHubEnterpriseTest] diff --git a/Octokit.Tests.Integration/Reactive/ObservableUserAdministrationClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableUserAdministrationClientTests.cs new file mode 100644 index 0000000000..efaea9a0bd --- /dev/null +++ b/Octokit.Tests.Integration/Reactive/ObservableUserAdministrationClientTests.cs @@ -0,0 +1,201 @@ +using System; +using System.Linq; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Octokit.Reactive; +using Octokit.Tests.Integration.Helpers; +using Xunit; + +namespace Octokit.Tests.Integration.Clients +{ + public class ObservableUserAdministrationClientTests + { + readonly IObservableGitHubClient _github; + + public ObservableUserAdministrationClientTests() + { + _github = new ObservableGitHubClient(EnterpriseHelper.GetAuthenticatedClient()); + } + + private NewUser GenerateNewUserDetails() + { + string username = Helper.MakeNameWithTimestamp("user"); + string email = string.Concat(username, "@company.com"); + return new NewUser(username, email); + } + + [GitHubEnterpriseTest] + public async Task CanCreateAndDelete() + { + User checkUser = null; + + // Create a new user + var newUser = GenerateNewUserDetails(); + + var observable = _github.User.Administration.Create(newUser); + var user = await observable; + + // Check returned object (cant check email as it isn't public) + Assert.NotNull(user); + Assert.Equal(user.Login, newUser.Login); + + // Get user to check they exist + checkUser = await _github.User.Get(newUser.Login); + Assert.Equal(checkUser.Login, newUser.Login); + + // Delete the user + await _github.User.Administration.Delete(newUser.Login); + + // Ensure user doesnt exist + try + { + checkUser = await _github.User.Get(newUser.Login); + if (checkUser != null) + { + throw new Exception("User still exists!"); + } + } + catch (ApiException e) + { + if (e.StatusCode != System.Net.HttpStatusCode.NotFound) + { + throw; + } + } + } + + [GitHubEnterpriseTest] + public async Task CanRename() + { + string renamedUsername = Helper.MakeNameWithTimestamp("user-renamed"); + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + var observable = _github.User.Administration.Rename( + context.UserLogin, + new UserRename(renamedUsername)); + var response = await observable; + + Assert.NotNull(response); + Assert.StartsWith("Job queued to rename user", response.Message); + Assert.EndsWith(context.UserId.ToString(), response.Url); + } + + // Remove user if it was already renamed + EnterpriseHelper.DeleteUser(renamedUsername); + } + + [GitHubEnterpriseTest] + public async Task CanAddAndDeleteImpersonationToken() + { + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Create Impersonation token + var observable = _github.User.Administration.CreateImpersonationToken( + context.UserLogin, + new NewImpersonationToken(new string[] { "public_repo" })); + var token = await observable; + + Assert.NotNull(token); + Assert.True( + token.Scopes.Count() == 1 && + token.Scopes.All(s => s == "public_repo")); + + // Delete Impersonation token + await _github.User.Administration.DeleteImpersonationToken(context.UserLogin); + } + } + + [GitHubEnterpriseTest] + public async Task CanPromoteAndDemote() + { + User checkUser = null; + + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user is not site admin + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.SiteAdmin); + + // Promote to site admin + await _github.User.Administration.Promote(context.UserLogin); + + // Ensure user is site admin + checkUser = await _github.User.Get(context.UserLogin); + Assert.True(checkUser.SiteAdmin); + + // Demote user + await _github.User.Administration.Demote(context.UserLogin); + + // Ensure user is not site admin + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.SiteAdmin); + } + } + + [GitHubEnterpriseTest] + public async Task CanSuspendAndUnsuspend() + { + User checkUser = null; + + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user is not suspended + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.Suspended); + + // Suspend user + await _github.User.Administration.Suspend(context.UserLogin); + + // Ensure user is suspended + checkUser = await _github.User.Get(context.UserLogin); + Assert.True(checkUser.Suspended); + + // Unsuspend user + await _github.User.Administration.Unsuspend(context.UserLogin); + + // Ensure user is not suspended + checkUser = await _github.User.Get(context.UserLogin); + Assert.False(checkUser.Suspended); + } + } + + [GitHubEnterpriseTest(Skip = "Currently no way to add keys, so cant test listing keys")] + public async Task CanListAllPublicKeys() + { + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user has a key + //var key = await _github.User.Keys.Create(new NewPublicKey("title", "key")); + + // Get public keys + var observable = _github.User.Administration.ListAllPublicKeys(); + var keys = await (observable.ToList()); + + Assert.NotNull(keys); + Assert.True(keys.Count > 0); + + // Delete key + //await _github.User.Administration.DeletePublicKey(key.Id); + } + } + + [GitHubEnterpriseTest(Skip = "Currently no way to add keys, so cant test deleting keys")] + public async Task CanDeletePublicKey() + { + // Create a disposable user for the test + using (var context = _github.CreateEnterpriseUserContext(GenerateNewUserDetails()).Result) + { + // Ensure user has a key + //var key = await _github.User.Keys.Create(new NewPublicKey("title", "key")); + + // Delete key + //await _github.User.Administration.DeletePublicKey(key.Id); + } + } + } +} diff --git a/Octokit.Tests/Clients/UserAdministrationClientTests.cs b/Octokit.Tests/Clients/UserAdministrationClientTests.cs index 573fe10793..4174b06be5 100644 --- a/Octokit.Tests/Clients/UserAdministrationClientTests.cs +++ b/Octokit.Tests/Clients/UserAdministrationClientTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using NSubstitute; using Octokit.Tests.Helpers; @@ -9,6 +10,174 @@ namespace Octokit.Tests.Clients { public class UserAdministrationClientTests { + public class TheCreateMethod + { + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new UserAdministrationClient(Substitute.For()); + await Assert.ThrowsAsync(() => client.Create(null)); + } + + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + var expectedUri = "admin/users"; + client.Create(new NewUser("name", "email@company.com")); + + connection.Received().Post( + Arg.Is(u => u.ToString() == expectedUri), + Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + client.Create(new NewUser("name", "email@company.com")); + + connection.Received().Post( + Arg.Any(), + Arg.Is(a => + a.Login == "name" && + a.Email == "email@company.com")); + } + } + + public class TheRenameMethod + { + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new UserAdministrationClient(Substitute.For()); + await Assert.ThrowsAsync(() => client.Rename(null, new UserRename("newlogin"))); + await Assert.ThrowsAsync(() => client.Rename("login", null)); + } + + [Fact] + public async Task EnsuresNonEmptyString() + { + var client = new UserAdministrationClient(Substitute.For()); + var exception = await Assert.ThrowsAsync(() => client.Rename("", new UserRename())); + Assert.Equal("login", exception.ParamName); + } + + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + var expectedUri = "admin/users/auser"; + client.Rename("auser", new UserRename()); + + connection.Received().Patch( + Arg.Is(u => u.ToString() == expectedUri), + Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + client.Rename("auser", new UserRename("newlogin")); + + connection.Received().Patch( + Arg.Any(), + Arg.Is(a => + a.Login == "newlogin")); + } + } + + public class TheCreateImpersonationTokenMethod + { + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new UserAdministrationClient(Substitute.For()); + await Assert.ThrowsAsync(() => client.CreateImpersonationToken(null, new NewImpersonationToken())); + await Assert.ThrowsAsync(() => client.CreateImpersonationToken("login", null)); + } + + [Fact] + public async Task EnsuresNonEmptyString() + { + var client = new UserAdministrationClient(Substitute.For()); + var exception = await Assert.ThrowsAsync(() => client.CreateImpersonationToken("", new NewImpersonationToken())); + Assert.Equal("login", exception.ParamName); + } + + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + var expectedUri = "admin/users/auser/authorizations"; + + client.CreateImpersonationToken("auser", new NewImpersonationToken()); + + connection.Received().Post( + Arg.Is(u => u.ToString() == expectedUri), + Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + string[] scopes = new string[] { "public-repo" }; + client.CreateImpersonationToken("auser", new NewImpersonationToken(scopes)); + + connection.Received().Post( + Arg.Any(), + Arg.Is(a => + a.Scopes.Count() == scopes.Count() && + a.Scopes.ToList().All(s => scopes.Contains(s)) && + scopes.ToList().All(s => a.Scopes.Contains(s)))); + } + } + + public class TheDeleteImpersonationTokenMethod + { + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new UserAdministrationClient(Substitute.For()); + await Assert.ThrowsAsync(() => client.DeleteImpersonationToken(null)); + } + + [Fact] + public async Task EnsuresNonEmptyString() + { + var client = new UserAdministrationClient(Substitute.For()); + var exception = await Assert.ThrowsAsync(() => client.DeleteImpersonationToken("")); + Assert.Equal("login", exception.ParamName); + } + + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + var expectedUri = "admin/users/auser/authorizations"; + client.DeleteImpersonationToken("auser"); + + connection.Connection.Received().Delete( + Arg.Is(u => u.ToString() == expectedUri)); + } + } + public class ThePromoteMethod { [Fact] @@ -32,11 +201,14 @@ public void RequestsTheCorrectUrl() var connection = Substitute.For(); var client = new UserAdministrationClient(connection); + var expectedUri = "users/auser/site_admin"; client.Promote("auser"); - connection.Received().Put(Arg.Is(u => u.ToString() == "/users/auser/site_admin")); + connection.Received().Put( + Arg.Is(u => u.ToString() == expectedUri)); } } + public class TheDemoteMethod { [Fact] @@ -60,9 +232,11 @@ public void RequestsTheCorrectUrl() var connection = Substitute.For(); var client = new UserAdministrationClient(connection); + var expectedUri = "users/auser/site_admin"; client.Demote("auser"); - connection.Received().Delete(Arg.Is(u => u.ToString() == "/users/auser/site_admin")); + connection.Received().Delete( + Arg.Is(u => u.ToString() == expectedUri)); } } @@ -89,9 +263,11 @@ public void RequestsTheCorrectUrl() var connection = Substitute.For(); var client = new UserAdministrationClient(connection); + var expectedUri = "users/auser/suspended"; client.Suspend("auser"); - connection.Received().Put(Arg.Is(u => u.ToString() == "/users/auser/suspended")); + connection.Received().Put( + Arg.Is(u => u.ToString() == expectedUri)); } } @@ -118,9 +294,74 @@ public void RequestsTheCorrectUrl() var connection = Substitute.For(); var client = new UserAdministrationClient(connection); + var expectedUri = "users/auser/suspended"; client.Unsuspend("auser"); - connection.Received().Delete(Arg.Is(u => u.ToString() == "/users/auser/suspended")); + connection.Received().Delete( + Arg.Is(u => u.ToString() == expectedUri)); + } + } + + public class TheListAllPublicKeysMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + var expectedUri = "admin/keys"; + client.ListAllPublicKeys(); + + connection.Received().GetAll( + Arg.Is(u => u.ToString() == expectedUri)); + } + } + + public class TheDeleteMethod + { + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new UserAdministrationClient(Substitute.For()); + await Assert.ThrowsAsync(() => client.Delete(null)); + } + + [Fact] + public async Task EnsuresNonEmptyString() + { + var client = new UserAdministrationClient(Substitute.For()); + var exception = await Assert.ThrowsAsync(() => client.Delete("")); + Assert.Equal("login", exception.ParamName); + } + + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + var expectedUri = "admin/users/auser"; + client.Delete("auser"); + + connection.Connection.Received().Delete( + Arg.Is(u => u.ToString() == expectedUri)); + } + } + + public class TheDeletePublicKeyMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new UserAdministrationClient(connection); + + var expectedUri = "admin/keys/1"; + client.DeletePublicKey(1); + + connection.Connection.Received().Delete( + Arg.Is(u => u.ToString() == expectedUri)); } } } diff --git a/Octokit.Tests/Reactive/ObservableUserAdministrationClientTests.cs b/Octokit.Tests/Reactive/ObservableUserAdministrationClientTests.cs index d605e71843..d247ddb30f 100644 --- a/Octokit.Tests/Reactive/ObservableUserAdministrationClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableUserAdministrationClientTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using NSubstitute; using Octokit.Reactive; using Xunit; @@ -7,10 +8,75 @@ namespace Octokit.Tests.Reactive { public class ObservableUserAdministrationClientTests { + public class TheCreateMethod + { + [Fact] + public void CallsIntoClient() + { + var gitHubClient = Substitute.For(); + var client = new ObservableUserAdministrationClient(gitHubClient); + + client.Create(new NewUser("auser", "email@company.com")); + + gitHubClient.User.Administration.Received().Create( + Arg.Is(a => + a.Login == "auser" && + a.Email == "email@company.com")); + } + } + + public class TheRenameMethod + { + [Fact] + public void CallsIntoClient() + { + var gitHubClient = Substitute.For(); + var client = new ObservableUserAdministrationClient(gitHubClient); + + client.Rename("auser", new UserRename("renamed-user")); + + gitHubClient.User.Administration.Received().Rename( + "auser", + Arg.Is(a => + a.Login == "renamed-user")); + } + } + + public class TheCreateImpersonationTokenMethod + { + [Fact] + public void CallsIntoClient() + { + var gitHubClient = Substitute.For(); + var client = new ObservableUserAdministrationClient(gitHubClient); + + client.CreateImpersonationToken("auser", new NewImpersonationToken(new string[] { "public_repo" })); + + gitHubClient.User.Administration.Received().CreateImpersonationToken( + "auser", + Arg.Is(a => + a.Scopes.ToList()[0] == "public_repo")); + } + } + + public class TheDeleteImpersonationTokenMethod + { + [Fact] + public void CallsIntoClient() + { + var gitHubClient = Substitute.For(); + var client = new ObservableUserAdministrationClient(gitHubClient); + + client.DeleteImpersonationToken("auser"); + + gitHubClient.User.Administration.Received().DeleteImpersonationToken("auser"); + } + } + public class ThePromoteMethod { [Fact] - public void GetsFromClientPromtePromote() + public void CallsIntoClient() { var gitHubClient = Substitute.For(); var client = new ObservableUserAdministrationClient(gitHubClient); @@ -24,7 +90,7 @@ public void GetsFromClientPromtePromote() public class TheDemoteMethod { [Fact] - public void GetsFromClientDemoteDemote() + public void CallsIntoClient() { var gitHubClient = Substitute.For(); var client = new ObservableUserAdministrationClient(gitHubClient); @@ -38,7 +104,7 @@ public void GetsFromClientDemoteDemote() public class TheSuspendMethod { [Fact] - public void GetsFromClientSuspendSuspend() + public void CallsIntoClient() { var gitHubClient = Substitute.For(); var client = new ObservableUserAdministrationClient(gitHubClient); @@ -52,7 +118,7 @@ public void GetsFromClientSuspendSuspend() public class TheUnsuspendMethod { [Fact] - public void GetsFromClientUnsuspendUnsuspend() + public void CallsIntoClient() { var gitHubClient = Substitute.For(); var client = new ObservableUserAdministrationClient(gitHubClient); @@ -63,6 +129,54 @@ public void GetsFromClientUnsuspendUnsuspend() } } + public class TheListAllPublicKeysMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableUserAdministrationClient(gitHubClient); + + var expectedUri = "admin/keys"; + + client.ListAllPublicKeys(); + + gitHubClient.Connection.Received().Get>( + Arg.Is(a => + a.ToString() == expectedUri), + null, + null); + } + } + + public class TheDeleteMethod + { + [Fact] + public void CallsIntoClient() + { + var gitHubClient = Substitute.For(); + var client = new ObservableUserAdministrationClient(gitHubClient); + + client.Delete("auser"); + + gitHubClient.User.Administration.Received().Delete("auser"); + } + } + + public class TheDeletePublicKeyMethod + { + [Fact] + public void CallsIntoClient() + { + var gitHubClient = Substitute.For(); + var client = new ObservableUserAdministrationClient(gitHubClient); + + client.DeletePublicKey(1); + + gitHubClient.User.Administration.Received().DeletePublicKey(1); + } + } + public class TheCtor { [Fact] diff --git a/Octokit/Clients/IUserAdministrationClient.cs b/Octokit/Clients/IUserAdministrationClient.cs index cdececd9a1..8bd2af8e75 100644 --- a/Octokit/Clients/IUserAdministrationClient.cs +++ b/Octokit/Clients/IUserAdministrationClient.cs @@ -1,56 +1,137 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit -{ /// - /// A client for GitHub's User Administration API. - /// - /// - /// See the Administration API documentation for more details. - /// +{ + /// + /// A client for GitHub's User Administration API (GitHub Enterprise) + /// + /// + /// See the Administration API documentation for more details. + /// public interface IUserAdministrationClient { /// - /// Promotes ordinary user to a site administrator. + /// Create a new user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#promote-an-ordinary-user-to-a-site-administrator + /// See the API documentation + /// for more information. + /// + /// The object describing the user to create + /// The created object + Task Create(NewUser newUser); + + /// + /// Rename an existing user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// Note that this queues a request to rename a user, rather than execute it straight away + /// + /// The username to rename + /// The request, specifying the new login + /// A object indicating the queued task message and Url to the user + Task Rename(string login, UserRename userRename); + + /// + /// Create an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to impersonate + /// The request specifying the required scopes + /// An object containing the impersonation token + Task CreateImpersonationToken(string login, NewImpersonationToken newImpersonationToken); + + /// + /// Deletes an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to remove impersonation token from + /// + Task DeleteImpersonationToken(string login); + + /// + /// Promotes ordinary user to a site administrator (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. /// /// The user to promote to administrator. /// Task Promote(string login); /// - /// Demotes a site administrator to an ordinary user. + /// Demotes a site administrator to an ordinary user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#demote-a-site-administrator-to-an-ordinary-user + /// See the API documentation + /// for more information. /// /// The user to demote from administrator. /// Task Demote(string login); /// - /// Suspends a user. + /// Suspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#suspend-a-user + /// See the API documentation + /// for more information. /// /// The user to suspend. /// Task Suspend(string login); /// - /// Unsuspends a user. + /// Unsuspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#unsuspend-a-user + /// See the API documentation + /// for more information. /// /// The user to unsuspend. /// Task Unsuspend(string login); + + /// + /// List all public keys (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// + Task> ListAllPublicKeys(); + + /// + /// Delete a user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to delete + /// + Task Delete(string login); + + /// + /// Delete a public key (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The key to delete + /// + Task DeletePublicKey(int keyId); } } diff --git a/Octokit/Clients/UserAdministrationClient.cs b/Octokit/Clients/UserAdministrationClient.cs index 4b8ff4c8c2..a39fcb8dd8 100644 --- a/Octokit/Clients/UserAdministrationClient.cs +++ b/Octokit/Clients/UserAdministrationClient.cs @@ -1,13 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; +using System.Net; using System.Threading.Tasks; namespace Octokit { /// - /// A client for GitHub's User Administration API. + /// A client for GitHub's User Administration API (GitHub Enterprise) /// /// /// See the Administration API documentation for more details. @@ -24,63 +22,210 @@ public UserAdministrationClient(IApiConnection apiConnection) } /// - /// Promotes ordinary user to a site administrator. + /// Create a new user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#promote-an-ordinary-user-to-a-site-administrator + /// See the API documentation + /// for more information. + /// + /// The object describing the user to create + /// The created object + public Task Create(NewUser newUser) + { + Ensure.ArgumentNotNull(newUser, "newUser"); + + var endpoint = ApiUrls.UserAdministration(); + + return ApiConnection.Post(endpoint, newUser); + } + + /// + /// Rename an existing user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// Note that this queues a request to rename a user, rather than execute it straight away + /// + /// The username to rename + /// The request, specifying the new login + /// A object indicating the queued task message and Url to the user + public Task Rename(string login, UserRename userRename) + { + Ensure.ArgumentNotNullOrEmptyString(login, "login"); + Ensure.ArgumentNotNull(userRename, "userRename"); + + var endpoint = ApiUrls.UserAdministration(login); + + return ApiConnection.Patch(endpoint, userRename); + } + + /// + /// Create an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to impersonate + /// The request specifying the required scopes + /// An object containing the impersonation token + public Task CreateImpersonationToken(string login, NewImpersonationToken newImpersonationToken) + { + Ensure.ArgumentNotNullOrEmptyString(login, "login"); + Ensure.ArgumentNotNull(newImpersonationToken, "newImpersonationToken"); + + var endpoint = ApiUrls.UserAdministrationAuthorization(login); + + return ApiConnection.Post(endpoint, newImpersonationToken); + } + + /// + /// Deletes an impersonation OAuth token (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to remove impersonation token from + /// + public async Task DeleteImpersonationToken(string login) + { + Ensure.ArgumentNotNullOrEmptyString(login, "login"); + + var endpoint = ApiUrls.UserAdministrationAuthorization(login); + + var response = ((HttpStatusCode)await Connection.Delete(endpoint)); + if (response != HttpStatusCode.NoContent) + { + throw new ApiException("Invalid Status Code returned. Expected a 204", response); + } + + return; + } + + /// + /// Promotes ordinary user to a site administrator (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. /// /// The user to promote to administrator. /// public Task Promote(string login) { Ensure.ArgumentNotNullOrEmptyString(login, "login"); - var endpoint = ApiUrls.UserAdministration(login); + var endpoint = ApiUrls.UserAdministrationSiteAdmin(login); return ApiConnection.Put(endpoint); } /// - /// Demotes a site administrator to an ordinary user. + /// Demotes a site administrator to an ordinary user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#demote-a-site-administrator-to-an-ordinary-user + /// See the API documentation + /// for more information. /// /// The user to demote from administrator. /// public Task Demote(string login) { Ensure.ArgumentNotNullOrEmptyString(login, "login"); - var endpoint = ApiUrls.UserAdministration(login); + var endpoint = ApiUrls.UserAdministrationSiteAdmin(login); return ApiConnection.Delete(endpoint); } /// - /// Suspends a user. + /// Suspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#suspend-a-user + /// See the API documentation + /// for more information. /// /// The user to suspend. /// public Task Suspend(string login) { Ensure.ArgumentNotNullOrEmptyString(login, "login"); - var endpoint = ApiUrls.UserSuspension(login); + var endpoint = ApiUrls.UserAdministrationSuspension(login); return ApiConnection.Put(endpoint); } /// - /// Unsuspends a user. + /// Unsuspends a user (must be Site Admin user). /// /// - /// https://developer.github.com/v3/users/administration/#unsuspend-a-user + /// See the API documentation + /// for more information. /// /// The user to unsuspend. /// public Task Unsuspend(string login) { Ensure.ArgumentNotNullOrEmptyString(login, "login"); - var endpoint = ApiUrls.UserSuspension(login); + var endpoint = ApiUrls.UserAdministrationSuspension(login); return ApiConnection.Delete(endpoint); } + + /// + /// List all public keys (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// + public Task> ListAllPublicKeys() + { + var endpoint = ApiUrls.UserAdministrationPublicKeys(); + return ApiConnection.GetAll(endpoint); + } + + /// + /// Delete a user (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The user to delete + /// + public async Task Delete(string login) + { + Ensure.ArgumentNotNullOrEmptyString(login, "login"); + var endpoint = ApiUrls.UserAdministration(login); + + var response = ((HttpStatusCode)await Connection.Delete(endpoint)); + if (response != HttpStatusCode.NoContent) + { + throw new ApiException("Invalid Status Code returned. Expected a 204", response); + } + + return; + } + + /// + /// Delete a public key (must be Site Admin user). + /// + /// + /// See the API documentation + /// for more information. + /// + /// The key to delete + /// + public async Task DeletePublicKey(int keyId) + { + Ensure.ArgumentNotNull(keyId, "keyId"); + var endpoint = ApiUrls.UserAdministrationPublicKeys(keyId); + + var response = ((HttpStatusCode)await Connection.Delete(endpoint)); + if (response != HttpStatusCode.NoContent) + { + throw new ApiException("Invalid Status Code returned. Expected a 204", response); + } + + return; + } } } diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 2c7e131c38..1f067602ca 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1699,14 +1699,39 @@ public static Uri EnterpriseSearchIndexing() return "staff/indexing_jobs".FormatUri(); } + public static Uri UserAdministration() + { + return "admin/users".FormatUri(); + } + + public static Uri UserAdministration(string login) + { + return "admin/users/{0}".FormatUri(login); + } + + public static Uri UserAdministrationAuthorization(string login) + { + return "admin/users/{0}/authorizations".FormatUri(login); + } + + public static Uri UserAdministrationPublicKeys() + { + return "admin/keys".FormatUri(); + } + + public static Uri UserAdministrationPublicKeys(int keyId) + { + return "admin/keys/{0}".FormatUri(keyId); + } + /// /// Creates the relative for altering administration status of a user. /// /// The login for the intended user. /// - public static Uri UserAdministration(string login) + public static Uri UserAdministrationSiteAdmin(string login) { - return "/users/{0}/site_admin".FormatUri(login); + return "users/{0}/site_admin".FormatUri(login); } /// @@ -1714,9 +1739,9 @@ public static Uri UserAdministration(string login) /// /// The login for the intended user. /// - public static Uri UserSuspension(string login) + public static Uri UserAdministrationSuspension(string login) { - return "/users/{0}/suspended".FormatUri(login); + return "users/{0}/suspended".FormatUri(login); } } } diff --git a/Octokit/Models/Request/NewImpersonationToken.cs b/Octokit/Models/Request/NewImpersonationToken.cs new file mode 100644 index 0000000000..3e55126d48 --- /dev/null +++ b/Octokit/Models/Request/NewImpersonationToken.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Describes a new Impersonation Token to create via the method. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewImpersonationToken + { + public NewImpersonationToken() { } + + /// + /// Initializes a new instance of the class. + /// + /// The scopes for the token. + public NewImpersonationToken(IEnumerable scopes) + { + Scopes = scopes; + } + + /// + /// The scopes for the token + /// + public IEnumerable Scopes { get; set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Scopes: {0}", string.Join("\r\n", Scopes)); + } + } + } +} diff --git a/Octokit/Models/Request/NewUser.cs b/Octokit/Models/Request/NewUser.cs new file mode 100644 index 0000000000..600d339d15 --- /dev/null +++ b/Octokit/Models/Request/NewUser.cs @@ -0,0 +1,48 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace Octokit +{ + /// + /// Describes a new user to create via the method. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewUser + { + public NewUser() { } + + /// + /// Initializes a new instance of the class. + /// + /// The login for the user. + /// The email address of the user + public NewUser(string login, string email) + { + Ensure.ArgumentNotNullOrEmptyString(login, "login"); + Ensure.ArgumentNotNullOrEmptyString(email, "email"); + + Login = login; + Email = email; + } + + /// + /// Login of the user + /// + public string Login { get; protected set; } + + /// + /// Email address of the user + /// + public string Email { get; protected set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Login: {0} Email: {1}", Login, Email); + } + } + } +} diff --git a/Octokit/Models/Request/UserRename.cs b/Octokit/Models/Request/UserRename.cs new file mode 100644 index 0000000000..6a7bde76ff --- /dev/null +++ b/Octokit/Models/Request/UserRename.cs @@ -0,0 +1,38 @@ +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Describes the new login when renaming a user via the method. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class UserRename + { + public UserRename() { } + + /// + /// Initializes a new instance of the class. + /// + /// The new login for the user. + public UserRename(string login) + { + Ensure.ArgumentNotNullOrEmptyString(login, "login"); + + Login = login; + } + + /// + /// The new username for the user + /// + public string Login { get; protected set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Login: {0}", Login); + } + } + } +} diff --git a/Octokit/Models/Response/User.cs b/Octokit/Models/Response/User.cs index 14bc3e96ef..59bb4e3672 100644 --- a/Octokit/Models/Response/User.cs +++ b/Octokit/Models/Response/User.cs @@ -14,11 +14,12 @@ public class User : Account { public User() { } - public User(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, bool siteAdmin, string ldapDistinguishedName) + public User(string avatarUrl, string bio, string blog, int collaborators, string company, DateTimeOffset createdAt, int diskUsage, string email, int followers, int following, bool? hireable, string htmlUrl, int totalPrivateRepos, int id, string location, string login, string name, int ownedPrivateRepos, Plan plan, int privateGists, int publicGists, int publicRepos, string url, bool siteAdmin, string ldapDistinguishedName, DateTimeOffset? suspendedAt) : base(avatarUrl, bio, blog, collaborators, company, createdAt, diskUsage, email, followers, following, hireable, htmlUrl, totalPrivateRepos, id, location, login, name, ownedPrivateRepos, plan, privateGists, publicGists, publicRepos, AccountType.User, url) { SiteAdmin = siteAdmin; LdapDistinguishedName = ldapDistinguishedName; + SuspendedAt = suspendedAt; } /// @@ -26,6 +27,16 @@ public User(string avatarUrl, string bio, string blog, int collaborators, string /// public bool SiteAdmin { get; protected set; } + /// + /// When the user was suspended, if at all (GitHub Enterprise) + /// + public DateTimeOffset? SuspendedAt { get; protected set; } + + /// + /// Whether or not the user is currently suspended + /// + public bool Suspended { get { return SuspendedAt.HasValue; } } + /// /// LDAP Binding (GitHub Enterprise only) /// diff --git a/Octokit/Models/Response/UserRenameResponse.cs b/Octokit/Models/Response/UserRenameResponse.cs new file mode 100644 index 0000000000..9fe0c8a6fe --- /dev/null +++ b/Octokit/Models/Response/UserRenameResponse.cs @@ -0,0 +1,38 @@ +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Represents the response information from a operation + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class UserRenameResponse + { + public UserRenameResponse() { } + + public UserRenameResponse(string message, string url) + { + Message = message; + Url = url; + } + + /// + /// Message indiating if the Rename request was queued + /// + public string Message { get; protected set; } + + /// + /// Url to the user that will be renamed + /// + public string Url { get; protected set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Message: {0}", Message); + } + } + } +} diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 674e22acf7..1adf178be9 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -452,6 +452,10 @@ + + + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 15d146fc52..96b6ba4165 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -460,6 +460,10 @@ + + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 98e4beee9c..491e5cbb8b 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -456,6 +456,10 @@ + + + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index eedca31146..f378486f3e 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -449,6 +449,10 @@ + + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 8478f6f53e..67015b13f9 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -456,6 +456,10 @@ + + + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 45a357276b..0109e67a22 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -113,12 +113,14 @@ + + @@ -132,6 +134,7 @@ + @@ -171,6 +174,7 @@ + @@ -488,4 +492,4 @@ --> - + \ No newline at end of file