diff --git a/src/Api/Controllers/CollectionUsersController.cs b/src/Api/Controllers/CollectionUsersController.cs deleted file mode 100644 index 1f568905fb..0000000000 --- a/src/Api/Controllers/CollectionUsersController.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Bit.Core.Repositories; -using Microsoft.AspNetCore.Authorization; -using Bit.Core.Models.Api; -using Bit.Core.Exceptions; -using Bit.Core.Services; -using Bit.Core; - -namespace Bit.Api.Controllers -{ - [Route("organizations/{orgId}/collectionUsers")] - [Authorize("Application")] - public class CollectionUsersController : Controller - { - private readonly ICollectionRepository _collectionRepository; - private readonly ICollectionUserRepository _collectionUserRepository; - private readonly IUserService _userService; - private readonly CurrentContext _currentContext; - - public CollectionUsersController( - ICollectionRepository collectionRepository, - ICollectionUserRepository collectionUserRepository, - IUserService userService, - CurrentContext currentContext) - { - _collectionRepository = collectionRepository; - _collectionUserRepository = collectionUserRepository; - _userService = userService; - _currentContext = currentContext; - } - - [HttpGet("{collectionId}")] - public async Task> GetByCollection(string orgId, string collectionId) - { - var collectionIdGuid = new Guid(collectionId); - var collection = await _collectionRepository.GetByIdAsync(collectionIdGuid); - if(collection == null || !_currentContext.OrganizationAdmin(collection.OrganizationId)) - { - throw new NotFoundException(); - } - - var collectionUsers = await _collectionUserRepository.GetManyDetailsByCollectionIdAsync(collection.OrganizationId, - collection.Id); - var responses = collectionUsers.Select(c => new CollectionUserResponseModel(c)); - return new ListResponseModel(responses); - } - - [HttpDelete("{id}")] - [HttpPost("{id}/delete")] - public async Task Delete(string orgId, string id) - { - var user = await _collectionUserRepository.GetByIdAsync(new Guid(id)); - if(user == null) - { - throw new NotFoundException(); - } - - var collection = await _collectionRepository.GetByIdAsync(user.CollectionId); - if(collection == null || !_currentContext.OrganizationAdmin(collection.OrganizationId)) - { - throw new NotFoundException(); - } - - await _collectionUserRepository.DeleteAsync(user); - } - } -} diff --git a/src/Api/Controllers/CollectionsController.cs b/src/Api/Controllers/CollectionsController.cs index 1265a6ad48..e3b148141e 100644 --- a/src/Api/Controllers/CollectionsController.cs +++ b/src/Api/Controllers/CollectionsController.cs @@ -17,20 +17,17 @@ namespace Bit.Api.Controllers public class CollectionsController : Controller { private readonly ICollectionRepository _collectionRepository; - private readonly ICollectionUserRepository _collectionUserRepository; private readonly ICollectionService _collectionService; private readonly IUserService _userService; private readonly CurrentContext _currentContext; public CollectionsController( ICollectionRepository collectionRepository, - ICollectionUserRepository collectionUserRepository, ICollectionService collectionService, IUserService userService, CurrentContext currentContext) { _collectionRepository = collectionRepository; - _collectionUserRepository = collectionUserRepository; _collectionService = collectionService; _userService = userService; _currentContext = currentContext; @@ -82,6 +79,24 @@ namespace Bit.Api.Controllers return new ListResponseModel(responses); } + + + [HttpGet("{id}/users")] + public async Task> GetUsers(string orgId, string id) + { + var idGuid = new Guid(id); + var collection = await _collectionRepository.GetByIdAsync(idGuid); + if(collection == null || !_currentContext.OrganizationAdmin(collection.OrganizationId)) + { + throw new NotFoundException(); + } + + var collectionUsers = await _collectionRepository.GetManyUserDetailsByIdAsync(collection.OrganizationId, + collection.Id); + var responses = collectionUsers.Select(c => new CollectionUserResponseModel(c)); + return new ListResponseModel(responses); + } + [HttpPost("")] public async Task Post(string orgId, [FromBody]CollectionRequestModel model) { @@ -123,5 +138,18 @@ namespace Bit.Api.Controllers await _collectionRepository.DeleteAsync(collection); } + + [HttpDelete("{id}/user/{orgUserId}")] + [HttpPost("{id}/delete-user/{orgUserId}")] + public async Task Delete(string orgId, string id, string orgUserId) + { + var collection = await _collectionRepository.GetByIdAsync(new Guid(id)); + if(collection == null || !_currentContext.OrganizationAdmin(collection.OrganizationId)) + { + throw new NotFoundException(); + } + + await _collectionRepository.DeleteUserAsync(collection.Id, new Guid(orgUserId)); + } } } diff --git a/src/Api/Controllers/OrganizationUsersController.cs b/src/Api/Controllers/OrganizationUsersController.cs index bbd5779b8f..da642bf038 100644 --- a/src/Api/Controllers/OrganizationUsersController.cs +++ b/src/Api/Controllers/OrganizationUsersController.cs @@ -93,7 +93,7 @@ namespace Bit.Api.Controllers var userId = _userService.GetProperUserId(User); var result = await _organizationService.InviteUserAsync(orgGuidId, userId.Value, model.Email, model.Type.Value, - model.AccessAll, model.Collections?.Select(c => c.ToCollectionUser())); + model.AccessAll, model.Collections?.Select(c => c.ToSelectionReadOnly())); } [HttpPut("{id}/reinvite")] @@ -150,7 +150,7 @@ namespace Bit.Api.Controllers var userId = _userService.GetProperUserId(User); await _organizationService.SaveUserAsync(model.ToOrganizationUser(organizationUser), userId.Value, - model.Collections?.Select(c => c.ToCollectionUser())); + model.Collections?.Select(c => c.ToSelectionReadOnly())); } [HttpPut("{id}/groups")] diff --git a/src/Core/Models/Api/Request/CollectionUserRequestModel.cs b/src/Core/Models/Api/Request/CollectionUserRequestModel.cs deleted file mode 100644 index 869299e567..0000000000 --- a/src/Core/Models/Api/Request/CollectionUserRequestModel.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Bit.Core.Models.Table; -using System.Collections.Generic; -using System.Linq; - -namespace Bit.Core.Models.Api -{ - public class CollectionUserCollectionRequestModel - { - public string UserId { get; set; } - public IEnumerable Collections { get; set; } - - public IEnumerable ToCollectionUsers() - { - return Collections.Select(c => new CollectionUser - { - OrganizationUserId = new Guid(UserId), - CollectionId = new Guid(c.CollectionId), - ReadOnly = c.ReadOnly - }); - } - - public class Collection - { - public string CollectionId { get; set; } - public bool ReadOnly { get; set; } - } - } - - public class CollectionUserUserRequestModel - { - public string UserId { get; set; } - public bool ReadOnly { get; set; } - } -} diff --git a/src/Core/Models/Api/Request/SelectionReadOnlyRequestModel.cs b/src/Core/Models/Api/Request/SelectionReadOnlyRequestModel.cs index 9833946e60..d903b3cce5 100644 --- a/src/Core/Models/Api/Request/SelectionReadOnlyRequestModel.cs +++ b/src/Core/Models/Api/Request/SelectionReadOnlyRequestModel.cs @@ -12,15 +12,6 @@ namespace Bit.Core.Models.Api public string Id { get; set; } public bool ReadOnly { get; set; } - public CollectionUser ToCollectionUser() - { - return new CollectionUser - { - ReadOnly = ReadOnly, - CollectionId = new Guid(Id) - }; - } - public SelectionReadOnly ToSelectionReadOnly() { return new SelectionReadOnly diff --git a/src/Core/Models/Api/Response/CollectionUserResponseModel.cs b/src/Core/Models/Api/Response/CollectionUserResponseModel.cs index c4d8515a9e..dc96c5dcfe 100644 --- a/src/Core/Models/Api/Response/CollectionUserResponseModel.cs +++ b/src/Core/Models/Api/Response/CollectionUserResponseModel.cs @@ -1,5 +1,4 @@ using System; -using Bit.Core.Models.Table; using Bit.Core.Models.Data; using Bit.Core.Enums; @@ -7,7 +6,7 @@ namespace Bit.Core.Models.Api { public class CollectionUserResponseModel : ResponseModel { - public CollectionUserResponseModel(CollectionUserUserDetails collectionUser) + public CollectionUserResponseModel(CollectionUserDetails collectionUser) : base("collectionUser") { if(collectionUser == null) @@ -15,9 +14,7 @@ namespace Bit.Core.Models.Api throw new ArgumentNullException(nameof(collectionUser)); } - Id = collectionUser.Id?.ToString(); OrganizationUserId = collectionUser.OrganizationUserId.ToString(); - CollectionId = collectionUser.CollectionId?.ToString(); AccessAll = collectionUser.AccessAll; Name = collectionUser.Name; Email = collectionUser.Email; @@ -26,9 +23,7 @@ namespace Bit.Core.Models.Api ReadOnly = collectionUser.ReadOnly; } - public string Id { get; set; } public string OrganizationUserId { get; set; } - public string CollectionId { get; set; } public bool AccessAll { get; set; } public string Name { get; set; } public string Email { get; set; } diff --git a/src/Core/Models/Api/Response/GroupUserResponseModel.cs b/src/Core/Models/Api/Response/GroupUserResponseModel.cs index c3851cf2c1..1f118cd4cd 100644 --- a/src/Core/Models/Api/Response/GroupUserResponseModel.cs +++ b/src/Core/Models/Api/Response/GroupUserResponseModel.cs @@ -6,7 +6,7 @@ namespace Bit.Core.Models.Api { public class GroupUserResponseModel : ResponseModel { - public GroupUserResponseModel(GroupUserUserDetails groupUser) + public GroupUserResponseModel(GroupUserDetails groupUser) : base("groupUser") { if(groupUser == null) @@ -15,7 +15,6 @@ namespace Bit.Core.Models.Api } OrganizationUserId = groupUser.OrganizationUserId.ToString(); - GroupId = groupUser.GroupId.ToString(); AccessAll = groupUser.AccessAll; Name = groupUser.Name; Email = groupUser.Email; @@ -24,7 +23,6 @@ namespace Bit.Core.Models.Api } public string OrganizationUserId { get; set; } - public string GroupId { get; set; } public bool AccessAll { get; set; } public string Name { get; set; } public string Email { get; set; } diff --git a/src/Core/Models/Data/GroupUserUserDetails.cs b/src/Core/Models/Data/CollectionUserDetails.cs similarity index 74% rename from src/Core/Models/Data/GroupUserUserDetails.cs rename to src/Core/Models/Data/CollectionUserDetails.cs index 16e4483d18..5f81b6eea5 100644 --- a/src/Core/Models/Data/GroupUserUserDetails.cs +++ b/src/Core/Models/Data/CollectionUserDetails.cs @@ -2,15 +2,14 @@ namespace Bit.Core.Models.Data { - public class GroupUserUserDetails + public class CollectionUserDetails { public Guid OrganizationUserId { get; set; } - public Guid OrganizationId { get; set; } - public Guid GroupId { get; set; } public bool AccessAll { get; set; } public string Name { get; set; } public string Email { get; set; } public Enums.OrganizationUserStatusType Status { get; set; } public Enums.OrganizationUserType Type { get; set; } + public bool ReadOnly { get; set; } } } diff --git a/src/Core/Models/Data/CollectionUserUserDetails.cs b/src/Core/Models/Data/GroupUserDetails.cs similarity index 62% rename from src/Core/Models/Data/CollectionUserUserDetails.cs rename to src/Core/Models/Data/GroupUserDetails.cs index 09344ce826..a719e352c3 100644 --- a/src/Core/Models/Data/CollectionUserUserDetails.cs +++ b/src/Core/Models/Data/GroupUserDetails.cs @@ -2,17 +2,13 @@ namespace Bit.Core.Models.Data { - public class CollectionUserUserDetails + public class GroupUserDetails { - public Guid? Id { get; set; } public Guid OrganizationUserId { get; set; } - public Guid? OrganizationId { get; set; } - public Guid? CollectionId { get; set; } public bool AccessAll { get; set; } public string Name { get; set; } public string Email { get; set; } public Enums.OrganizationUserStatusType Status { get; set; } public Enums.OrganizationUserType Type { get; set; } - public bool ReadOnly { get; set; } } } diff --git a/src/Core/Models/Table/CollectionGroup.cs b/src/Core/Models/Table/CollectionGroup.cs deleted file mode 100644 index d666d73443..0000000000 --- a/src/Core/Models/Table/CollectionGroup.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Bit.Core.Models.Table -{ - public class CollectionGroup - { - public Guid CollectionId { get; set; } - public Guid GroupId { get; set; } - public bool ReadOnly { get; set; } - } -} diff --git a/src/Core/Models/Table/CollectionUser.cs b/src/Core/Models/Table/CollectionUser.cs deleted file mode 100644 index f559db0a12..0000000000 --- a/src/Core/Models/Table/CollectionUser.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Bit.Core.Utilities; - -namespace Bit.Core.Models.Table -{ - public class CollectionUser : IDataObject - { - public Guid Id { get; set; } - public Guid CollectionId { get; set; } - public Guid OrganizationUserId { get; set; } - public bool ReadOnly { get; set; } - public DateTime CreationDate { get; internal set; } = DateTime.UtcNow; - public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow; - - public void SetNewId() - { - Id = CoreHelpers.GenerateComb(); - } - } -} diff --git a/src/Core/Repositories/ICollectionRepository.cs b/src/Core/Repositories/ICollectionRepository.cs index 51ae8a32fb..26cae13559 100644 --- a/src/Core/Repositories/ICollectionRepository.cs +++ b/src/Core/Repositories/ICollectionRepository.cs @@ -12,8 +12,9 @@ namespace Bit.Core.Repositories Task>> GetByIdWithGroupsAsync(Guid id); Task> GetManyByOrganizationIdAsync(Guid organizationId); Task> GetManyByUserIdAsync(Guid userId); + Task> GetManyUserDetailsByIdAsync(Guid organizationId, Guid collectionId); Task CreateAsync(Collection obj, IEnumerable groups); Task ReplaceAsync(Collection obj, IEnumerable groups); - + Task DeleteUserAsync(Guid collectionId, Guid organizationUserId); } } diff --git a/src/Core/Repositories/ICollectionUserRepository.cs b/src/Core/Repositories/ICollectionUserRepository.cs deleted file mode 100644 index cc7ad4e00a..0000000000 --- a/src/Core/Repositories/ICollectionUserRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Threading.Tasks; -using Bit.Core.Models.Table; -using System.Collections.Generic; -using Bit.Core.Models.Data; - -namespace Bit.Core.Repositories -{ - public interface ICollectionUserRepository : IRepository - { - Task> GetManyByOrganizationUserIdAsync(Guid orgUserId); - Task> GetManyDetailsByCollectionIdAsync(Guid organizationId, Guid collectionId); - } -} diff --git a/src/Core/Repositories/IGroupRepository.cs b/src/Core/Repositories/IGroupRepository.cs index 84b235d34e..56065b7cf9 100644 --- a/src/Core/Repositories/IGroupRepository.cs +++ b/src/Core/Repositories/IGroupRepository.cs @@ -10,7 +10,7 @@ namespace Bit.Core.Repositories { Task>> GetByIdWithCollectionsAsync(Guid id); Task> GetManyByOrganizationIdAsync(Guid organizationId); - Task> GetManyUserDetailsByIdAsync(Guid id); + Task> GetManyUserDetailsByIdAsync(Guid id); Task> GetManyIdsByUserIdAsync(Guid organizationUserId); Task CreateAsync(Group obj, IEnumerable collections); Task ReplaceAsync(Group obj, IEnumerable collections); diff --git a/src/Core/Repositories/IOrganizationUserRepository.cs b/src/Core/Repositories/IOrganizationUserRepository.cs index 877d290088..cd36a67a90 100644 --- a/src/Core/Repositories/IOrganizationUserRepository.cs +++ b/src/Core/Repositories/IOrganizationUserRepository.cs @@ -21,5 +21,7 @@ namespace Bit.Core.Repositories Task> GetManyDetailsByUserAsync(Guid userId, OrganizationUserStatusType? status = null); Task UpdateGroupsAsync(Guid orgUserId, IEnumerable groupIds); + Task CreateAsync(OrganizationUser obj, IEnumerable collections); + Task ReplaceAsync(OrganizationUser obj, IEnumerable collections); } } diff --git a/src/Core/Repositories/SqlServer/CollectionRepository.cs b/src/Core/Repositories/SqlServer/CollectionRepository.cs index a039337b50..6c1be72485 100644 --- a/src/Core/Repositories/SqlServer/CollectionRepository.cs +++ b/src/Core/Repositories/SqlServer/CollectionRepository.cs @@ -81,6 +81,24 @@ namespace Bit.Core.Repositories.SqlServer } } + public async Task> GetManyUserDetailsByIdAsync(Guid organizationId, + Guid collectionId) + { + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.QueryAsync( + $"[{Schema}].[CollectionUserDetails_ReadByCollectionId]", + new { OrganizationId = organizationId, CollectionId = collectionId }, + commandType: CommandType.StoredProcedure); + + // Return distinct Id results. If at least one of the grouped results is not ReadOnly, that we return it. + return results + .GroupBy(c => c.OrganizationUserId) + .Select(g => g.OrderBy(og => og.ReadOnly).First()) + .ToList(); + } + } + public async Task CreateAsync(Collection obj, IEnumerable groups) { obj.SetNewId(); @@ -110,6 +128,17 @@ namespace Bit.Core.Repositories.SqlServer } } + public async Task DeleteUserAsync(Guid collectionId, Guid organizationUserId) + { + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.ExecuteAsync( + $"[{Schema}].[CollectionUser_Delete]", + new { CollectionId = collectionId, OrganizationUserId = organizationUserId }, + commandType: CommandType.StoredProcedure); + } + } + public class CollectionWithGroups : Collection { public DataTable Groups { get; set; } diff --git a/src/Core/Repositories/SqlServer/CollectionUserRepository.cs b/src/Core/Repositories/SqlServer/CollectionUserRepository.cs deleted file mode 100644 index 2d2047ba8d..0000000000 --- a/src/Core/Repositories/SqlServer/CollectionUserRepository.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using Bit.Core.Models.Table; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Data; -using System.Data.SqlClient; -using Dapper; -using System.Linq; -using Bit.Core.Models.Data; - -namespace Bit.Core.Repositories.SqlServer -{ - public class CollectionUserRepository : Repository, ICollectionUserRepository - { - public CollectionUserRepository(GlobalSettings globalSettings) - : this(globalSettings.SqlServer.ConnectionString) - { } - - public CollectionUserRepository(string connectionString) - : base(connectionString) - { } - - public async Task> GetManyByOrganizationUserIdAsync(Guid orgUserId) - { - using(var connection = new SqlConnection(ConnectionString)) - { - var results = await connection.QueryAsync( - $"[{Schema}].[{Table}_ReadByOrganizationUserId]", - new { OrganizationUserId = orgUserId }, - commandType: CommandType.StoredProcedure); - - return results.ToList(); - } - } - - public async Task> GetManyDetailsByCollectionIdAsync(Guid organizationId, - Guid collectionId) - { - using(var connection = new SqlConnection(ConnectionString)) - { - var results = await connection.QueryAsync( - $"[{Schema}].[CollectionUserUserDetails_ReadByCollectionId]", - new { OrganizationId = organizationId, CollectionId = collectionId }, - commandType: CommandType.StoredProcedure); - - // Return distinct Id results. If at least one of the grouped results is not ReadOnly, that we return it. - return results - .GroupBy(c => c.Id) - .Select(g => g.OrderBy(og => og.ReadOnly).First()) - .ToList(); - } - } - } -} diff --git a/src/Core/Repositories/SqlServer/GroupRepository.cs b/src/Core/Repositories/SqlServer/GroupRepository.cs index 2ec55f75fc..4ef8e87f2f 100644 --- a/src/Core/Repositories/SqlServer/GroupRepository.cs +++ b/src/Core/Repositories/SqlServer/GroupRepository.cs @@ -51,12 +51,12 @@ namespace Bit.Core.Repositories.SqlServer } } - public async Task> GetManyUserDetailsByIdAsync(Guid id) + public async Task> GetManyUserDetailsByIdAsync(Guid id) { using(var connection = new SqlConnection(ConnectionString)) { - var results = await connection.QueryAsync( - $"[{Schema}].[GroupUserUserDetails_ReadByGroupId]", + var results = await connection.QueryAsync( + $"[{Schema}].[GroupUserDetails_ReadByGroupId]", new { GroupId = id }, commandType: CommandType.StoredProcedure); diff --git a/src/Core/Repositories/SqlServer/OrganizationUserRepository.cs b/src/Core/Repositories/SqlServer/OrganizationUserRepository.cs index f9e562488a..0c5ba67275 100644 --- a/src/Core/Repositories/SqlServer/OrganizationUserRepository.cs +++ b/src/Core/Repositories/SqlServer/OrganizationUserRepository.cs @@ -9,6 +9,7 @@ using Bit.Core.Models.Data; using System.Collections.Generic; using Bit.Core.Enums; using Bit.Core.Utilities; +using Newtonsoft.Json; namespace Bit.Core.Repositories.SqlServer { @@ -166,5 +167,41 @@ namespace Bit.Core.Repositories.SqlServer commandType: CommandType.StoredProcedure); } } + + public async Task CreateAsync(OrganizationUser obj, IEnumerable collections) + { + obj.SetNewId(); + var objWithCollections = JsonConvert.DeserializeObject( + JsonConvert.SerializeObject(obj)); + objWithCollections.Collections = collections.ToArrayTVP(); + + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.ExecuteAsync( + $"[{Schema}].[OrganizationUser_CreateWithCollections]", + objWithCollections, + commandType: CommandType.StoredProcedure); + } + } + + public async Task ReplaceAsync(OrganizationUser obj, IEnumerable collections) + { + var objWithCollections = JsonConvert.DeserializeObject( + JsonConvert.SerializeObject(obj)); + objWithCollections.Collections = collections.ToArrayTVP(); + + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.ExecuteAsync( + $"[{Schema}].[OrganizationUser_UpdateWithCollections]", + objWithCollections, + commandType: CommandType.StoredProcedure); + } + } + + public class OrganizationUserWithCollections : OrganizationUser + { + public DataTable Collections { get; set; } + } } } diff --git a/src/Core/Services/IOrganizationService.cs b/src/Core/Services/IOrganizationService.cs index 33bd3de268..69d2f6a45a 100644 --- a/src/Core/Services/IOrganizationService.cs +++ b/src/Core/Services/IOrganizationService.cs @@ -4,6 +4,7 @@ using Bit.Core.Models.Table; using System; using System.Collections.Generic; using Bit.Core.Enums; +using Bit.Core.Models.Data; namespace Bit.Core.Services { @@ -21,11 +22,11 @@ namespace Bit.Core.Services Task EnableAsync(Guid organizationId); Task UpdateAsync(Organization organization, bool updateBilling = false); Task InviteUserAsync(Guid organizationId, Guid invitingUserId, string email, - OrganizationUserType type, bool accessAll, IEnumerable collections); + OrganizationUserType type, bool accessAll, IEnumerable collections); Task ResendInviteAsync(Guid organizationId, Guid invitingUserId, Guid organizationUserId); Task AcceptUserAsync(Guid organizationUserId, User user, string token); Task ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key, Guid confirmingUserId); - Task SaveUserAsync(OrganizationUser user, Guid savingUserId, IEnumerable collections); + Task SaveUserAsync(OrganizationUser user, Guid savingUserId, IEnumerable collections); Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, Guid deletingUserId); Task DeleteUserAsync(Guid organizationId, Guid userId); } diff --git a/src/Core/Services/Implementations/CollectionService.cs b/src/Core/Services/Implementations/CollectionService.cs index 17e5d27a03..92269d84f7 100644 --- a/src/Core/Services/Implementations/CollectionService.cs +++ b/src/Core/Services/Implementations/CollectionService.cs @@ -13,7 +13,6 @@ namespace Bit.Core.Services private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationUserRepository _organizationUserRepository; private readonly ICollectionRepository _collectionRepository; - private readonly ICollectionUserRepository _collectionUserRepository; private readonly IUserRepository _userRepository; private readonly IMailService _mailService; @@ -21,14 +20,12 @@ namespace Bit.Core.Services IOrganizationRepository organizationRepository, IOrganizationUserRepository organizationUserRepository, ICollectionRepository collectionRepository, - ICollectionUserRepository collectionUserRepository, IUserRepository userRepository, IMailService mailService) { _organizationRepository = organizationRepository; _organizationUserRepository = organizationUserRepository; _collectionRepository = collectionRepository; - _collectionUserRepository = collectionUserRepository; _userRepository = userRepository; _mailService = mailService; } diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index bab0eedef8..98fb478d60 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.DataProtection; using Stripe; using Bit.Core.Enums; using Bit.Core.Models.StaticStore; +using Bit.Core.Models.Data; namespace Bit.Core.Services { @@ -19,7 +20,6 @@ namespace Bit.Core.Services private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationUserRepository _organizationUserRepository; private readonly ICollectionRepository _collectionRepository; - private readonly ICollectionUserRepository _collectionUserRepository; private readonly IUserRepository _userRepository; private readonly IDataProtector _dataProtector; private readonly IMailService _mailService; @@ -29,7 +29,6 @@ namespace Bit.Core.Services IOrganizationRepository organizationRepository, IOrganizationUserRepository organizationUserRepository, ICollectionRepository collectionRepository, - ICollectionUserRepository collectionUserRepository, IUserRepository userRepository, IDataProtectionProvider dataProtectionProvider, IMailService mailService, @@ -38,7 +37,6 @@ namespace Bit.Core.Services _organizationRepository = organizationRepository; _organizationUserRepository = organizationUserRepository; _collectionRepository = collectionRepository; - _collectionUserRepository = collectionUserRepository; _userRepository = userRepository; _dataProtector = dataProtectionProvider.CreateProtector("OrganizationServiceDataProtector"); _mailService = mailService; @@ -683,7 +681,7 @@ namespace Bit.Core.Services } public async Task InviteUserAsync(Guid organizationId, Guid invitingUserId, string email, - OrganizationUserType type, bool accessAll, IEnumerable collections) + OrganizationUserType type, bool accessAll, IEnumerable collections) { var organization = await _organizationRepository.GetByIdAsync(organizationId); if(organization == null) @@ -721,13 +719,16 @@ namespace Bit.Core.Services RevisionDate = DateTime.UtcNow }; - await _organizationUserRepository.CreateAsync(orgUser); if(!orgUser.AccessAll && collections.Any()) { - await SaveUserCollectionsAsync(orgUser, collections, true); + await _organizationUserRepository.CreateAsync(orgUser, collections); + } + else + { + await _organizationUserRepository.CreateAsync(orgUser); } - await SendInviteAsync(orgUser); + await SendInviteAsync(orgUser); return orgUser; } @@ -833,7 +834,7 @@ namespace Bit.Core.Services return orgUser; } - public async Task SaveUserAsync(OrganizationUser user, Guid savingUserId, IEnumerable collections) + public async Task SaveUserAsync(OrganizationUser user, Guid savingUserId, IEnumerable collections) { if(user.Id.Equals(default(Guid))) { @@ -846,14 +847,13 @@ namespace Bit.Core.Services throw new BadRequestException("Organization must have at least one confirmed owner."); } - await _organizationUserRepository.ReplaceAsync(user); if(user.AccessAll) { // We don't need any collections if we're flagged to have all access. - collections = new List(); + collections = new List(); } - await SaveUserCollectionsAsync(user, collections, false); + await _organizationUserRepository.ReplaceAsync(user, collections); } public async Task DeleteUserAsync(Guid organizationId, Guid organizationUserId, Guid deletingUserId) @@ -901,41 +901,5 @@ namespace Bit.Core.Services Enums.OrganizationUserType.Owner); return owners.Where(o => o.Status == Enums.OrganizationUserStatusType.Confirmed); } - - private async Task SaveUserCollectionsAsync(OrganizationUser user, IEnumerable collections, bool newUser) - { - if(collections == null) - { - collections = new List(); - } - - var orgCollections = await _collectionRepository.GetManyByOrganizationIdAsync(user.OrganizationId); - var currentUserCollections = newUser ? null : await _collectionUserRepository.GetManyByOrganizationUserIdAsync(user.Id); - - // Let's make sure all these belong to this user and organization. - var filteredCollections = collections.Where(c => orgCollections.Any(os => os.Id == c.CollectionId)); - foreach(var collection in filteredCollections) - { - var existingCollectionUser = currentUserCollections?.FirstOrDefault(cu => cu.CollectionId == collection.CollectionId); - if(existingCollectionUser != null) - { - collection.Id = existingCollectionUser.Id; - collection.CreationDate = existingCollectionUser.CreationDate; - } - - collection.OrganizationUserId = user.Id; - await _collectionUserRepository.UpsertAsync(collection); - } - - if(!newUser) - { - var collectionsToDelete = currentUserCollections.Where(cu => - !filteredCollections.Any(c => c.CollectionId == cu.CollectionId)); - foreach(var collection in collectionsToDelete) - { - await _collectionUserRepository.DeleteAsync(collection); - } - } - } } } diff --git a/src/Core/Utilities/ServiceCollectionExtensions.cs b/src/Core/Utilities/ServiceCollectionExtensions.cs index 91f13724cf..729f061904 100644 --- a/src/Core/Utilities/ServiceCollectionExtensions.cs +++ b/src/Core/Utilities/ServiceCollectionExtensions.cs @@ -32,7 +32,6 @@ namespace Bit.Core.Utilities services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index 2c70828afa..5f33d0eb0d 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -82,8 +82,6 @@ - - @@ -127,16 +125,11 @@ - - - - - - + @@ -188,11 +181,13 @@ - - + + + + \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CollectionUserDetails_ReadByCollectionId.sql b/src/Sql/dbo/Stored Procedures/CollectionUserDetails_ReadByCollectionId.sql new file mode 100644 index 0000000000..e86aa884c0 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/CollectionUserDetails_ReadByCollectionId.sql @@ -0,0 +1,44 @@ +CREATE PROCEDURE [dbo].[CollectionUserDetails_ReadByCollectionId] + @CollectionId UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + OU.[Id] AS [OrganizationUserId], + CASE + WHEN OU.[AccessAll] = 1 OR G.[AccessAll] = 1 THEN 1 + ELSE 0 + END [AccessAll], + U.[Name], + ISNULL(U.[Email], OU.[Email]) Email, + OU.[Status], + OU.[Type], + CASE + WHEN OU.[AccessAll] = 1 OR CU.[ReadOnly] = 0 OR G.[AccessAll] = 1 OR CG.[ReadOnly] = 0 THEN 0 + ELSE 1 + END [ReadOnly] + FROM + [dbo].[OrganizationUser] OU + LEFT JOIN + [dbo].[User] U ON U.[Id] = OU.[UserId] + LEFT JOIN + [dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = OU.[Id] AND CU.[CollectionId] = @CollectionId + LEFT JOIN + [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id] + LEFT JOIN + [dbo].[Group] G ON G.[Id] = GU.[GroupId] + LEFT JOIN + [dbo].[CollectionGroup] CG ON G.[AccessAll] = 0 AND CG.[GroupId] = GU.[GroupId] AND CG.[CollectionId] = @CollectionId + WHERE + CU.[CollectionId] IS NOT NULL + OR CG.[CollectionId] IS NOT NULL + OR ( + OU.[OrganizationId] = @OrganizationId + AND ( + OU.[AccessAll] = 1 + OR G.[AccessAll] = 1 + ) + ) +END diff --git a/src/Sql/dbo/Stored Procedures/CollectionUserUserDetails_ReadByCollectionId.sql b/src/Sql/dbo/Stored Procedures/CollectionUserUserDetails_ReadByCollectionId.sql deleted file mode 100644 index ecdcb4ae36..0000000000 --- a/src/Sql/dbo/Stored Procedures/CollectionUserUserDetails_ReadByCollectionId.sql +++ /dev/null @@ -1,19 +0,0 @@ -CREATE PROCEDURE [dbo].[CollectionUserUserDetails_ReadByCollectionId] - @CollectionId UNIQUEIDENTIFIER, - @OrganizationId UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - SELECT - * - FROM - [dbo].[CollectionUserUserDetailsView] - WHERE - [CollectionId] = @CollectionId - OR - ( - [OrganizationId] = @OrganizationId - AND [AccessAll] = 1 - ) -END diff --git a/src/Sql/dbo/Stored Procedures/CollectionUser_Create.sql b/src/Sql/dbo/Stored Procedures/CollectionUser_Create.sql deleted file mode 100644 index 56e81b2f4b..0000000000 --- a/src/Sql/dbo/Stored Procedures/CollectionUser_Create.sql +++ /dev/null @@ -1,35 +0,0 @@ -CREATE PROCEDURE [dbo].[CollectionUser_Create] - @Id UNIQUEIDENTIFIER, - @CollectionId UNIQUEIDENTIFIER, - @OrganizationUserId UNIQUEIDENTIFIER, - @ReadOnly BIT, - @CreationDate DATETIME2(7), - @RevisionDate DATETIME2(7) -AS -BEGIN - SET NOCOUNT ON - - INSERT INTO [dbo].[CollectionUser] - ( - [Id], - [CollectionId], - [OrganizationUserId], - [ReadOnly], - [CreationDate], - [RevisionDate] - ) - VALUES - ( - @Id, - @CollectionId, - @OrganizationUserId, - @ReadOnly, - @CreationDate, - @RevisionDate - ) - - IF @OrganizationUserId IS NOT NULL - BEGIN - EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationUserId] @OrganizationUserId - END -END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CollectionUser_Delete.sql b/src/Sql/dbo/Stored Procedures/CollectionUser_Delete.sql new file mode 100644 index 0000000000..0dc859cfc6 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/CollectionUser_Delete.sql @@ -0,0 +1,16 @@ +CREATE PROCEDURE [dbo].[CollectionUser_Delete] + @CollectionId UNIQUEIDENTIFIER, + @OrganizationUserId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + DELETE + FROM + [dbo].[CollectionUser] + WHERE + [CollectionId] = @CollectionId + AND [OrganizationUserId] = @OrganizationUserId + + EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationUserId] @OrganizationUserId +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CollectionUser_DeleteById.sql b/src/Sql/dbo/Stored Procedures/CollectionUser_DeleteById.sql deleted file mode 100644 index 386248b192..0000000000 --- a/src/Sql/dbo/Stored Procedures/CollectionUser_DeleteById.sql +++ /dev/null @@ -1,19 +0,0 @@ -CREATE PROCEDURE [dbo].[CollectionUser_DeleteById] - @Id UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - DECLARE @OrganizationUserId UNIQUEIDENTIFIER = (SELECT TOP 1 [OrganizationUserId] FROM [dbo].[CollectionUser] WHERE [Id] = @Id) - - DELETE - FROM - [dbo].[CollectionUser] - WHERE - [Id] = @Id - - IF @OrganizationUserId IS NOT NULL - BEGIN - EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationUserId] @OrganizationUserId - END -END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CollectionUser_ReadById.sql b/src/Sql/dbo/Stored Procedures/CollectionUser_ReadById.sql deleted file mode 100644 index da31978806..0000000000 --- a/src/Sql/dbo/Stored Procedures/CollectionUser_ReadById.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE PROCEDURE [dbo].[CollectionUser_ReadById] - @Id UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - SELECT - * - FROM - [dbo].[CollectionUserView] - WHERE - [Id] = @Id -END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CollectionUser_ReadByOrganizationUserId.sql b/src/Sql/dbo/Stored Procedures/CollectionUser_ReadByOrganizationUserId.sql deleted file mode 100644 index 531555bc8c..0000000000 --- a/src/Sql/dbo/Stored Procedures/CollectionUser_ReadByOrganizationUserId.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE PROCEDURE [dbo].[CollectionUser_ReadByOrganizationUserId] - @OrganizationUserId UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - SELECT - * - FROM - [dbo].[CollectionUserView] - WHERE - [OrganizationUserId] = @OrganizationUserId -END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/CollectionUser_Update.sql b/src/Sql/dbo/Stored Procedures/CollectionUser_Update.sql deleted file mode 100644 index 3f2c80f44c..0000000000 --- a/src/Sql/dbo/Stored Procedures/CollectionUser_Update.sql +++ /dev/null @@ -1,27 +0,0 @@ -CREATE PROCEDURE [dbo].[CollectionUser_Update] - @Id UNIQUEIDENTIFIER, - @CollectionId UNIQUEIDENTIFIER, - @OrganizationUserId UNIQUEIDENTIFIER, - @ReadOnly BIT, - @CreationDate DATETIME2(7), - @RevisionDate DATETIME2(7) -AS -BEGIN - SET NOCOUNT ON - - UPDATE - [dbo].[CollectionUser] - SET - [CollectionId] = @CollectionId, - [OrganizationUserId] = @OrganizationUserId, - [ReadOnly] = @ReadOnly, - [CreationDate] = @CreationDate, - [RevisionDate] = @RevisionDate - WHERE - [Id] = @Id - - IF @OrganizationUserId IS NOT NULL - BEGIN - EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationUserId] @OrganizationUserId - END -END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/Collection_ReadByUserId.sql b/src/Sql/dbo/Stored Procedures/Collection_ReadByUserId.sql index 3618bc2b6a..981016b6b9 100644 --- a/src/Sql/dbo/Stored Procedures/Collection_ReadByUserId.sql +++ b/src/Sql/dbo/Stored Procedures/Collection_ReadByUserId.sql @@ -22,7 +22,7 @@ BEGIN OU.[UserId] = @UserId AND ( OU.[AccessAll] = 1 - OR CU.[Id] IS NOT NULL + OR CU.[CollectionId] IS NOT NULL OR G.[AccessAll] = 1 OR CG.[CollectionId] IS NOT NULL ) diff --git a/src/Sql/dbo/Stored Procedures/GroupUserDetails_ReadByGroupId.sql b/src/Sql/dbo/Stored Procedures/GroupUserDetails_ReadByGroupId.sql new file mode 100644 index 0000000000..2e32c087c8 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/GroupUserDetails_ReadByGroupId.sql @@ -0,0 +1,22 @@ +CREATE PROCEDURE [dbo].[GroupUserDetails_ReadByGroupId] + @GroupId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + SELECT + OU.[Id] AS [OrganizationUserId], + OU.[AccessAll], + U.[Name], + ISNULL(U.[Email], OU.[Email]) Email, + OU.[Status], + OU.[Type] + FROM + [dbo].[OrganizationUser] OU + INNER JOIN + [dbo].[GroupUser] GU ON GU.[OrganizationUserId] = OU.[Id] + INNER JOIN + [dbo].[User] U ON U.[Id] = OU.[UserId] + WHERE + GU.[GroupId] = @GroupId +END diff --git a/src/Sql/dbo/Stored Procedures/GroupUserUserDetails_ReadByGroupId.sql b/src/Sql/dbo/Stored Procedures/GroupUserUserDetails_ReadByGroupId.sql deleted file mode 100644 index 65e1616e10..0000000000 --- a/src/Sql/dbo/Stored Procedures/GroupUserUserDetails_ReadByGroupId.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE PROCEDURE [dbo].[GroupUserUserDetails_ReadByGroupId] - @GroupId UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - SELECT - * - FROM - [dbo].[GroupUserUserDetailsView] - WHERE - [GroupId] = @GroupId -END diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateWithCollections.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateWithCollections.sql new file mode 100644 index 0000000000..6f32394d4a --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateWithCollections.sql @@ -0,0 +1,41 @@ +CREATE PROCEDURE [dbo].[OrganizationUser_CreateWithCollections] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @Email NVARCHAR(50), + @Key VARCHAR(MAX), + @Status TINYINT, + @Type TINYINT, + @AccessAll BIT, + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Collections AS [dbo].[SelectionReadOnlyArray] READONLY +AS +BEGIN + SET NOCOUNT ON + + EXEC [dbo].[OrganizationUser_Create] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @CreationDate, @RevisionDate + + ;WITH [AvailableCollectionsCTE] AS( + SELECT + [Id] + FROM + [dbo].[Collection] + WHERE + [OrganizationId] = @OrganizationId + ) + INSERT INTO [dbo].[CollectionUser] + ( + [CollectionId], + [OrganizationUserId], + [ReadOnly] + ) + SELECT + [Id], + @Id, + [ReadOnly] + FROM + @Collections + WHERE + [Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE]) +END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql index 6242e366fd..7cf8f70bff 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql @@ -27,4 +27,6 @@ BEGIN [RevisionDate] = @RevisionDate WHERE [Id] = @Id + + EXEC [dbo].[User_BumpAccountRevisionDate] @UserId END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateWithCollections.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateWithCollections.sql new file mode 100644 index 0000000000..54a9bdba9d --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateWithCollections.sql @@ -0,0 +1,48 @@ +CREATE PROCEDURE [dbo].[OrganizationUser_UpdateWithCollections] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @Email NVARCHAR(50), + @Key VARCHAR(MAX), + @Status TINYINT, + @Type TINYINT, + @AccessAll BIT, + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Collections AS [dbo].[SelectionReadOnlyArray] READONLY +AS +BEGIN + SET NOCOUNT ON + + EXEC [dbo].[OrganizationUser_Update] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @CreationDate, @RevisionDate + + ;WITH [AvailableCollectionsCTE] AS( + SELECT + Id + FROM + [dbo].[Collection] + WHERE + OrganizationId = @OrganizationId + ) + MERGE + [dbo].[CollectionUser] AS [Target] + USING + @Collections AS [Source] + ON + [Target].[CollectionId] = [Source].[Id] + AND [Target].[OrganizationUserId] = @Id + WHEN NOT MATCHED BY TARGET + AND [Source].[Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE]) THEN + INSERT VALUES + ( + [Source].[Id], + @Id, + [Source].[ReadOnly] + ) + WHEN MATCHED AND [Target].[ReadOnly] != [Source].[ReadOnly] THEN + UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly] + WHEN NOT MATCHED BY SOURCE + AND [Target].[OrganizationUserId] = @Id THEN + DELETE + ; +END \ No newline at end of file diff --git a/src/Sql/dbo/Tables/CollectionUser.sql b/src/Sql/dbo/Tables/CollectionUser.sql index 10dbdd8d79..2f9c89cea1 100644 --- a/src/Sql/dbo/Tables/CollectionUser.sql +++ b/src/Sql/dbo/Tables/CollectionUser.sql @@ -1,17 +1,9 @@ CREATE TABLE [dbo].[CollectionUser] ( - [Id] UNIQUEIDENTIFIER NOT NULL, [CollectionId] UNIQUEIDENTIFIER NOT NULL, [OrganizationUserId] UNIQUEIDENTIFIER NOT NULL, - [ReadOnly] BIT NOT NULL, - [CreationDate] DATETIME2 (7) NOT NULL, - [RevisionDate] DATETIME2 (7) NOT NULL, - CONSTRAINT [PK_CollectionUser] PRIMARY KEY CLUSTERED ([Id] ASC), + [ReadOnly] BIT NOT NULL + CONSTRAINT [PK_CollectionUser] PRIMARY KEY CLUSTERED ([CollectionId] ASC, [OrganizationUserId] ASC), CONSTRAINT [FK_CollectionUser_Collection] FOREIGN KEY ([CollectionId]) REFERENCES [dbo].[Collection] ([Id]) ON DELETE CASCADE, CONSTRAINT [FK_CollectionUser_OrganizationUser] FOREIGN KEY ([OrganizationUserId]) REFERENCES [dbo].[OrganizationUser] ([Id]) ); - -GO -CREATE NONCLUSTERED INDEX [IX_CollectionUser_CollectionId] - ON [dbo].[CollectionUser]([CollectionId] ASC); - diff --git a/src/Sql/dbo/Views/CollectionUserUserDetailsView.sql b/src/Sql/dbo/Views/CollectionUserUserDetailsView.sql deleted file mode 100644 index 7fb9b88526..0000000000 --- a/src/Sql/dbo/Views/CollectionUserUserDetailsView.sql +++ /dev/null @@ -1,28 +0,0 @@ -CREATE VIEW [dbo].[CollectionUserUserDetailsView] -AS -SELECT - OU.[Id] AS [OrganizationUserId], - OU.[OrganizationId], - OU.[AccessAll], - CU.[Id], - CU.[CollectionId], - U.[Name], - ISNULL(U.[Email], OU.[Email]) Email, - OU.[Status], - OU.[Type], - CASE - WHEN OU.[AccessAll] = 0 AND CU.[ReadOnly] = 1 AND G.[AccessAll] = 0 AND CG.[ReadOnly] = 1 THEN 1 - ELSE 0 - END [ReadOnly] -FROM - [dbo].[OrganizationUser] OU -LEFT JOIN - [dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = OU.[Id] -LEFT JOIN - [dbo].[User] U ON U.[Id] = OU.[UserId] -LEFT JOIN - [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id] -LEFT JOIN - [dbo].[Group] G ON G.[Id] = GU.[GroupId] -LEFT JOIN - [dbo].[CollectionGroup] CG ON G.[AccessAll] = 0 AND CG.[GroupId] = GU.[GroupId] \ No newline at end of file diff --git a/src/Sql/dbo/Views/CollectionUserView.sql b/src/Sql/dbo/Views/CollectionUserView.sql deleted file mode 100644 index 3e81be94e9..0000000000 --- a/src/Sql/dbo/Views/CollectionUserView.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE VIEW [dbo].[CollectionUserView] -AS -SELECT - * -FROM - [dbo].[CollectionUser] \ No newline at end of file diff --git a/src/Sql/dbo/Views/GroupUserUserDetailsView.sql b/src/Sql/dbo/Views/GroupUserUserDetailsView.sql deleted file mode 100644 index 40e0355eab..0000000000 --- a/src/Sql/dbo/Views/GroupUserUserDetailsView.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE VIEW [dbo].[GroupUserUserDetailsView] -AS -SELECT - OU.[Id] AS [OrganizationUserId], - OU.[OrganizationId], - OU.[AccessAll], - GU.[GroupId], - U.[Name], - ISNULL(U.[Email], OU.[Email]) Email, - OU.[Status], - OU.[Type] -FROM - [dbo].[OrganizationUser] OU -INNER JOIN - [dbo].[GroupUser] GU ON GU.[OrganizationUserId] = OU.[Id] -INNER JOIN - [dbo].[User] U ON U.[Id] = OU.[UserId] \ No newline at end of file diff --git a/src/SqlUpdate/2017-05-11_00_AlterCollectionUser.sql b/src/SqlUpdate/2017-05-11_00_AlterCollectionUser.sql new file mode 100644 index 0000000000..a3326ba1f9 --- /dev/null +++ b/src/SqlUpdate/2017-05-11_00_AlterCollectionUser.sql @@ -0,0 +1,11 @@ +alter table [CollectionUser] drop constraint [PK_CollectionUser] +go + +alter table [CollectionUser] drop column id +go + +alter table [CollectionUser] drop column revisiondate +go + +alter table [CollectionUser] drop column creationdate +go