mirror of
https://github.com/bitwarden/server.git
synced 2025-05-10 06:02:24 -05:00
refactor groups logic
This commit is contained in:
parent
f76d6fde62
commit
15cff6c507
@ -0,0 +1,12 @@
|
|||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Models.Business;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Data.Organizations;
|
||||||
|
|
||||||
|
public class OrganizationGroupImportData
|
||||||
|
{
|
||||||
|
public IEnumerable<ImportedGroup> Groups { get; set; }
|
||||||
|
public ICollection<Group> ExistingGroups { get; set; }
|
||||||
|
public IEnumerable<Group> ExistingExternalGroups { get; set; }
|
||||||
|
public IDictionary<string, ImportedGroup> GroupsDict { get; set; }
|
||||||
|
}
|
@ -10,6 +10,7 @@ using Bit.Core.Enums;
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Models.Commands;
|
using Bit.Core.Models.Commands;
|
||||||
|
using Bit.Core.Models.Data.Organizations;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
@ -60,8 +61,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
IEnumerable<ImportedOrganizationUser> newUsers,
|
IEnumerable<ImportedOrganizationUser> newUsers,
|
||||||
IEnumerable<string> removeUserExternalIds,
|
IEnumerable<string> removeUserExternalIds,
|
||||||
bool overwriteExisting,
|
bool overwriteExisting,
|
||||||
EventSystemUser eventSystemUser
|
EventSystemUser eventSystemUser)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
var organization = await GetOrgById(organizationId);
|
var organization = await GetOrgById(organizationId);
|
||||||
if (organization == null)
|
if (organization == null)
|
||||||
@ -76,27 +76,27 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
|
|
||||||
var existingUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId);
|
var existingUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId);
|
||||||
|
|
||||||
var importData = new OrganizationUserImportData
|
var importUserData = new OrganizationUserImportData
|
||||||
{
|
{
|
||||||
NewUsersSet = new HashSet<string>(newUsers?.Select(u => u.ExternalId) ?? new List<string>()),
|
NewUsersSet = new HashSet<string>(newUsers?.Select(u => u.ExternalId) ?? new List<string>()),
|
||||||
ExistingUsers = existingUsers,
|
ExistingUsers = existingUsers,
|
||||||
ExistingExternalUsers = GetExistingExternalUsers(existingUsers),
|
ExistingExternalUsers = GetExistingExternalUsers(existingUsers),
|
||||||
ExistingExternalUsersIdDict = GetExistingExternalUsersIdDict(existingUsers)
|
ExistingExternalUsersIdDict = GetExistingExternalUsers(existingUsers).ToDictionary(u => u.ExternalId, u => u.Id)
|
||||||
};
|
};
|
||||||
|
|
||||||
var events = new List<(OrganizationUserUserDetails ou, EventType e, DateTime? d)>();
|
var events = new List<(OrganizationUserUserDetails ou, EventType e, DateTime? d)>();
|
||||||
|
|
||||||
// Users
|
// Users
|
||||||
await RemoveExistingExternalUsers(removeUserExternalIds, events, importData);
|
await RemoveExistingExternalUsers(removeUserExternalIds, events, importUserData);
|
||||||
if (overwriteExisting)
|
if (overwriteExisting)
|
||||||
{
|
{
|
||||||
await OverwriteExisting(events, importData);
|
await OverwriteExisting(events, importUserData);
|
||||||
}
|
}
|
||||||
await RemoveExistingUsers(existingUsers, newUsers, organization, importData);
|
await RemoveExistingUsers(existingUsers, newUsers, organization, importUserData);
|
||||||
await AddNewUsers(organization, newUsers, eventSystemUser, importData);
|
await AddNewUsers(organization, newUsers, eventSystemUser, importUserData);
|
||||||
|
|
||||||
// Groups
|
// Groups
|
||||||
await ImportGroups(organization, groups, eventSystemUser, importData);
|
await ImportGroups(organization, groups, eventSystemUser, importUserData);
|
||||||
|
|
||||||
await _eventService.LogOrganizationUserEventsAsync(events.Select(e => (e.ou, e.e, eventSystemUser, e.d)));
|
await _eventService.LogOrganizationUserEventsAsync(events.Select(e => (e.ou, e.e, eventSystemUser, e.d)));
|
||||||
await _referenceEventService.RaiseEventAsync(
|
await _referenceEventService.RaiseEventAsync(
|
||||||
@ -116,20 +116,18 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
await _groupRepository.UpdateUsersAsync(group.Id, users);
|
await _groupRepository.UpdateUsersAsync(group.Id, users);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RemoveExistingExternalUsers(
|
private async Task RemoveExistingExternalUsers(IEnumerable<string> removeUserExternalIds,
|
||||||
IEnumerable<string> removeUserExternalIds,
|
|
||||||
List<(OrganizationUserUserDetails ou, EventType e, DateTime? d)> events,
|
List<(OrganizationUserUserDetails ou, EventType e, DateTime? d)> events,
|
||||||
OrganizationUserImportData importData
|
OrganizationUserImportData importUserData)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
if (!removeUserExternalIds.Any())
|
if (!removeUserExternalIds.Any())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var existingUsersDict = importData.ExistingExternalUsers.ToDictionary(u => u.ExternalId);
|
var existingUsersDict = importUserData.ExistingExternalUsers.ToDictionary(u => u.ExternalId);
|
||||||
var removeUsersSet = new HashSet<string>(removeUserExternalIds)
|
var removeUsersSet = new HashSet<string>(removeUserExternalIds)
|
||||||
.Except(importData.NewUsersSet)
|
.Except(importUserData.NewUsersSet)
|
||||||
.Where(u => existingUsersDict.ContainsKey(u) && existingUsersDict[u].Type != OrganizationUserType.Owner)
|
.Where(u => existingUsersDict.ContainsKey(u) && existingUsersDict[u].Type != OrganizationUserType.Owner)
|
||||||
.Select(u => existingUsersDict[u]);
|
.Select(u => existingUsersDict[u]);
|
||||||
|
|
||||||
@ -142,12 +140,10 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RemoveExistingUsers(
|
private async Task RemoveExistingUsers(IEnumerable<OrganizationUserUserDetails> existingUsers,
|
||||||
IEnumerable<OrganizationUserUserDetails> existingUsers,
|
|
||||||
IEnumerable<ImportedOrganizationUser> newUsers,
|
IEnumerable<ImportedOrganizationUser> newUsers,
|
||||||
Organization organization,
|
Organization organization,
|
||||||
OrganizationUserImportData importData
|
OrganizationUserImportData importUserData)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
if (!newUsers.Any())
|
if (!newUsers.Any())
|
||||||
{
|
{
|
||||||
@ -169,7 +165,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
{
|
{
|
||||||
orgUser.ExternalId = newUsersEmailsDict[user].ExternalId;
|
orgUser.ExternalId = newUsersEmailsDict[user].ExternalId;
|
||||||
usersToUpsert.Add(orgUser);
|
usersToUpsert.Add(orgUser);
|
||||||
importData.ExistingExternalUsersIdDict.Add(orgUser.ExternalId, orgUser.Id);
|
importUserData.ExistingExternalUsersIdDict.Add(orgUser.ExternalId, orgUser.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await _organizationUserRepository.UpsertManyAsync(usersToUpsert);
|
await _organizationUserRepository.UpsertManyAsync(usersToUpsert);
|
||||||
@ -178,11 +174,11 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
private async Task AddNewUsers(Organization organization,
|
private async Task AddNewUsers(Organization organization,
|
||||||
IEnumerable<ImportedOrganizationUser> newUsers,
|
IEnumerable<ImportedOrganizationUser> newUsers,
|
||||||
EventSystemUser eventSystemUser,
|
EventSystemUser eventSystemUser,
|
||||||
OrganizationUserImportData importData)
|
OrganizationUserImportData importUserData)
|
||||||
{
|
{
|
||||||
|
|
||||||
var existingUsersSet = new HashSet<string>(importData.ExistingExternalUsersIdDict.Keys);
|
var existingUsersSet = new HashSet<string>(importUserData.ExistingExternalUsersIdDict.Keys);
|
||||||
var usersToAdd = importData.NewUsersSet.Except(existingUsersSet).ToList();
|
var usersToAdd = importUserData.NewUsersSet.Except(existingUsersSet).ToList();
|
||||||
|
|
||||||
var seatsAvailable = int.MaxValue;
|
var seatsAvailable = int.MaxValue;
|
||||||
var enoughSeatsAvailable = true;
|
var enoughSeatsAvailable = true;
|
||||||
@ -219,11 +215,10 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
|
|
||||||
switch (commandResult)
|
switch (commandResult)
|
||||||
{
|
{
|
||||||
case Success<InviteOrganizationUsersResponse> success:
|
case Success<InviteOrganizationUsersResponse> result:
|
||||||
var result = success.Value;
|
foreach (var u in result.Value.InvitedUsers)
|
||||||
foreach (var u in result.InvitedUsers)
|
|
||||||
{
|
{
|
||||||
importData.ExistingExternalUsersIdDict.Add(u.ExternalId, u.Id);
|
importUserData.ExistingExternalUsersIdDict.Add(u.ExternalId, u.Id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Failure<InviteOrganizationUsersResponse> failure:
|
case Failure<InviteOrganizationUsersResponse> failure:
|
||||||
@ -244,14 +239,13 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
|
|
||||||
private async Task OverwriteExisting(
|
private async Task OverwriteExisting(
|
||||||
List<(OrganizationUserUserDetails ou, EventType e, DateTime? d)> events,
|
List<(OrganizationUserUserDetails ou, EventType e, DateTime? d)> events,
|
||||||
OrganizationUserImportData importData
|
OrganizationUserImportData importUserData)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
// Remove existing external users that are not in new user set
|
// Remove existing external users that are not in new user set
|
||||||
var usersToDelete = importData.ExistingExternalUsers.Where(u =>
|
var usersToDelete = importUserData.ExistingExternalUsers.Where(u =>
|
||||||
u.Type != OrganizationUserType.Owner &&
|
u.Type != OrganizationUserType.Owner &&
|
||||||
!importData.NewUsersSet.Contains(u.ExternalId) &&
|
!importUserData.NewUsersSet.Contains(u.ExternalId) &&
|
||||||
importData.ExistingExternalUsersIdDict.ContainsKey(u.ExternalId));
|
importUserData.ExistingExternalUsersIdDict.ContainsKey(u.ExternalId));
|
||||||
await _organizationUserRepository.DeleteManyAsync(usersToDelete.Select(u => u.Id));
|
await _organizationUserRepository.DeleteManyAsync(usersToDelete.Select(u => u.Id));
|
||||||
events.AddRange(usersToDelete.Select(u => (
|
events.AddRange(usersToDelete.Select(u => (
|
||||||
u,
|
u,
|
||||||
@ -261,15 +255,14 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
);
|
);
|
||||||
foreach (var deletedUser in usersToDelete)
|
foreach (var deletedUser in usersToDelete)
|
||||||
{
|
{
|
||||||
importData.ExistingExternalUsersIdDict.Remove(deletedUser.ExternalId);
|
importUserData.ExistingExternalUsersIdDict.Remove(deletedUser.ExternalId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ImportGroups(Organization organization,
|
private async Task ImportGroups(Organization organization,
|
||||||
IEnumerable<ImportedGroup> groups,
|
IEnumerable<ImportedGroup> groups,
|
||||||
EventSystemUser eventSystemUser,
|
EventSystemUser eventSystemUser,
|
||||||
OrganizationUserImportData importData
|
OrganizationUserImportData importUserData)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!groups.Any())
|
if (!groups.Any())
|
||||||
@ -282,14 +275,25 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
throw new BadRequestException("Organization cannot use groups.");
|
throw new BadRequestException("Organization cannot use groups.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var groupsDict = groups.ToDictionary(g => g.Group.ExternalId);
|
|
||||||
var existingGroups = await _groupRepository.GetManyByOrganizationIdAsync(organization.Id);
|
var existingGroups = await _groupRepository.GetManyByOrganizationIdAsync(organization.Id);
|
||||||
var existingExternalGroups = existingGroups
|
var importGroupData = new OrganizationGroupImportData
|
||||||
.Where(u => !string.IsNullOrWhiteSpace(u.ExternalId)).ToList();
|
{
|
||||||
var existingExternalGroupsDict = existingExternalGroups.ToDictionary(g => g.ExternalId);
|
Groups = groups,
|
||||||
|
GroupsDict = groups.ToDictionary(g => g.Group.ExternalId),
|
||||||
|
ExistingGroups = existingGroups,
|
||||||
|
ExistingExternalGroups = GetExistingExternalGroups(existingGroups)
|
||||||
|
};
|
||||||
|
|
||||||
var newGroups = groups
|
await SaveNewGroups(importGroupData, importUserData, eventSystemUser);
|
||||||
.Where(g => !existingExternalGroupsDict.ContainsKey(g.Group.ExternalId))
|
await UpdateExistingGroups(importGroupData, importUserData, organization, eventSystemUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveNewGroups(OrganizationGroupImportData importGroupData,
|
||||||
|
OrganizationUserImportData importUserData,
|
||||||
|
EventSystemUser eventSystemUser)
|
||||||
|
{
|
||||||
|
var newGroups = importGroupData.Groups
|
||||||
|
.Where(g => !importGroupData.ExistingExternalGroups.ToDictionary(g => g.ExternalId).ContainsKey(g.Group.ExternalId))
|
||||||
.Select(g => g.Group).ToList();
|
.Select(g => g.Group).ToList();
|
||||||
|
|
||||||
var savedGroups = new List<Group>();
|
var savedGroups = new List<Group>();
|
||||||
@ -298,15 +302,21 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
group.CreationDate = group.RevisionDate = DateTime.UtcNow;
|
group.CreationDate = group.RevisionDate = DateTime.UtcNow;
|
||||||
|
|
||||||
savedGroups.Add(await _groupRepository.CreateAsync(group));
|
savedGroups.Add(await _groupRepository.CreateAsync(group));
|
||||||
await UpdateUsersAsync(group, groupsDict[group.ExternalId].ExternalUserIds,
|
await UpdateUsersAsync(group, importGroupData.GroupsDict[group.ExternalId].ExternalUserIds,
|
||||||
importData.ExistingExternalUsersIdDict);
|
importUserData.ExistingExternalUsersIdDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _eventService.LogGroupEventsAsync(
|
await _eventService.LogGroupEventsAsync(
|
||||||
savedGroups.Select(g => (g, EventType.Group_Created, (EventSystemUser?)eventSystemUser, (DateTime?)DateTime.UtcNow)));
|
savedGroups.Select(g => (g, EventType.Group_Created, (EventSystemUser?)eventSystemUser, (DateTime?)DateTime.UtcNow)));
|
||||||
|
}
|
||||||
|
|
||||||
var updateGroups = existingExternalGroups
|
private async Task UpdateExistingGroups(OrganizationGroupImportData importGroupData,
|
||||||
.Where(g => groupsDict.ContainsKey(g.ExternalId))
|
OrganizationUserImportData importUserData,
|
||||||
|
Organization organization,
|
||||||
|
EventSystemUser eventSystemUser)
|
||||||
|
{
|
||||||
|
var updateGroups = importGroupData.ExistingExternalGroups
|
||||||
|
.Where(g => importGroupData.GroupsDict.ContainsKey(g.ExternalId))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (updateGroups.Any())
|
if (updateGroups.Any())
|
||||||
@ -318,7 +328,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
|
|
||||||
foreach (var group in updateGroups)
|
foreach (var group in updateGroups)
|
||||||
{
|
{
|
||||||
var updatedGroup = groupsDict[group.ExternalId].Group;
|
var updatedGroup = importGroupData.GroupsDict[group.ExternalId].Group;
|
||||||
if (group.Name != updatedGroup.Name)
|
if (group.Name != updatedGroup.Name)
|
||||||
{
|
{
|
||||||
group.RevisionDate = DateTime.UtcNow;
|
group.RevisionDate = DateTime.UtcNow;
|
||||||
@ -327,8 +337,8 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
await _groupRepository.ReplaceAsync(group);
|
await _groupRepository.ReplaceAsync(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
await UpdateUsersAsync(group, groupsDict[group.ExternalId].ExternalUserIds,
|
await UpdateUsersAsync(group, importGroupData.GroupsDict[group.ExternalId].ExternalUserIds,
|
||||||
importData.ExistingExternalUsersIdDict,
|
importUserData.ExistingExternalUsersIdDict,
|
||||||
existingGroupUsers.ContainsKey(group.Id) ? existingGroupUsers[group.Id] : null);
|
existingGroupUsers.ContainsKey(group.Id) ? existingGroupUsers[group.Id] : null);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -336,6 +346,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
await _eventService.LogGroupEventsAsync(
|
await _eventService.LogGroupEventsAsync(
|
||||||
updateGroups.Select(g => (g, EventType.Group_Updated, (EventSystemUser?)eventSystemUser, (DateTime?)DateTime.UtcNow)));
|
updateGroups.Select(g => (g, EventType.Group_Updated, (EventSystemUser?)eventSystemUser, (DateTime?)DateTime.UtcNow)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<OrganizationUserUserDetails> GetExistingExternalUsers(ICollection<OrganizationUserUserDetails> existingUsers)
|
private IEnumerable<OrganizationUserUserDetails> GetExistingExternalUsers(ICollection<OrganizationUserUserDetails> existingUsers)
|
||||||
@ -345,11 +356,11 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, Guid> GetExistingExternalUsersIdDict(ICollection<OrganizationUserUserDetails> existingUsers)
|
private IEnumerable<Group> GetExistingExternalGroups(ICollection<Group> existingGroups)
|
||||||
{
|
{
|
||||||
return existingUsers
|
return existingGroups
|
||||||
.Where(u => !string.IsNullOrWhiteSpace(u.ExternalId))
|
.Where(u => !string.IsNullOrWhiteSpace(u.ExternalId))
|
||||||
.ToDictionary(u => u.ExternalId, u => u.Id);
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Organization> GetOrgById(Guid id)
|
private async Task<Organization> GetOrgById(Guid id)
|
||||||
|
@ -20,7 +20,7 @@ public interface IInviteOrganizationUsersCommand
|
|||||||
/// <returns>Response from InviteScimOrganiation<see cref="ScimInviteOrganizationUsersResponse"/></returns>
|
/// <returns>Response from InviteScimOrganiation<see cref="ScimInviteOrganizationUsersResponse"/></returns>
|
||||||
Task<CommandResult<ScimInviteOrganizationUsersResponse>> InviteScimOrganizationUserAsync(InviteOrganizationUsersRequest request);
|
Task<CommandResult<ScimInviteOrganizationUsersResponse>> InviteScimOrganizationUserAsync(InviteOrganizationUsersRequest request);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends invitations to add imported organization users via directory connector or public API.
|
/// Sends invitations to add imported organization users via the public API.
|
||||||
/// This can be a Success or a Failure. Failure will contain the Error along with a representation of the errored value.
|
/// This can be a Success or a Failure. Failure will contain the Error along with a representation of the errored value.
|
||||||
/// Success will be the successful return object.
|
/// Success will be the successful return object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -16,7 +16,7 @@ public class InviteOrganizationUsersRequestTests
|
|||||||
public void Constructor_WhenPassedInvalidEmail_ThrowsException(string email, OrganizationUserType type, Permissions permissions, string externalId)
|
public void Constructor_WhenPassedInvalidEmail_ThrowsException(string email, OrganizationUserType type, Permissions permissions, string externalId)
|
||||||
{
|
{
|
||||||
var exception = Assert.Throws<BadRequestException>(() =>
|
var exception = Assert.Throws<BadRequestException>(() =>
|
||||||
new OrganizationUserInvite(email, [], [], type, permissions, externalId, false));
|
new OrganizationUserInviteCommandModel(email, [], [], type, permissions, externalId, false));
|
||||||
|
|
||||||
Assert.Contains(InvalidEmailErrorMessage, exception.Message);
|
Assert.Contains(InvalidEmailErrorMessage, exception.Message);
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ public class InviteOrganizationUsersRequestTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
var exception = Assert.Throws<BadRequestException>(() =>
|
var exception = Assert.Throws<BadRequestException>(() =>
|
||||||
new OrganizationUserInvite(
|
new OrganizationUserInviteCommandModel(
|
||||||
email: validEmail,
|
email: validEmail,
|
||||||
assignedCollections: [invalidCollectionConfiguration],
|
assignedCollections: [invalidCollectionConfiguration],
|
||||||
groups: [],
|
groups: [],
|
||||||
@ -51,7 +51,7 @@ public class InviteOrganizationUsersRequestTests
|
|||||||
const string validEmail = "test@email.com";
|
const string validEmail = "test@email.com";
|
||||||
var validCollectionConfiguration = new CollectionAccessSelection { Id = Guid.NewGuid(), Manage = true };
|
var validCollectionConfiguration = new CollectionAccessSelection { Id = Guid.NewGuid(), Manage = true };
|
||||||
|
|
||||||
var invite = new OrganizationUserInvite(
|
var invite = new OrganizationUserInviteCommandModel(
|
||||||
email: validEmail,
|
email: validEmail,
|
||||||
assignedCollections: [validCollectionConfiguration],
|
assignedCollections: [validCollectionConfiguration],
|
||||||
groups: [],
|
groups: [],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user