mirror of
https://github.com/bitwarden/server.git
synced 2024-11-23 12:25:16 +01:00
785e788cb6
* Increase organization max seat size from 30k to 2b (#1274) * Increase organization max seat size from 30k to 2b * PR review. Do not modify unless state matches expected * Organization sync simultaneous event reporting (#1275) * Split up azure messages according to max size * Allow simultaneous login of organization user events * Early resolve small event lists * Clarify logic Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Improve readability This comes at the cost of multiple serializations, but the improvement in wire-time should more than make up for this on message where serialization time matters Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Queue emails (#1286) * Extract common Azure queue methods * Do not use internal entity framework namespace * Prefer IEnumerable to IList unless needed All of these implementations were just using `Count == 1`, which is easily replicated. This will be used when abstracting Azure queues * Add model for azure queue message * Abstract Azure queue for reuse * Creat service to enqueue mail messages for later processing Azure queue mail service uses Azure queues. Blocking just blocks until all the work is done -- This is how emailing works today * Provide mail queue service to DI * Queue organization invite emails for later processing All emails can later be added to this queue * Create Admin hosted service to process enqueued mail messages * Prefer constructors to static generators * Mass delete organization users (#1287) * Add delete many to Organization Users * Correct formatting * Remove erroneous migration * Clarify parameter name * Formatting fixes * Simplify bump account revision sproc * Formatting fixes * Match file names to objects * Indicate if large import is expected * Early pull all existing users we were planning on inviting (#1290) * Early pull all existing users we were planning on inviting * Improve sproc name * Batch upsert org users (#1289) * Add UpsertMany sprocs to OrganizationUser * Add method to create TVPs from any object. Uses DbOrder attribute to generate. Sproc will fail unless TVP column order matches that of the db type * Combine migrations * Correct formatting * Include sql objects in sql project * Keep consisten parameter names * Batch deletes for performance * Correct formatting * consolidate migrations * Use batch methods in OrganizationImport * Declare @BatchSize * Transaction names limited to 32 chars Drop sproc before creating it if it exists * Update import tests * Allow for more users in org upgrades * Fix formatting * Improve class hierarchy structure * Use name tuple types * Fix formatting * Front load all reflection * Format constructor * Simplify ToTvp as class-specific extension Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com>
514 lines
29 KiB
C#
514 lines
29 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Bit.Core.Models.Data;
|
|
using Bit.Core.Models.Table;
|
|
using Bit.Core.Models.Business;
|
|
using Bit.Core.Repositories;
|
|
using Bit.Core.Services;
|
|
using NSubstitute;
|
|
using Xunit;
|
|
using Bit.Core.Test.AutoFixture;
|
|
using Bit.Core.Exceptions;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Test.AutoFixture.Attributes;
|
|
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
|
|
using System.Text.Json;
|
|
using Organization = Bit.Core.Models.Table.Organization;
|
|
using System.Linq;
|
|
|
|
namespace Bit.Core.Test.Services
|
|
{
|
|
public class OrganizationServiceTests
|
|
{
|
|
// [Fact]
|
|
[Theory, PaidOrganizationAutoData]
|
|
public async Task OrgImportCreateNewUsers(SutProvider<OrganizationService> sutProvider, Guid userId,
|
|
Organization org, List<OrganizationUserUserDetails> existingUsers, List<ImportedOrganizationUser> newUsers)
|
|
{
|
|
org.UseDirectory = true;
|
|
newUsers.Add(new ImportedOrganizationUser
|
|
{
|
|
Email = existingUsers.First().Email,
|
|
ExternalId = existingUsers.First().ExternalId
|
|
});
|
|
var expectedNewUsersCount = newUsers.Count - 1;
|
|
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
|
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id)
|
|
.Returns(existingUsers);
|
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetCountByOrganizationIdAsync(org.Id)
|
|
.Returns(existingUsers.Count);
|
|
|
|
await sutProvider.Sut.ImportAsync(org.Id, userId, null, newUsers, null, false);
|
|
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
|
|
.UpsertAsync(default);
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
|
|
.UpsertManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == 0));
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
|
|
.CreateAsync(default);
|
|
|
|
// Create new users
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
|
|
.CreateManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == expectedNewUsersCount));
|
|
await sutProvider.GetDependency<IMailService>().Received(1)
|
|
.BulkSendOrganizationInviteEmailAsync(org.Name,
|
|
Arg.Is<IEnumerable<(OrganizationUser, string)>>(messages => messages.Count() == expectedNewUsersCount));
|
|
|
|
// Send events
|
|
await sutProvider.GetDependency<IEventService>().Received(1)
|
|
.LogOrganizationUserEventsAsync(Arg.Is<IEnumerable<(OrganizationUser, EventType, DateTime?)>>(events =>
|
|
events.Count() == expectedNewUsersCount));
|
|
await sutProvider.GetDependency<IReferenceEventService>().Received(1)
|
|
.RaiseEventAsync(Arg.Is<ReferenceEvent>(referenceEvent =>
|
|
referenceEvent.Type == ReferenceEventType.InvitedUsers && referenceEvent.Id == org.Id &&
|
|
referenceEvent.Users == expectedNewUsersCount));
|
|
}
|
|
|
|
[Theory, PaidOrganizationAutoData]
|
|
public async Task OrgImportCreateNewUsersAndMarryExistingUser(SutProvider<OrganizationService> sutProvider,
|
|
Guid userId, Organization org, List<OrganizationUserUserDetails> existingUsers,
|
|
List<ImportedOrganizationUser> newUsers)
|
|
{
|
|
org.UseDirectory = true;
|
|
var reInvitedUser = existingUsers.First();
|
|
reInvitedUser.ExternalId = null;
|
|
newUsers.Add(new ImportedOrganizationUser
|
|
{
|
|
Email = reInvitedUser.Email,
|
|
ExternalId = reInvitedUser.Email,
|
|
});
|
|
var expectedNewUsersCount = newUsers.Count - 1;
|
|
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
|
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id)
|
|
.Returns(existingUsers);
|
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetCountByOrganizationIdAsync(org.Id)
|
|
.Returns(existingUsers.Count);
|
|
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(reInvitedUser.Id)
|
|
.Returns(new OrganizationUser { Id = reInvitedUser.Id });
|
|
|
|
await sutProvider.Sut.ImportAsync(org.Id, userId, null, newUsers, null, false);
|
|
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
|
|
.UpsertAsync(default);
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
|
|
.CreateAsync(default);
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
|
|
.CreateAsync(default, default);
|
|
|
|
// Upserted existing user
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
|
|
.UpsertManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == 1));
|
|
|
|
// Created and invited new users
|
|
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
|
|
.CreateManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == expectedNewUsersCount));
|
|
await sutProvider.GetDependency<IMailService>().Received(1)
|
|
.BulkSendOrganizationInviteEmailAsync(org.Name,
|
|
Arg.Is<IEnumerable<(OrganizationUser, string)>>(messages => messages.Count() == expectedNewUsersCount));
|
|
|
|
// Sent events
|
|
await sutProvider.GetDependency<IEventService>().Received(1)
|
|
.LogOrganizationUserEventsAsync(Arg.Is<IEnumerable<(OrganizationUser, EventType, DateTime?)>>(events =>
|
|
events.Where(e => e.Item2 == EventType.OrganizationUser_Invited).Count() == expectedNewUsersCount));
|
|
await sutProvider.GetDependency<IReferenceEventService>().Received(1)
|
|
.RaiseEventAsync(Arg.Is<ReferenceEvent>(referenceEvent =>
|
|
referenceEvent.Type == ReferenceEventType.InvitedUsers && referenceEvent.Id == org.Id &&
|
|
referenceEvent.Users == expectedNewUsersCount));
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task UpgradePlan_OrganizationIsNull_Throws(Guid organizationId, OrganizationUpgrade upgrade,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(Task.FromResult<Organization>(null));
|
|
var exception = await Assert.ThrowsAsync<NotFoundException>(
|
|
() => sutProvider.Sut.UpgradePlanAsync(organizationId, upgrade));
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task UpgradePlan_GatewayCustomIdIsNull_Throws(Organization organization, OrganizationUpgrade upgrade,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
organization.GatewayCustomerId = string.Empty;
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
|
|
Assert.Contains("no payment method", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task UpgradePlan_AlreadyInPlan_Throws(Organization organization, OrganizationUpgrade upgrade,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
upgrade.Plan = organization.PlanType;
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
|
|
Assert.Contains("already on this plan", exception.Message);
|
|
}
|
|
|
|
[Theory, PaidOrganizationAutoData]
|
|
public async Task UpgradePlan_UpgradeFromPaidPlan_Throws(Organization organization, OrganizationUpgrade upgrade,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
|
|
Assert.Contains("can only upgrade", exception.Message);
|
|
}
|
|
|
|
[Theory]
|
|
[FreeOrganizationUpgradeAutoData]
|
|
public async Task UpgradePlan_Passes(Organization organization, OrganizationUpgrade upgrade,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
await sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade);
|
|
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).ReplaceAsync(organization);
|
|
}
|
|
|
|
[Theory]
|
|
[OrganizationInviteAutoData]
|
|
public async Task InviteUser_NoEmails_Throws(Organization organization, OrganizationUser invitor,
|
|
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
invite.Emails = null;
|
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
await Assert.ThrowsAsync<NotFoundException>(
|
|
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
|
|
}
|
|
|
|
[Theory]
|
|
[OrganizationInviteAutoData(
|
|
inviteeUserType: (int)OrganizationUserType.Owner,
|
|
invitorUserType: (int)OrganizationUserType.Admin
|
|
)]
|
|
public async Task InviteUser_NonOwnerConfiguringOwner_Throws(Organization organization, OrganizationUserInvite invite,
|
|
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
|
organizationUserRepository.GetManyByUserAsync(invitor.Id).Returns(new List<OrganizationUser> { invitor });
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
|
|
Assert.Contains("only an owner", exception.Message.ToLowerInvariant());
|
|
}
|
|
|
|
[Theory]
|
|
[OrganizationInviteAutoData(
|
|
inviteeUserType: (int)OrganizationUserType.Custom,
|
|
invitorUserType: (int)OrganizationUserType.Admin
|
|
)]
|
|
public async Task InviteUser_NonAdminConfiguringAdmin_Throws(Organization organization, OrganizationUserInvite invite,
|
|
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
|
organizationUserRepository.GetManyByUserAsync(invitor.Id).Returns(new List<OrganizationUser> { invitor });
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
|
|
Assert.Contains("only owners and admins", exception.Message.ToLowerInvariant());
|
|
}
|
|
|
|
[Theory]
|
|
[OrganizationInviteAutoData(
|
|
inviteeUserType: (int)OrganizationUserType.Manager,
|
|
invitorUserType: (int)OrganizationUserType.Custom
|
|
)]
|
|
public async Task InviteUser_CustomUserWithoutManageUsersConfiguringUser_Throws(Organization organization, OrganizationUserInvite invite,
|
|
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
invitor.Permissions = JsonSerializer.Serialize(new Permissions() { ManageUsers = false },
|
|
new JsonSerializerOptions
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
});
|
|
|
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
|
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
|
|
Assert.Contains("account does not have permission", exception.Message.ToLowerInvariant());
|
|
}
|
|
|
|
[Theory]
|
|
[OrganizationInviteAutoData(
|
|
inviteeUserType: (int)OrganizationUserType.Admin,
|
|
invitorUserType: (int)OrganizationUserType.Custom
|
|
)]
|
|
public async Task InviteUser_CustomUserConfiguringAdmin_Throws(Organization organization, OrganizationUserInvite invite,
|
|
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
invitor.Permissions = JsonSerializer.Serialize(new Permissions() { ManageUsers = true },
|
|
new JsonSerializerOptions
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
});
|
|
|
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
|
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
|
|
Assert.Contains("can not manage admins", exception.Message.ToLowerInvariant());
|
|
}
|
|
|
|
[Theory]
|
|
[OrganizationInviteAutoData(
|
|
inviteeUserType: (int)OrganizationUserType.User,
|
|
invitorUserType: (int)OrganizationUserType.Owner
|
|
)]
|
|
public async Task InviteUser_NoPermissionsObject_Passes(Organization organization, OrganizationUserInvite invite,
|
|
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
invite.Permissions = null;
|
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
var eventService = sutProvider.GetDependency<IEventService>();
|
|
|
|
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
|
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
|
|
|
|
await sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite);
|
|
}
|
|
|
|
[Theory]
|
|
[OrganizationInviteAutoData(
|
|
inviteeUserType: (int)OrganizationUserType.User,
|
|
invitorUserType: (int)OrganizationUserType.Custom
|
|
)]
|
|
public async Task InviteUser_Passes(Organization organization, OrganizationUserInvite invite,
|
|
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
invitor.Permissions = JsonSerializer.Serialize(new Permissions() { ManageUsers = true },
|
|
new JsonSerializerOptions
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
});
|
|
|
|
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
var eventService = sutProvider.GetDependency<IEventService>();
|
|
|
|
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
|
|
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
|
|
|
|
await sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task SaveUser_NoUserId_Throws(OrganizationUser user, Guid? savingUserId,
|
|
IEnumerable<SelectionReadOnly> collections, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
user.Id = default(Guid);
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.SaveUserAsync(user, savingUserId, collections));
|
|
Assert.Contains("invite the user first", exception.Message.ToLowerInvariant());
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task SaveUser_NoChangeToData_Throws(OrganizationUser user, Guid? savingUserId,
|
|
IEnumerable<SelectionReadOnly> collections, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
organizationUserRepository.GetByIdAsync(user.Id).Returns(user);
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.SaveUserAsync(user, savingUserId, collections));
|
|
Assert.Contains("make changes before saving", exception.Message.ToLowerInvariant());
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task SaveUser_Passes(OrganizationUser oldUserData, OrganizationUser newUserData,
|
|
IEnumerable<SelectionReadOnly> collections, OrganizationUser savingUser, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
newUserData.Id = oldUserData.Id;
|
|
newUserData.UserId = oldUserData.UserId;
|
|
newUserData.OrganizationId = savingUser.OrganizationId = oldUserData.OrganizationId;
|
|
savingUser.Type = OrganizationUserType.Owner;
|
|
organizationUserRepository.GetByIdAsync(oldUserData.Id).Returns(oldUserData);
|
|
organizationUserRepository.GetManyByOrganizationAsync(savingUser.OrganizationId, OrganizationUserType.Owner)
|
|
.Returns(new List<OrganizationUser> { savingUser });
|
|
organizationUserRepository.GetManyByUserAsync(savingUser.UserId.Value).Returns(new List<OrganizationUser> { savingUser });
|
|
|
|
await sutProvider.Sut.SaveUserAsync(newUserData, savingUser.UserId, collections);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUser_InvalidUser(OrganizationUser organizationUser, OrganizationUser deletingUser,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationUserRepository.GetByIdAsync(organizationUser.Id).Returns(organizationUser);
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUserAsync(Guid.NewGuid(), organizationUser.Id, deletingUser.UserId));
|
|
Assert.Contains("User not valid.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUser_RemoveYourself(OrganizationUser deletingUser, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationUserRepository.GetByIdAsync(deletingUser.Id).Returns(deletingUser);
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUserAsync(deletingUser.OrganizationId, deletingUser.Id, deletingUser.UserId));
|
|
Assert.Contains("You cannot remove yourself.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUser_NonOwnerRemoveOwner(OrganizationUser organizationUser, OrganizationUser deletingUser,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationUser.OrganizationId = deletingUser.OrganizationId;
|
|
organizationUser.Type = OrganizationUserType.Owner;
|
|
organizationUserRepository.GetByIdAsync(organizationUser.Id).Returns(organizationUser);
|
|
organizationUserRepository.GetManyByUserAsync(deletingUser.UserId.Value).Returns(new[] { deletingUser });
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUserAsync(deletingUser.OrganizationId, organizationUser.Id, deletingUser.UserId));
|
|
Assert.Contains("Only owners can delete other owners.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUser_LastOwner(OrganizationUser organizationUser, OrganizationUser deletingUser,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
organizationUser.OrganizationId = deletingUser.OrganizationId;
|
|
organizationUser.Type = OrganizationUserType.Owner;
|
|
organizationUserRepository.GetByIdAsync(organizationUser.Id).Returns(organizationUser);
|
|
organizationUserRepository.GetManyByOrganizationAsync(deletingUser.OrganizationId, OrganizationUserType.Owner)
|
|
.Returns(new[] { organizationUser });
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUserAsync(deletingUser.OrganizationId, organizationUser.Id, null));
|
|
Assert.Contains("Organization must have at least one confirmed owner.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUser_Success(OrganizationUser organizationUser, OrganizationUser deletingUser,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
deletingUser.Type = OrganizationUserType.Owner;
|
|
deletingUser.Status = OrganizationUserStatusType.Confirmed;
|
|
organizationUser.OrganizationId = deletingUser.OrganizationId;
|
|
organizationUserRepository.GetByIdAsync(organizationUser.Id).Returns(organizationUser);
|
|
organizationUserRepository.GetByIdAsync(deletingUser.Id).Returns(deletingUser);
|
|
organizationUserRepository.GetManyByUserAsync(deletingUser.UserId.Value).Returns(new[] { deletingUser });
|
|
organizationUserRepository.GetManyByOrganizationAsync(deletingUser.OrganizationId, OrganizationUserType.Owner)
|
|
.Returns(new[] {deletingUser, organizationUser});
|
|
|
|
await sutProvider.Sut.DeleteUserAsync(deletingUser.OrganizationId, organizationUser.Id, deletingUser.UserId);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUsers_FilterInvalid(OrganizationUser organizationUser, OrganizationUser deletingUser,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
var organizationUsers = new[] { organizationUser };
|
|
var organizationUserIds = organizationUsers.Select(u => u.Id);
|
|
organizationUserRepository.GetManyAsync(organizationUserIds).Returns(organizationUsers);
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUsersAsync(deletingUser.OrganizationId, organizationUserIds, deletingUser.UserId));
|
|
Assert.Contains("Users invalid.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUsers_RemoveYourself(OrganizationUser deletingUser, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
var organizationUsers = new[] { deletingUser };
|
|
var organizationUserIds = organizationUsers.Select(u => u.Id);
|
|
organizationUserRepository.GetManyAsync(organizationUserIds).Returns(organizationUsers);
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUsersAsync(deletingUser.OrganizationId, organizationUserIds, deletingUser.UserId));
|
|
Assert.Contains("You cannot remove yourself.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUsers_NonOwnerRemoveOwner(OrganizationUser deletingUser, OrganizationUser orgUser1, OrganizationUser orgUser2,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
deletingUser.Type = OrganizationUserType.Admin;
|
|
orgUser1.OrganizationId = orgUser2.OrganizationId = deletingUser.OrganizationId;
|
|
var organizationUsers = new[] { orgUser1, orgUser2 };
|
|
var organizationUserIds = organizationUsers.Select(u => u.Id);
|
|
organizationUserRepository.GetManyAsync(organizationUserIds).Returns(organizationUsers);
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUsersAsync(deletingUser.OrganizationId, organizationUserIds, deletingUser.UserId));
|
|
Assert.Contains("Only owners can delete other owners.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUsers_LastOwner(OrganizationUser orgUser, SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
orgUser.Type = OrganizationUserType.Owner;
|
|
orgUser.Status = OrganizationUserStatusType.Confirmed;
|
|
var organizationUsers = new[] { orgUser };
|
|
var organizationUserIds = organizationUsers.Select(u => u.Id);
|
|
organizationUserRepository.GetManyAsync(organizationUserIds).Returns(organizationUsers);
|
|
organizationUserRepository.GetManyByOrganizationAsync(orgUser.OrganizationId, OrganizationUserType.Owner).Returns(organizationUsers);
|
|
|
|
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
|
() => sutProvider.Sut.DeleteUsersAsync(orgUser.OrganizationId, organizationUserIds, null));
|
|
Assert.Contains("Organization must have at least one confirmed owner.", exception.Message);
|
|
}
|
|
|
|
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
|
|
public async Task DeleteUsers_Success(OrganizationUser deletingUser, OrganizationUser orgUser1, OrganizationUser orgUser2,
|
|
SutProvider<OrganizationService> sutProvider)
|
|
{
|
|
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
|
|
|
deletingUser.Type = OrganizationUserType.Owner;
|
|
deletingUser.Status = OrganizationUserStatusType.Confirmed;
|
|
orgUser1.OrganizationId = orgUser2.OrganizationId = deletingUser.OrganizationId;
|
|
orgUser1.Type = OrganizationUserType.Owner;
|
|
var organizationUsers = new[] { orgUser1, orgUser2 };
|
|
var organizationUserIds = organizationUsers.Select(u => u.Id);
|
|
organizationUserRepository.GetManyAsync(organizationUserIds).Returns(organizationUsers);
|
|
organizationUserRepository.GetByIdAsync(deletingUser.Id).Returns(deletingUser);
|
|
organizationUserRepository.GetManyByUserAsync(deletingUser.UserId.Value).Returns(new[] { deletingUser });
|
|
organizationUserRepository.GetManyByOrganizationAsync(deletingUser.OrganizationId, OrganizationUserType.Owner)
|
|
.Returns(new[] {deletingUser, orgUser1});
|
|
|
|
await sutProvider.Sut.DeleteUsersAsync(deletingUser.OrganizationId, organizationUserIds, deletingUser.UserId);
|
|
}
|
|
}
|
|
}
|