Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add create organization invitation via email #2895

Merged
merged 4 commits into from Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions Octokit.Reactive/Clients/IObservableOrganizationMembersClient.cs
Expand Up @@ -304,6 +304,21 @@ public interface IObservableOrganizationMembersClient
/// <returns></returns>
IObservable<OrganizationMembership> AddOrUpdateOrganizationMembership(string org, string user, OrganizationMembershipUpdate addOrUpdateRequest);

/// <summary>
/// Create an organization invitation for a user
/// </summary>
/// <remarks>
/// This method requires authentication.
/// The authenticated user must be an organization owner.
/// See the <a href="https://developer.github.com/v3/orgs/members/#create-an-organization-invitation">API documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The login for the organization</param>
/// <param name="invitationRequest">An <see cref="OrganizationInvitationRequest"/> instance containing the
/// details of the organization invitation</param>
/// <returns></returns>
IObservable<OrganizationMembershipInvitation> CreateOrganizationInvitation(string org, OrganizationInvitationRequest invitationRequest);

/// <summary>
/// Remove a user's membership with an organization.
/// </summary>
Expand Down
21 changes: 21 additions & 0 deletions Octokit.Reactive/Clients/ObservableOrganizationMembersClient.cs
Expand Up @@ -418,6 +418,27 @@ public IObservable<OrganizationMembership> AddOrUpdateOrganizationMembership(str

return _client.AddOrUpdateOrganizationMembership(org, user, addOrUpdateRequest).ToObservable();
}

/// <summary>
/// Create an organization invitation for a user
/// </summary>
/// <remarks>
/// This method requires authentication.
/// The authenticated user must be an organization owner.
/// See the <a href="https://developer.github.com/v3/orgs/members/#create-an-organization-invitation">API documentation</a>
/// for more information.
/// </remarks>
/// <param name="org">The login for the organization</param>
/// <param name="invitationRequest">An <see cref="OrganizationInvitationRequest"/> instance containing the
/// details of the organization invitation</param>
/// <returns></returns>
public IObservable<OrganizationMembershipInvitation> CreateOrganizationInvitation(string org, OrganizationInvitationRequest invitationRequest)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNull(invitationRequest, nameof(invitationRequest));

return _client.CreateOrganizationInvitation(org, invitationRequest).ToObservable();
}

/// <summary>
/// Remove a user's membership with an organization.
Expand Down
@@ -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;

Expand Down Expand Up @@ -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<ApiValidationException>(() => _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;
Expand Down
@@ -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;

Expand Down Expand Up @@ -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<ApiValidationException>(() => _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
{
Expand Down
28 changes: 28 additions & 0 deletions Octokit.Tests/Clients/OrganizationMembersClientTests.cs
Expand Up @@ -2,6 +2,7 @@
using System.Net;
using System.Threading.Tasks;
using NSubstitute;
using NSubstitute.Core.DependencyInjection;
using Octokit.Internal;
using Xunit;

Expand Down Expand Up @@ -562,6 +563,33 @@ public async Task EnsureNonNullArguments()
}
}

public class TheCreateOrganizationInvitationMethod
{
[Fact]
public void PostsToTheCorrectUrl()
{
var organizationInvitationRequest = new OrganizationInvitationRequest("email");

var connection = Substitute.For<IApiConnection>();
var client = new OrganizationMembersClient(connection);

client.CreateOrganizationInvitation("org", organizationInvitationRequest);

connection.Received().Post<OrganizationMembershipInvitation>(Arg.Is<Uri>(u => u.ToString() == "orgs/org/invitations"), Arg.Any<object>());
}

[Fact]
public async Task EnsureNonNullArguments()
{
var organizationInvitationRequest = new OrganizationInvitationRequest("email");
var client = new OrganizationMembersClient(Substitute.For<IApiConnection>());

await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrganizationInvitation(null, organizationInvitationRequest));
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrganizationInvitation("", organizationInvitationRequest));
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrganizationInvitation("org", null));
}
}

public class TheDeleteOrganizationMembershipMethod
{
[Fact]
Expand Down
15 changes: 15 additions & 0 deletions 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";
}
}
}
35 changes: 35 additions & 0 deletions 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);
}
}
}
}
27 changes: 27 additions & 0 deletions Octokit.Tests/Reactive/ObservableOrganizationMembersClientTests.cs
Expand Up @@ -361,6 +361,33 @@ public async Task EnsuresNonNullArguments()
await Assert.ThrowsAsync<ArgumentNullException>(() => client.AddOrUpdateOrganizationMembership("org", "username", null).ToTask());
}
}

public class TheCreateOrganizationInvitationMethod
{
[Fact]
public void CreateOrganizationInvitationFromClientOrganizationMember()
{
var gitHubClient = Substitute.For<IGitHubClient>();
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<IGitHubClient>());

var organizationInvitationRequest = new OrganizationInvitationRequest(1);

await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrganizationInvitation(null, organizationInvitationRequest).ToTask());
await Assert.ThrowsAsync<ArgumentException>(() => client.CreateOrganizationInvitation("", organizationInvitationRequest).ToTask());
await Assert.ThrowsAsync<ArgumentNullException>(() => client.CreateOrganizationInvitation("org", null).ToTask());
}
}

public class TheDeleteOrganizationMembershipMethod
{
Expand Down