mirror of
https://github.com/bitwarden/server.git
synced 2024-11-25 12:45:18 +01:00
apis for bulk sharing
This commit is contained in:
parent
ebb1f9e1a8
commit
de552be25f
@ -346,6 +346,36 @@ namespace Bit.Api.Controllers
|
||||
string.IsNullOrWhiteSpace(model.FolderId) ? (Guid?)null : new Guid(model.FolderId), userId);
|
||||
}
|
||||
|
||||
[HttpPut("share")]
|
||||
[HttpPost("share")]
|
||||
public async Task PutShareMany([FromBody]CipherBulkShareRequestModel model)
|
||||
{
|
||||
var organizationId = new Guid(model.Ciphers.First().OrganizationId);
|
||||
if(!_currentContext.OrganizationUser(organizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var ciphers = await _cipherRepository.GetManyByUserIdAsync(userId, false);
|
||||
var ciphersDict = ciphers.ToDictionary(c => c.Id);
|
||||
|
||||
var shareCiphers = new List<Cipher>();
|
||||
foreach(var cipher in model.Ciphers)
|
||||
{
|
||||
var cipherGuid = new Guid(cipher.Id);
|
||||
if(!ciphersDict.ContainsKey(cipherGuid))
|
||||
{
|
||||
throw new BadRequestException("Trying to share ciphers that you do not own.");
|
||||
}
|
||||
|
||||
shareCiphers.Add(cipher.ToCipher(ciphersDict[cipherGuid]));
|
||||
}
|
||||
|
||||
await _cipherService.ShareManyAsync(shareCiphers, organizationId,
|
||||
model.CollectionIds.Select(c => new Guid(c)), userId);
|
||||
}
|
||||
|
||||
[HttpPost("purge")]
|
||||
public async Task PostPurge([FromBody]CipherPurgeRequestModel model)
|
||||
{
|
||||
|
@ -182,4 +182,50 @@ namespace Bit.Core.Models.Api
|
||||
public IEnumerable<string> Ids { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
}
|
||||
|
||||
public class CipherBulkShareRequestModel
|
||||
{
|
||||
[Required]
|
||||
public IEnumerable<string> CollectionIds { get; set; }
|
||||
[Required]
|
||||
public IEnumerable<CipherWithIdRequestModel> Ciphers { get; set; }
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if(!Ciphers?.Any() ?? false)
|
||||
{
|
||||
yield return new ValidationResult("You must select at least one cipher.",
|
||||
new string[] { nameof(Ciphers) });
|
||||
}
|
||||
else
|
||||
{
|
||||
var allHaveIds = true;
|
||||
var organizationIds = new HashSet<string>();
|
||||
foreach(var c in Ciphers)
|
||||
{
|
||||
organizationIds.Add(c.OrganizationId);
|
||||
if(allHaveIds)
|
||||
{
|
||||
allHaveIds = !(string.IsNullOrWhiteSpace(c.Id) || string.IsNullOrWhiteSpace(c.OrganizationId));
|
||||
}
|
||||
}
|
||||
|
||||
if(!allHaveIds)
|
||||
{
|
||||
yield return new ValidationResult("All Ciphers must have an Id and OrganizationId.",
|
||||
new string[] { nameof(Ciphers) });
|
||||
}
|
||||
else if(organizationIds.Count != 1)
|
||||
{
|
||||
yield return new ValidationResult("All ciphers must be for the same organization.");
|
||||
}
|
||||
}
|
||||
|
||||
if(!CollectionIds?.Any() ?? false)
|
||||
{
|
||||
yield return new ValidationResult("You must select at least one collection.",
|
||||
new string[] { nameof(CollectionIds) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace Bit.Core.Repositories
|
||||
Task MoveAsync(IEnumerable<Guid> ids, Guid? folderId, Guid userId);
|
||||
Task DeleteByUserIdAsync(Guid userId);
|
||||
Task UpdateUserKeysAndCiphersAsync(User user, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
||||
Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
||||
IEnumerable<CollectionCipher> collectionCiphers);
|
||||
|
@ -12,5 +12,7 @@ namespace Bit.Core.Repositories
|
||||
Task<ICollection<CollectionCipher>> GetManyByUserIdCipherIdAsync(Guid userId, Guid cipherId);
|
||||
Task UpdateCollectionsAsync(Guid cipherId, Guid userId, IEnumerable<Guid> collectionIds);
|
||||
Task UpdateCollectionsForAdminAsync(Guid cipherId, Guid organizationId, IEnumerable<Guid> collectionIds);
|
||||
Task UpdateCollectionsForCiphersAsync(IEnumerable<Guid> cipherIds, Guid userId, Guid organizationId,
|
||||
IEnumerable<Guid> collectionIds);
|
||||
}
|
||||
}
|
||||
|
@ -346,6 +346,86 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public async Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers)
|
||||
{
|
||||
if(!ciphers.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using(var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
using(var transaction = connection.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1. Create temp tables to bulk copy into.
|
||||
|
||||
var sqlCreateTemp = @"
|
||||
SELECT TOP 0 *
|
||||
INTO #TempCipher
|
||||
FROM [dbo].[Cipher]";
|
||||
|
||||
using(var cmd = new SqlCommand(sqlCreateTemp, connection, transaction))
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
// 2. Bulk copy into temp tables.
|
||||
using(var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
||||
{
|
||||
bulkCopy.DestinationTableName = "#TempCipher";
|
||||
var dataTable = BuildCiphersTable(ciphers);
|
||||
bulkCopy.WriteToServer(dataTable);
|
||||
}
|
||||
|
||||
// 3. Insert into real tables from temp tables and clean up.
|
||||
|
||||
// Intentionally not including Favorites, Folders, and CreationDate
|
||||
// since those are not meant to be bulk updated at this time
|
||||
var sql = @"
|
||||
UPDATE
|
||||
[dbo].[Cipher]
|
||||
SET
|
||||
[UserId] = TC.[UserId],
|
||||
[OrganizationId] = TC.[OrganizationId],
|
||||
[Type] = TC.[Type],
|
||||
[Data] = TC.[Data],
|
||||
[Attachments] = TC.[Attachments],
|
||||
[RevisionDate] = TC.[RevisionDate]
|
||||
FROM
|
||||
[dbo].[Cipher] C
|
||||
INNER JOIN
|
||||
#TempCipher TC ON C.Id = TC.Id
|
||||
WHERE
|
||||
C.[UserId] = @UserId
|
||||
|
||||
DROP TABLE #TempCipher";
|
||||
|
||||
using(var cmd = new SqlCommand(sql, connection, transaction))
|
||||
{
|
||||
cmd.Parameters.Add("@UserId", SqlDbType.UniqueIdentifier).Value = userId;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
await connection.ExecuteAsync(
|
||||
$"[{Schema}].[User_BumpAccountRevisionDate]",
|
||||
new { Id = userId },
|
||||
commandType: CommandType.StoredProcedure, transaction: transaction);
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders)
|
||||
{
|
||||
if(!ciphers.Any())
|
||||
|
@ -80,5 +80,23 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateCollectionsForCiphersAsync(IEnumerable<Guid> cipherIds, Guid userId,
|
||||
Guid organizationId, IEnumerable<Guid> collectionIds)
|
||||
{
|
||||
using(var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var results = await connection.ExecuteAsync(
|
||||
"[dbo].[CollectionCipher_UpdateCollectionsForCiphers]",
|
||||
new
|
||||
{
|
||||
CipherIds = cipherIds.ToGuidIdArrayTVP(),
|
||||
UserId = userId,
|
||||
OrganizationId = organizationId,
|
||||
CollectionIds = collectionIds.ToGuidIdArrayTVP()
|
||||
},
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ namespace Bit.Core.Services
|
||||
Task SaveFolderAsync(Folder folder);
|
||||
Task DeleteFolderAsync(Folder folder);
|
||||
Task ShareAsync(Cipher originalCipher, Cipher cipher, Guid organizationId, IEnumerable<Guid> collectionIds, Guid userId);
|
||||
Task ShareManyAsync(IEnumerable<Cipher> ciphers, Guid organizationId, IEnumerable<Guid> collectionIds, Guid sharingUserId);
|
||||
Task SaveCollectionsAsync(Cipher cipher, IEnumerable<Guid> collectionIds, Guid savingUserId, bool orgAdmin);
|
||||
Task ImportCiphersAsync(List<Folder> folders, List<CipherDetails> ciphers,
|
||||
IEnumerable<KeyValuePair<int, int>> folderRelationships);
|
||||
|
@ -401,6 +401,52 @@ namespace Bit.Core.Services
|
||||
await _pushService.PushSyncCipherUpdateAsync(cipher);
|
||||
}
|
||||
|
||||
public async Task ShareManyAsync(IEnumerable<Cipher> ciphers, Guid organizationId,
|
||||
IEnumerable<Guid> collectionIds, Guid sharingUserId)
|
||||
{
|
||||
var cipherIds = new List<Guid>();
|
||||
foreach(var cipher in ciphers)
|
||||
{
|
||||
if(cipher.Id == default(Guid))
|
||||
{
|
||||
throw new BadRequestException("All ciphers must already exist.");
|
||||
}
|
||||
|
||||
if(cipher.OrganizationId.HasValue)
|
||||
{
|
||||
throw new BadRequestException("One or more ciphers already belong to an organization.");
|
||||
}
|
||||
|
||||
if(!cipher.UserId.HasValue || cipher.UserId.Value != sharingUserId)
|
||||
{
|
||||
throw new BadRequestException("One or more ciphers do not belong to you.");
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(cipher.Attachments))
|
||||
{
|
||||
throw new BadRequestException("One or more ciphers have attachments.");
|
||||
}
|
||||
|
||||
cipher.UserId = null;
|
||||
cipher.OrganizationId = organizationId;
|
||||
cipher.RevisionDate = DateTime.UtcNow;
|
||||
cipherIds.Add(cipher.Id);
|
||||
}
|
||||
|
||||
await _cipherRepository.UpdateCiphersAsync(sharingUserId, ciphers);
|
||||
await _collectionCipherRepository.UpdateCollectionsForCiphersAsync(cipherIds, sharingUserId,
|
||||
organizationId, collectionIds);
|
||||
|
||||
// TODO: move this to a single event?
|
||||
foreach(var cipher in ciphers)
|
||||
{
|
||||
await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_Shared);
|
||||
}
|
||||
|
||||
// push
|
||||
await _pushService.PushSyncCiphersAsync(sharingUserId);
|
||||
}
|
||||
|
||||
public async Task SaveCollectionsAsync(Cipher cipher, IEnumerable<Guid> collectionIds, Guid savingUserId, bool orgAdmin)
|
||||
{
|
||||
if(cipher.Id == default(Guid))
|
||||
|
@ -225,5 +225,6 @@
|
||||
<Build Include="dbo\Stored Procedures\Organization_Search.sql" />
|
||||
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadCountByOrganizationIdEmail.sql" />
|
||||
<Build Include="dbo\Stored Procedures\CipherDetails_ReadWithoutOrganizationsByUserId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\CollectionCipher_UpdateCollectionsForCiphers.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,64 @@
|
||||
CREATE PROCEDURE [dbo].[CollectionCipher_UpdateCollectionsForCiphers]
|
||||
@CipherIds AS [dbo].[GuidIdArray] READONLY,
|
||||
@OrganizationId UNIQUEIDENTIFIER,
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@CollectionIds AS [dbo].[GuidIdArray] READONLY
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
CREATE TABLE #AvailableCollections (
|
||||
[Id] UNIQUEIDENTIFIER
|
||||
)
|
||||
|
||||
INSERT INTO #AvailableCollections
|
||||
SELECT
|
||||
C.[Id]
|
||||
FROM
|
||||
[dbo].[Collection] C
|
||||
INNER JOIN
|
||||
[Organization] O ON O.[Id] = C.[OrganizationId]
|
||||
INNER JOIN
|
||||
[dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId
|
||||
LEFT JOIN
|
||||
[dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = OU.[Id]
|
||||
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]
|
||||
WHERE
|
||||
O.[Id] = @OrganizationId
|
||||
AND O.[Enabled] = 1
|
||||
AND OU.[Status] = 2 -- Confirmed
|
||||
AND (
|
||||
OU.[AccessAll] = 1
|
||||
OR CU.[ReadOnly] = 0
|
||||
OR G.[AccessAll] = 1
|
||||
OR CG.[ReadOnly] = 0
|
||||
)
|
||||
|
||||
IF (SELECT COUNT(1) FROM #AvailableCollections) < 1
|
||||
BEGIN
|
||||
-- No writable collections available to share with in this organization.
|
||||
RETURN
|
||||
END
|
||||
|
||||
INSERT INTO [dbo].[CollectionCipher]
|
||||
(
|
||||
[CollectionId],
|
||||
[CipherId]
|
||||
)
|
||||
SELECT
|
||||
[Collection].[Id],
|
||||
[Cipher].[Id]
|
||||
FROM
|
||||
@CollectionIds [Collection]
|
||||
INNER JOIN
|
||||
@CipherIds [Cipher] ON 1 = 1
|
||||
WHERE
|
||||
[Collection].[Id] IN (SELECT [Id] FROM #AvailableCollections)
|
||||
|
||||
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
|
||||
END
|
@ -12,8 +12,8 @@ BEGIN
|
||||
OR G.[AccessAll] = 1
|
||||
OR CU.[ReadOnly] = 0
|
||||
OR CG.[ReadOnly] = 0
|
||||
THEN 1
|
||||
ELSE 0
|
||||
THEN 0
|
||||
ELSE 1
|
||||
END [ReadOnly]
|
||||
FROM
|
||||
[dbo].[CollectionView] C
|
||||
|
@ -6,13 +6,13 @@ BEGIN
|
||||
|
||||
DECLARE @Storage BIGINT
|
||||
|
||||
CREATE TABLE #Temp
|
||||
CREATE TABLE #OrgStorageUpdateTemp
|
||||
(
|
||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||
[Attachments] VARCHAR(MAX) NULL
|
||||
)
|
||||
|
||||
INSERT INTO #Temp
|
||||
INSERT INTO #OrgStorageUpdateTemp
|
||||
SELECT
|
||||
[Id],
|
||||
[Attachments]
|
||||
@ -32,14 +32,14 @@ BEGIN
|
||||
OPENJSON([Attachments])
|
||||
) [Size]
|
||||
FROM
|
||||
#Temp
|
||||
#OrgStorageUpdateTemp
|
||||
)
|
||||
SELECT
|
||||
@Storage = SUM([Size])
|
||||
FROM
|
||||
[CTE]
|
||||
|
||||
DROP TABLE #Temp
|
||||
DROP TABLE #OrgStorageUpdateTemp
|
||||
|
||||
UPDATE
|
||||
[dbo].[Organization]
|
||||
|
@ -6,13 +6,13 @@ BEGIN
|
||||
|
||||
DECLARE @Storage BIGINT
|
||||
|
||||
CREATE TABLE #Temp
|
||||
CREATE TABLE #UserStorageUpdateTemp
|
||||
(
|
||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||
[Attachments] VARCHAR(MAX) NULL
|
||||
)
|
||||
|
||||
INSERT INTO #Temp
|
||||
INSERT INTO #UserStorageUpdateTemp
|
||||
SELECT
|
||||
[Id],
|
||||
[Attachments]
|
||||
@ -31,14 +31,14 @@ BEGIN
|
||||
OPENJSON([Attachments])
|
||||
) [Size]
|
||||
FROM
|
||||
#Temp
|
||||
#UserStorageUpdateTemp
|
||||
)
|
||||
SELECT
|
||||
@Storage = SUM([CTE].[Size])
|
||||
FROM
|
||||
[CTE]
|
||||
|
||||
DROP TABLE #Temp
|
||||
DROP TABLE #UserStorageUpdateTemp
|
||||
|
||||
UPDATE
|
||||
[dbo].[User]
|
||||
|
@ -18,8 +18,8 @@ BEGIN
|
||||
OR G.[AccessAll] = 1
|
||||
OR CU.[ReadOnly] = 0
|
||||
OR CG.[ReadOnly] = 0
|
||||
THEN 1
|
||||
ELSE 0
|
||||
THEN 0
|
||||
ELSE 1
|
||||
END [ReadOnly]
|
||||
FROM
|
||||
[dbo].[CollectionView] C
|
||||
@ -62,13 +62,13 @@ BEGIN
|
||||
|
||||
DECLARE @Storage BIGINT
|
||||
|
||||
CREATE TABLE #Temp
|
||||
CREATE TABLE #OrgStorageUpdateTemp
|
||||
(
|
||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||
[Attachments] VARCHAR(MAX) NULL
|
||||
)
|
||||
|
||||
INSERT INTO #Temp
|
||||
INSERT INTO #OrgStorageUpdateTemp
|
||||
SELECT
|
||||
[Id],
|
||||
[Attachments]
|
||||
@ -88,14 +88,14 @@ BEGIN
|
||||
OPENJSON([Attachments])
|
||||
) [Size]
|
||||
FROM
|
||||
#Temp
|
||||
#OrgStorageUpdateTemp
|
||||
)
|
||||
SELECT
|
||||
@Storage = SUM([Size])
|
||||
FROM
|
||||
[CTE]
|
||||
|
||||
DROP TABLE #Temp
|
||||
DROP TABLE #OrgStorageUpdateTemp
|
||||
|
||||
UPDATE
|
||||
[dbo].[Organization]
|
||||
@ -121,13 +121,13 @@ BEGIN
|
||||
|
||||
DECLARE @Storage BIGINT
|
||||
|
||||
CREATE TABLE #Temp
|
||||
CREATE TABLE #UserStorageUpdateTemp
|
||||
(
|
||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||
[Attachments] VARCHAR(MAX) NULL
|
||||
)
|
||||
|
||||
INSERT INTO #Temp
|
||||
INSERT INTO #UserStorageUpdateTemp
|
||||
SELECT
|
||||
[Id],
|
||||
[Attachments]
|
||||
@ -146,14 +146,14 @@ BEGIN
|
||||
OPENJSON([Attachments])
|
||||
) [Size]
|
||||
FROM
|
||||
#Temp
|
||||
#UserStorageUpdateTemp
|
||||
)
|
||||
SELECT
|
||||
@Storage = SUM([CTE].[Size])
|
||||
FROM
|
||||
[CTE]
|
||||
|
||||
DROP TABLE #Temp
|
||||
DROP TABLE #UserStorageUpdateTemp
|
||||
|
||||
UPDATE
|
||||
[dbo].[User]
|
||||
@ -164,3 +164,75 @@ BEGIN
|
||||
[Id] = @Id
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID('[dbo].[CollectionCipher_UpdateCollectionsForCiphers]') IS NOT NULL
|
||||
BEGIN
|
||||
DROP PROCEDURE [dbo].[CollectionCipher_UpdateCollectionsForCiphers]
|
||||
END
|
||||
GO
|
||||
|
||||
CREATE PROCEDURE [dbo].[CollectionCipher_UpdateCollectionsForCiphers]
|
||||
@CipherIds AS [dbo].[GuidIdArray] READONLY,
|
||||
@OrganizationId UNIQUEIDENTIFIER,
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@CollectionIds AS [dbo].[GuidIdArray] READONLY
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
CREATE TABLE #AvailableCollections (
|
||||
[Id] UNIQUEIDENTIFIER
|
||||
)
|
||||
|
||||
INSERT INTO #AvailableCollections
|
||||
SELECT
|
||||
C.[Id]
|
||||
FROM
|
||||
[dbo].[Collection] C
|
||||
INNER JOIN
|
||||
[Organization] O ON O.[Id] = C.[OrganizationId]
|
||||
INNER JOIN
|
||||
[dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId
|
||||
LEFT JOIN
|
||||
[dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = OU.[Id]
|
||||
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]
|
||||
WHERE
|
||||
O.[Id] = @OrganizationId
|
||||
AND O.[Enabled] = 1
|
||||
AND OU.[Status] = 2 -- Confirmed
|
||||
AND (
|
||||
OU.[AccessAll] = 1
|
||||
OR CU.[ReadOnly] = 0
|
||||
OR G.[AccessAll] = 1
|
||||
OR CG.[ReadOnly] = 0
|
||||
)
|
||||
|
||||
IF (SELECT COUNT(1) FROM #AvailableCollections) < 1
|
||||
BEGIN
|
||||
-- No writable collections available to share with in this organization.
|
||||
RETURN
|
||||
END
|
||||
|
||||
INSERT INTO [dbo].[CollectionCipher]
|
||||
(
|
||||
[CollectionId],
|
||||
[CipherId]
|
||||
)
|
||||
SELECT
|
||||
[Collection].[Id],
|
||||
[Cipher].[Id]
|
||||
FROM
|
||||
@CollectionIds [Collection]
|
||||
INNER JOIN
|
||||
@CipherIds [Cipher] ON 1 = 1
|
||||
WHERE
|
||||
[Collection].[Id] IN (SELECT [Id] FROM #AvailableCollections)
|
||||
|
||||
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
|
||||
END
|
||||
GO
|
||||
|
Loading…
Reference in New Issue
Block a user