From 68b3fa5c3d2a7094fbf7afccfd6e26c13c7465e8 Mon Sep 17 00:00:00 2001 From: Skye McLeman <118782658+skyemcleman@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:37:59 +1100 Subject: [PATCH 1/4] Add API request to create org invitation --- Octokit/Clients/IOrganizationMembersClient.cs | 15 ++++ Octokit/Clients/OrganizationMembersClient.cs | 22 +++++ Octokit/Helpers/ApiUrls.cs | 10 +++ .../Request/OrganizationInvitationRequest.cs | 87 +++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 Octokit/Models/Request/OrganizationInvitationRequest.cs diff --git a/Octokit/Clients/IOrganizationMembersClient.cs b/Octokit/Clients/IOrganizationMembersClient.cs index c16707f9d6..1a71af028f 100644 --- a/Octokit/Clients/IOrganizationMembersClient.cs +++ b/Octokit/Clients/IOrganizationMembersClient.cs @@ -310,6 +310,21 @@ public interface IOrganizationMembersClient /// Task AddOrUpdateOrganizationMembership(string org, string user, OrganizationMembershipUpdate addOrUpdateRequest); + /// + /// Create an organization invitation for a user + /// + /// + /// This method requires authentication. + /// The authenticated user must be an organization owner. + /// See the API documentation + /// for more information. + /// + /// The login for the organization + /// An instance containing the + /// details of the organization invitation + /// + Task CreateOrganizationInvitation(string org, OrganizationInvitationRequest invitationRequest); + /// /// Remove a user's membership with an organization. /// diff --git a/Octokit/Clients/OrganizationMembersClient.cs b/Octokit/Clients/OrganizationMembersClient.cs index b5fd87de78..038d821be4 100644 --- a/Octokit/Clients/OrganizationMembersClient.cs +++ b/Octokit/Clients/OrganizationMembersClient.cs @@ -511,6 +511,28 @@ public Task AddOrUpdateOrganizationMembership(string org return ApiConnection.Put(ApiUrls.OrganizationMemberships(org, user), addOrUpdateRequest); } + /// + /// Create an organization invitation for a user + /// + /// + /// This method requires authentication. + /// The authenticated user must be an organization owner. + /// See the API documentation + /// for more information. + /// + /// The login for the organization + /// An instance containing the + /// details of the organization invitation + /// + [ManualRoute("POST", "/orgs/{org}/invitations")] + public Task CreateOrganizationInvitation(string org, OrganizationInvitationRequest invitationRequest) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(invitationRequest, nameof(invitationRequest)); + + return ApiConnection.Post(ApiUrls.OrganizationInvitations(org), invitationRequest); + } + /// /// Remove a user's membership with an organization. /// diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 50b8e1a0e9..7c8ecc27ed 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -922,6 +922,16 @@ public static Uri OrganizationMemberships(string org, string name) { return "orgs/{0}/memberships/{1}".FormatUri(org, name); } + + /// + /// Returns the for the organization's invitations + /// + /// The name of the organization + /// + public static Uri OrganizationInvitations(string org) + { + return "orgs/{0}/invitations".FormatUri(org); + } /// /// Returns the for the organizations pending invitations diff --git a/Octokit/Models/Request/OrganizationInvitationRequest.cs b/Octokit/Models/Request/OrganizationInvitationRequest.cs new file mode 100644 index 0000000000..0db963146d --- /dev/null +++ b/Octokit/Models/Request/OrganizationInvitationRequest.cs @@ -0,0 +1,87 @@ +using System.Diagnostics; +using System.Globalization; +using Octokit.Internal; + +namespace Octokit +{ + /// + /// Used as part of the request to invite a user to an organization. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class OrganizationInvitationRequest + { + public OrganizationInvitationRequest(int inviteeId) + { + InviteeId = inviteeId; + } + + public OrganizationInvitationRequest(string email) + { + Email = email; + } + + public OrganizationInvitationRequest(int inviteeId, OrganizationMembershipRole role) + { + InviteeId = inviteeId; + Role = role; + } + + public OrganizationInvitationRequest(string email, OrganizationMembershipRole role) + { + Email = email; + Role = role; + } + + public OrganizationInvitationRequest(int inviteeId, int[] teamIds) + { + InviteeId = inviteeId; + TeamIds = teamIds; + } + + public OrganizationInvitationRequest(string email, int[] teamIds) + { + Email = email; + TeamIds = teamIds; + } + + public OrganizationInvitationRequest(int inviteeId, OrganizationMembershipRole role, int[] teamIds) + { + InviteeId = inviteeId; + Role = role; + TeamIds = teamIds; + } + + public OrganizationInvitationRequest(string email, OrganizationMembershipRole role, int[] teamIds) + { + Email = email; + Role = role; + TeamIds = teamIds; + } + + /// + /// The user ID of the person being invited. Required if Email is not specified. + /// + [Parameter(Key = "invitee_id")] + public int? InviteeId { get; set; } + + /// + /// The email address of the person being invited. Required if InviteeId is not specified. + /// + [Parameter(Key = "email")] + public string Email { get; set; } + + /// + /// The role to give the user in the organization. The default is . + /// + [Parameter(Key = "role")] + public OrganizationMembershipRole Role { get; set; } = OrganizationMembershipRole.DirectMember; + + /// + /// The IDs for the team(s) to invite new members to + /// + [Parameter(Key = "team_ids")] + public int[] TeamIds { get; set; } + + internal string DebuggerDisplay => $"InviteeId: {InviteeId}; Email: {Email}; Role: {Role}; Team IDs: {(TeamIds != null ? string.Join(", ", TeamIds) : "")}"; + } +} From 0edfab51e6d61bc236f2f6315dc7473a8eab9c90 Mon Sep 17 00:00:00 2001 From: Skye McLeman <118782658+skyemcleman@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:38:36 +1100 Subject: [PATCH 2/4] Add tests for create org invitation --- .../Clients/OrganizationMembersClientTests.cs | 93 ++++++++++++++++++- .../Clients/OrganizationMembersClientTests.cs | 28 ++++++ Octokit.Tests/Helpers/RandomEmailGenerator.cs | 15 +++ .../OrganizationInvitationRequestTests.cs | 35 +++++++ .../OrganizationMembershipInvitation.cs | 4 +- 5 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 Octokit.Tests/Helpers/RandomEmailGenerator.cs create mode 100644 Octokit.Tests/Models/OrganizationInvitationRequestTests.cs diff --git a/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs index d1fcb7f2c9..580d24fe09 100644 --- a/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs +++ b/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs @@ -1,5 +1,7 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading.Tasks; +using Octokit.Tests.Helpers; using Octokit.Tests.Integration.Helpers; using Xunit; @@ -172,6 +174,95 @@ public async Task ReturnsUsersPendingAdminOrganizationMembership() } } + public class TheCreateOrganizationInvitationMethod + { + readonly IGitHubClient _gitHub; + + public TheCreateOrganizationInvitationMethod() + { + _gitHub = Helper.GetAuthenticatedClient(); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationViaUserId() + { + var user = await _gitHub.User.Get("alfhenrik-test-2"); + + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id); + var organizationMembershipInvitation = await _gitHub.Organization.Member.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal("alfhenrik-test-2", organizationMembershipInvitation.Login); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + + await _gitHub.Organization.Member.RemoveOrganizationMembership(Helper.Organization, "alfhenrik-test-2"); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationViaUserEmail() + { + var email = RandomEmailGenerator.GenerateRandomEmail(); + + var organizationInvitationRequest = new OrganizationInvitationRequest(email); + var organizationMembershipInvitation = await _gitHub.Organization.Member.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal(email, organizationMembershipInvitation.Email); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + + await _gitHub.Organization.Member.CancelOrganizationInvitation(Helper.Organization, organizationMembershipInvitation.Id); + } + + [OrganizationTest] + public async Task ThrowsApiValidationExceptionForCurrentOrganizationMembers() + { + var user = await _gitHub.User.Get(Helper.UserName); + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id); + + await Assert.ThrowsAsync(() => _gitHub.Organization.Member.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest)); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationSingleTeam() + { + var user = await _gitHub.User.Get("alfhenrik-test-2"); + + var team1 = await _gitHub.Organization.Team.Create(Helper.Organization, new NewTeam("TestTeam1")); + + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id, new int[] {team1.Id}); + var organizationMembershipInvitation = await _gitHub.Organization.Member.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal("alfhenrik-test-2", organizationMembershipInvitation.Login); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + Assert.Equal(1, organizationMembershipInvitation.TeamCount); + + await _gitHub.Organization.Team.Delete(Helper.Organization, team1.Slug); + await _gitHub.Organization.Member.RemoveOrganizationMembership(Helper.Organization, "alfhenrik-test-2"); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationMultipleTeams() + { + var user = await _gitHub.User.Get("alfhenrik-test-2"); + + var team1 = await _gitHub.Organization.Team.Create(Helper.Organization, new NewTeam("TestTeam1")); + var team2 = await _gitHub.Organization.Team.Create(Helper.Organization, new NewTeam("TestTeam2")); + + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id, new int[] {team1.Id, team2.Id}); + var organizationMembershipInvitation = await _gitHub.Organization.Member.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal("alfhenrik-test-2", organizationMembershipInvitation.Login); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + Assert.Equal(2, organizationMembershipInvitation.TeamCount); + + await _gitHub.Organization.Team.Delete(Helper.Organization, team1.Slug); + await _gitHub.Organization.Team.Delete(Helper.Organization, team2.Slug); + await _gitHub.Organization.Member.RemoveOrganizationMembership(Helper.Organization, "alfhenrik-test-2"); + } + } + public class TheRemoveOrganizationMembershipMethod { readonly IGitHubClient _gitHub; diff --git a/Octokit.Tests/Clients/OrganizationMembersClientTests.cs b/Octokit.Tests/Clients/OrganizationMembersClientTests.cs index d09ed836aa..838cca8644 100644 --- a/Octokit.Tests/Clients/OrganizationMembersClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationMembersClientTests.cs @@ -2,6 +2,7 @@ using System.Net; using System.Threading.Tasks; using NSubstitute; +using NSubstitute.Core.DependencyInjection; using Octokit.Internal; using Xunit; @@ -562,6 +563,33 @@ public async Task EnsureNonNullArguments() } } + public class TheCreateOrganizationInvitationMethod + { + [Fact] + public void PostsToTheCorrectUrl() + { + var organizationInvitationRequest = new OrganizationInvitationRequest("email"); + + var connection = Substitute.For(); + var client = new OrganizationMembersClient(connection); + + client.CreateOrganizationInvitation("org", organizationInvitationRequest); + + connection.Received().Post(Arg.Is(u => u.ToString() == "orgs/org/invitations"), Arg.Any()); + } + + [Fact] + public async Task EnsureNonNullArguments() + { + var organizationInvitationRequest = new OrganizationInvitationRequest("email"); + var client = new OrganizationMembersClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.CreateOrganizationInvitation(null, organizationInvitationRequest)); + await Assert.ThrowsAsync(() => client.CreateOrganizationInvitation("", organizationInvitationRequest)); + await Assert.ThrowsAsync(() => client.CreateOrganizationInvitation("org", null)); + } + } + public class TheDeleteOrganizationMembershipMethod { [Fact] diff --git a/Octokit.Tests/Helpers/RandomEmailGenerator.cs b/Octokit.Tests/Helpers/RandomEmailGenerator.cs new file mode 100644 index 0000000000..c5399fb0e3 --- /dev/null +++ b/Octokit.Tests/Helpers/RandomEmailGenerator.cs @@ -0,0 +1,15 @@ +using System; + +namespace Octokit.Tests.Helpers +{ + public static class RandomEmailGenerator + { + public static string GenerateRandomEmail() + { + var randomUsername = Guid.NewGuid().ToString(); + var randomDomain = Guid.NewGuid().ToString(); + + return $"{randomUsername}@{randomDomain}.com"; + } + } +} \ No newline at end of file diff --git a/Octokit.Tests/Models/OrganizationInvitationRequestTests.cs b/Octokit.Tests/Models/OrganizationInvitationRequestTests.cs new file mode 100644 index 0000000000..fe4da95ffe --- /dev/null +++ b/Octokit.Tests/Models/OrganizationInvitationRequestTests.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class OrganizationInvitationRequestTests + { + public class TheConstructor + { + [Fact] + public void CreatesOrganizationInvitationRequestByUserId() + { + const int userId = 1; + var organizationInvitationRequest = new OrganizationInvitationRequest(userId); + + Assert.Equal(userId, organizationInvitationRequest.InviteeId); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationInvitationRequest.Role); + Assert.Null(organizationInvitationRequest.Email); + Assert.Null(organizationInvitationRequest.TeamIds); + } + + [Fact] + public async Task CreatesOrganizationInvitationRequestByUserEmail() + { + const string email = "testemail"; + var organizationInvitationRequest = new OrganizationInvitationRequest(email); + + Assert.Equal(email, organizationInvitationRequest.Email); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationInvitationRequest.Role); + Assert.Null(organizationInvitationRequest.InviteeId); + Assert.Null(organizationInvitationRequest.TeamIds); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Response/OrganizationMembershipInvitation.cs b/Octokit/Models/Response/OrganizationMembershipInvitation.cs index 3a22389fdd..da2ebc35a3 100644 --- a/Octokit/Models/Response/OrganizationMembershipInvitation.cs +++ b/Octokit/Models/Response/OrganizationMembershipInvitation.cs @@ -12,7 +12,7 @@ public OrganizationMembershipInvitation() { } - public OrganizationMembershipInvitation(int id, string nodeId, string login, string email, OrganizationMembershipRole role, DateTimeOffset createdAt, User inviter) + public OrganizationMembershipInvitation(int id, string nodeId, string login, string email, OrganizationMembershipRole role, DateTimeOffset createdAt, User inviter, int teamCount) { Id = id; NodeId = nodeId; @@ -21,6 +21,7 @@ public OrganizationMembershipInvitation(int id, string nodeId, string login, str Role = role; CreatedAt = createdAt; Inviter = inviter; + TeamCount = teamCount; } public int Id { get; private set; } @@ -35,6 +36,7 @@ public OrganizationMembershipInvitation(int id, string nodeId, string login, str public StringEnum Role { get; private set; } public DateTimeOffset CreatedAt { get; private set; } public User Inviter { get; private set; } + public int TeamCount { get; private set; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Used by DebuggerDisplayAttribute")] From 3ec7196cd4a990a588aa98ce7a91fa429bde1501 Mon Sep 17 00:00:00 2001 From: Skye McLeman <118782658+skyemcleman@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:38:57 +1100 Subject: [PATCH 3/4] Add IObservable API request to create org invitation --- .../IObservableOrganizationMembersClient.cs | 15 +++++++++++++ .../ObservableOrganizationMembersClient.cs | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/Octokit.Reactive/Clients/IObservableOrganizationMembersClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationMembersClient.cs index 8e5a903bc0..a327040aaa 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationMembersClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationMembersClient.cs @@ -304,6 +304,21 @@ public interface IObservableOrganizationMembersClient /// IObservable AddOrUpdateOrganizationMembership(string org, string user, OrganizationMembershipUpdate addOrUpdateRequest); + /// + /// Create an organization invitation for a user + /// + /// + /// This method requires authentication. + /// The authenticated user must be an organization owner. + /// See the API documentation + /// for more information. + /// + /// The login for the organization + /// An instance containing the + /// details of the organization invitation + /// + IObservable CreateOrganizationInvitation(string org, OrganizationInvitationRequest invitationRequest); + /// /// Remove a user's membership with an organization. /// diff --git a/Octokit.Reactive/Clients/ObservableOrganizationMembersClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationMembersClient.cs index e258722c26..31d41f23ba 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationMembersClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationMembersClient.cs @@ -418,6 +418,27 @@ public IObservable AddOrUpdateOrganizationMembership(str return _client.AddOrUpdateOrganizationMembership(org, user, addOrUpdateRequest).ToObservable(); } + + /// + /// Create an organization invitation for a user + /// + /// + /// This method requires authentication. + /// The authenticated user must be an organization owner. + /// See the API documentation + /// for more information. + /// + /// The login for the organization + /// An instance containing the + /// details of the organization invitation + /// + public IObservable CreateOrganizationInvitation(string org, OrganizationInvitationRequest invitationRequest) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(invitationRequest, nameof(invitationRequest)); + + return _client.CreateOrganizationInvitation(org, invitationRequest).ToObservable(); + } /// /// Remove a user's membership with an organization. From cae0bc82632c44ef912a8667cf4d93701a47d3d9 Mon Sep 17 00:00:00 2001 From: Skye McLeman <118782658+skyemcleman@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:39:11 +1100 Subject: [PATCH 4/4] Add tests for IObservable create org invitation --- ...bservableOrganizationMembersClientTests.cs | 95 ++++++++++++++++++- ...bservableOrganizationMembersClientTests.cs | 27 ++++++ 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/Octokit.Tests.Integration/Reactive/ObservableOrganizationMembersClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableOrganizationMembersClientTests.cs index 6095584ba3..aed9bcf5b7 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableOrganizationMembersClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableOrganizationMembersClientTests.cs @@ -1,7 +1,9 @@ -using System.Reactive.Linq; +using System; +using System.Reactive.Linq; using System.Reactive.Threading.Tasks; using System.Threading.Tasks; using Octokit.Reactive; +using Octokit.Tests.Helpers; using Octokit.Tests.Integration.Helpers; using Xunit; @@ -62,6 +64,97 @@ public async Task ReturnsUsersPendingAdminOrganizationMembership() await _client.RemoveOrganizationMembership(Helper.Organization, "alfhenrik-test-2"); } } + + public class TheCreateOrganizationInvitationMethod + { + readonly IGitHubClient _gitHub; + readonly ObservableOrganizationMembersClient _client; + + public TheCreateOrganizationInvitationMethod() + { + _gitHub = Helper.GetAuthenticatedClient(); + _client = new ObservableOrganizationMembersClient(_gitHub); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationViaUserId() + { + var user = await _gitHub.User.Get("alfhenrik-test-2"); + + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id); + var organizationMembershipInvitation = await _client.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal("alfhenrik-test-2", organizationMembershipInvitation.Login); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + + await _client.RemoveOrganizationMembership(Helper.Organization, "alfhenrik-test-2"); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationViaUserEmail() + { + var email = RandomEmailGenerator.GenerateRandomEmail(); + + var organizationInvitationRequest = new OrganizationInvitationRequest(email); + var organizationMembershipInvitation = await _client.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal(email, organizationMembershipInvitation.Email); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + + await _client.CancelOrganizationInvitation(Helper.Organization, organizationMembershipInvitation.Id); + } + + [OrganizationTest] + public async Task ThrowsApiValidationExceptionForCurrentOrganizationMembers() + { + var user = await _gitHub.User.Get(Helper.UserName); + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id); + + await Assert.ThrowsAsync(() => _client.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest).ToTask()); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationSingleTeam() + { + var user = await _gitHub.User.Get("alfhenrik-test-2"); + + var team1 = await _gitHub.Organization.Team.Create(Helper.Organization, new NewTeam("TestTeam1")); + + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id, new int[] {team1.Id}); + var organizationMembershipInvitation = await _client.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal("alfhenrik-test-2", organizationMembershipInvitation.Login); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + Assert.Equal(1, organizationMembershipInvitation.TeamCount); + + await _gitHub.Organization.Team.Delete(Helper.Organization, team1.Slug); + await _client.RemoveOrganizationMembership(Helper.Organization, "alfhenrik-test-2"); + } + + [OrganizationTest] + public async Task ReturnsOrganizationMembershipInvitationMultipleTeams() + { + var user = await _gitHub.User.Get("alfhenrik-test-2"); + + var team1 = await _gitHub.Organization.Team.Create(Helper.Organization, new NewTeam("TestTeam1")); + var team2 = await _gitHub.Organization.Team.Create(Helper.Organization, new NewTeam("TestTeam2")); + + var organizationInvitationRequest = new OrganizationInvitationRequest(user.Id, new int[] {team1.Id, team2.Id}); + var organizationMembershipInvitation = await _client.CreateOrganizationInvitation(Helper.Organization, organizationInvitationRequest); + + Assert.Equal("alfhenrik-test-2", organizationMembershipInvitation.Login); + Assert.Equal(OrganizationMembershipRole.DirectMember, organizationMembershipInvitation.Role.Value); + Assert.Equal(Helper.UserName, organizationMembershipInvitation.Inviter.Login); + Assert.Equal(2, organizationMembershipInvitation.TeamCount); + + await _gitHub.Organization.Team.Delete(Helper.Organization, team1.Slug); + await _gitHub.Organization.Team.Delete(Helper.Organization, team2.Slug); + await _client.RemoveOrganizationMembership(Helper.Organization, "alfhenrik-test-2"); + } + } public class TheRemoveOrganizationMembershipMethod { diff --git a/Octokit.Tests/Reactive/ObservableOrganizationMembersClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationMembersClientTests.cs index 6e3e44b435..1a03d209d1 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationMembersClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationMembersClientTests.cs @@ -361,6 +361,33 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => client.AddOrUpdateOrganizationMembership("org", "username", null).ToTask()); } } + + public class TheCreateOrganizationInvitationMethod + { + [Fact] + public void CreateOrganizationInvitationFromClientOrganizationMember() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationMembersClient(gitHubClient); + + var organizationInvitationRequest = new OrganizationInvitationRequest(1); + client.CreateOrganizationInvitation("org", organizationInvitationRequest); + + gitHubClient.Organization.Member.Received().CreateOrganizationInvitation("org", organizationInvitationRequest); + } + + [Fact] + public async Task EnsureNonNullArguments() + { + var client = new ObservableOrganizationMembersClient(Substitute.For()); + + var organizationInvitationRequest = new OrganizationInvitationRequest(1); + + await Assert.ThrowsAsync(() => client.CreateOrganizationInvitation(null, organizationInvitationRequest).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrganizationInvitation("", organizationInvitationRequest).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrganizationInvitation("org", null).ToTask()); + } + } public class TheDeleteOrganizationMembershipMethod {