diff --git a/src/Core/Models/Api/Public/CollectionBaseModel.cs b/src/Core/Models/Api/Public/CollectionBaseModel.cs new file mode 100644 index 0000000000..0b5a3c60cd --- /dev/null +++ b/src/Core/Models/Api/Public/CollectionBaseModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Bit.Core.Models.Api.Public +{ + public abstract class CollectionBaseModel + { + /// + /// External identifier for reference or linking this collection to another system. + /// + /// external_id_123456 + [StringLength(300)] + public string ExternalId { get; set; } + } +} diff --git a/src/Core/Models/Api/Public/GroupBaseModel.cs b/src/Core/Models/Api/Public/GroupBaseModel.cs index 8500341a74..d748db23e3 100644 --- a/src/Core/Models/Api/Public/GroupBaseModel.cs +++ b/src/Core/Models/Api/Public/GroupBaseModel.cs @@ -18,7 +18,7 @@ namespace Bit.Core.Models.Api.Public [Required] public bool? AccessAll { get; set; } /// - /// External identifier linking this group to another system, such as a user directory. + /// External identifier for reference or linking this group to another system, such as a user directory. /// /// external_id_123456 [StringLength(300)] diff --git a/src/Core/Models/Api/Public/MemberBaseModel.cs b/src/Core/Models/Api/Public/MemberBaseModel.cs index a8745de7ed..63bb46ea28 100644 --- a/src/Core/Models/Api/Public/MemberBaseModel.cs +++ b/src/Core/Models/Api/Public/MemberBaseModel.cs @@ -46,7 +46,7 @@ namespace Bit.Core.Models.Api.Public [Required] public bool? AccessAll { get; set; } /// - /// External identifier linking this member to another system, such as a user directory. + /// External identifier for reference or linking this member to another system, such as a user directory. /// /// external_id_123456 [StringLength(300)] diff --git a/src/Core/Models/Api/Public/Request/CollectionUpdateRequestModel.cs b/src/Core/Models/Api/Public/Request/CollectionUpdateRequestModel.cs index 5836d938ee..f86764f3ac 100644 --- a/src/Core/Models/Api/Public/Request/CollectionUpdateRequestModel.cs +++ b/src/Core/Models/Api/Public/Request/CollectionUpdateRequestModel.cs @@ -3,7 +3,7 @@ using Bit.Core.Models.Table; namespace Bit.Core.Models.Api.Public { - public class CollectionUpdateRequestModel + public class CollectionUpdateRequestModel : CollectionBaseModel { /// /// The associated groups that this collection is assigned to. @@ -12,8 +12,7 @@ namespace Bit.Core.Models.Api.Public public Collection ToCollection(Collection existingCollection) { - // TODO - // existingCollection.ExternalId = ExternalId; + existingCollection.ExternalId = ExternalId; return existingCollection; } } diff --git a/src/Core/Models/Api/Public/Response/CollectionResponseModel.cs b/src/Core/Models/Api/Public/Response/CollectionResponseModel.cs index 25155bc996..690ac11d64 100644 --- a/src/Core/Models/Api/Public/Response/CollectionResponseModel.cs +++ b/src/Core/Models/Api/Public/Response/CollectionResponseModel.cs @@ -10,7 +10,7 @@ namespace Bit.Core.Models.Api.Public /// /// A collection. /// - public class CollectionResponseModel : IResponseModel + public class CollectionResponseModel : CollectionBaseModel, IResponseModel { public CollectionResponseModel(Collection collection, IEnumerable groups) { @@ -20,7 +20,7 @@ namespace Bit.Core.Models.Api.Public } Id = collection.Id; - // ExternalId = group.ExternalId; TODO: Add external is for referencing purposes + ExternalId = collection.ExternalId; Groups = groups?.Select(c => new AssociationWithPermissionsResponseModel(c)); } diff --git a/src/Core/Models/Api/Request/CollectionRequestModel.cs b/src/Core/Models/Api/Request/CollectionRequestModel.cs index b912927dd5..551aadf940 100644 --- a/src/Core/Models/Api/Request/CollectionRequestModel.cs +++ b/src/Core/Models/Api/Request/CollectionRequestModel.cs @@ -13,6 +13,8 @@ namespace Bit.Core.Models.Api [EncryptedString] [EncryptedStringLength(1000)] public string Name { get; set; } + [StringLength(300)] + public string ExternalId { get; set; } public IEnumerable Groups { get; set; } public Collection ToCollection(Guid orgId) @@ -26,6 +28,7 @@ namespace Bit.Core.Models.Api public Collection ToCollection(Collection existingCollection) { existingCollection.Name = Name; + existingCollection.ExternalId = ExternalId; return existingCollection; } } diff --git a/src/Core/Models/Api/Response/CollectionResponseModel.cs b/src/Core/Models/Api/Response/CollectionResponseModel.cs index 6458455361..ce2508660e 100644 --- a/src/Core/Models/Api/Response/CollectionResponseModel.cs +++ b/src/Core/Models/Api/Response/CollectionResponseModel.cs @@ -19,11 +19,13 @@ namespace Bit.Core.Models.Api Id = collection.Id.ToString(); OrganizationId = collection.OrganizationId.ToString(); Name = collection.Name; + ExternalId = collection.ExternalId; } public string Id { get; set; } public string OrganizationId { get; set; } public string Name { get; set; } + public string ExternalId { get; set; } } public class CollectionDetailsResponseModel : CollectionResponseModel diff --git a/src/Core/Models/Table/Collection.cs b/src/Core/Models/Table/Collection.cs index d6a0bdecf6..369592789e 100644 --- a/src/Core/Models/Table/Collection.cs +++ b/src/Core/Models/Table/Collection.cs @@ -8,6 +8,7 @@ namespace Bit.Core.Models.Table public Guid Id { get; set; } public Guid OrganizationId { get; set; } public string Name { get; set; } + public string ExternalId { get; set; } public DateTime CreationDate { get; internal set; } = DateTime.UtcNow; public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow; diff --git a/src/Sql/dbo/Stored Procedures/Collection_Create.sql b/src/Sql/dbo/Stored Procedures/Collection_Create.sql index b939fb4146..c9e2f11853 100644 --- a/src/Sql/dbo/Stored Procedures/Collection_Create.sql +++ b/src/Sql/dbo/Stored Procedures/Collection_Create.sql @@ -2,6 +2,7 @@ @Id UNIQUEIDENTIFIER, @OrganizationId UNIQUEIDENTIFIER, @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), @CreationDate DATETIME2(7), @RevisionDate DATETIME2(7) AS @@ -13,6 +14,7 @@ BEGIN [Id], [OrganizationId], [Name], + [ExternalId], [CreationDate], [RevisionDate] ) @@ -21,6 +23,7 @@ BEGIN @Id, @OrganizationId, @Name, + @ExternalId, @CreationDate, @RevisionDate ) diff --git a/src/Sql/dbo/Stored Procedures/Collection_CreateWithGroups.sql b/src/Sql/dbo/Stored Procedures/Collection_CreateWithGroups.sql index c4f90cd782..b0475a4a73 100644 --- a/src/Sql/dbo/Stored Procedures/Collection_CreateWithGroups.sql +++ b/src/Sql/dbo/Stored Procedures/Collection_CreateWithGroups.sql @@ -2,6 +2,7 @@ @Id UNIQUEIDENTIFIER, @OrganizationId UNIQUEIDENTIFIER, @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), @CreationDate DATETIME2(7), @RevisionDate DATETIME2(7), @Groups AS [dbo].[SelectionReadOnlyArray] READONLY @@ -9,7 +10,7 @@ AS BEGIN SET NOCOUNT ON - EXEC [dbo].[Collection_Create] @Id, @OrganizationId, @Name, @CreationDate, @RevisionDate + EXEC [dbo].[Collection_Create] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate ;WITH [AvailableGroupsCTE] AS( SELECT diff --git a/src/Sql/dbo/Stored Procedures/Collection_Update.sql b/src/Sql/dbo/Stored Procedures/Collection_Update.sql index b6e7dbfc8c..e75f088d7d 100644 --- a/src/Sql/dbo/Stored Procedures/Collection_Update.sql +++ b/src/Sql/dbo/Stored Procedures/Collection_Update.sql @@ -2,6 +2,7 @@ @Id UNIQUEIDENTIFIER, @OrganizationId UNIQUEIDENTIFIER, @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), @CreationDate DATETIME2(7), @RevisionDate DATETIME2(7) AS @@ -13,6 +14,7 @@ BEGIN SET [OrganizationId] = @OrganizationId, [Name] = @Name, + [ExternalId] = @ExternalId, [CreationDate] = @CreationDate, [RevisionDate] = @RevisionDate WHERE diff --git a/src/Sql/dbo/Stored Procedures/Collection_UpdateWithGroups.sql b/src/Sql/dbo/Stored Procedures/Collection_UpdateWithGroups.sql index 6a4d23d6e7..f11231dc71 100644 --- a/src/Sql/dbo/Stored Procedures/Collection_UpdateWithGroups.sql +++ b/src/Sql/dbo/Stored Procedures/Collection_UpdateWithGroups.sql @@ -2,6 +2,7 @@ @Id UNIQUEIDENTIFIER, @OrganizationId UNIQUEIDENTIFIER, @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), @CreationDate DATETIME2(7), @RevisionDate DATETIME2(7), @Groups AS [dbo].[SelectionReadOnlyArray] READONLY @@ -9,7 +10,7 @@ AS BEGIN SET NOCOUNT ON - EXEC [dbo].[Collection_Update] @Id, @OrganizationId, @Name, @CreationDate, @RevisionDate + EXEC [dbo].[Collection_Update] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate ;WITH [AvailableGroupsCTE] AS( SELECT diff --git a/src/Sql/dbo/Tables/Collection.sql b/src/Sql/dbo/Tables/Collection.sql index 02f011a023..0106f341df 100644 --- a/src/Sql/dbo/Tables/Collection.sql +++ b/src/Sql/dbo/Tables/Collection.sql @@ -2,6 +2,7 @@ [Id] UNIQUEIDENTIFIER NOT NULL, [OrganizationId] UNIQUEIDENTIFIER NOT NULL, [Name] VARCHAR (MAX) NOT NULL, + [ExternalId] NVARCHAR (300) NULL, [CreationDate] DATETIME2 (7) NOT NULL, [RevisionDate] DATETIME2 (7) NOT NULL, CONSTRAINT [PK_Collection] PRIMARY KEY CLUSTERED ([Id] ASC), diff --git a/util/Setup/DbScripts/2019-03-01_00_OrgApi.sql b/util/Setup/DbScripts/2019-03-01_00_OrgApi.sql index 2f24377914..5e7c93eae2 100644 --- a/util/Setup/DbScripts/2019-03-01_00_OrgApi.sql +++ b/util/Setup/DbScripts/2019-03-01_00_OrgApi.sql @@ -384,3 +384,199 @@ BEGIN [OrganizationUserId] = @Id END GO + +IF COL_LENGTH('[dbo].[Collection]', 'ExternalId') IS NULL +BEGIN + ALTER TABLE + [dbo].[Collection] + ADD + [ExternalId] NVARCHAR(300) NULL +END +GO + +IF OBJECT_ID('[dbo].[Collection_Create]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[Collection_Create] +END +GO + +CREATE PROCEDURE [dbo].[Collection_Create] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7) +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[Collection] + ( + [Id], + [OrganizationId], + [Name], + [ExternalId], + [CreationDate], + [RevisionDate] + ) + VALUES + ( + @Id, + @OrganizationId, + @Name, + @ExternalId, + @CreationDate, + @RevisionDate + ) + + EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId +END +GO + +IF OBJECT_ID('[dbo].[Collection_Update]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[Collection_Update] +END +GO + +CREATE PROCEDURE [dbo].[Collection_Update] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7) +AS +BEGIN + SET NOCOUNT ON + + UPDATE + [dbo].[Collection] + SET + [OrganizationId] = @OrganizationId, + [Name] = @Name, + [ExternalId] = @ExternalId, + [CreationDate] = @CreationDate, + [RevisionDate] = @RevisionDate + WHERE + [Id] = @Id + + EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId +END +GO + +IF OBJECT_ID('[dbo].[Collection_CreateWithGroups]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[Collection_CreateWithGroups] +END +GO + +CREATE PROCEDURE [dbo].[Collection_CreateWithGroups] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Groups AS [dbo].[SelectionReadOnlyArray] READONLY +AS +BEGIN + SET NOCOUNT ON + + EXEC [dbo].[Collection_Create] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate + + ;WITH [AvailableGroupsCTE] AS( + SELECT + [Id] + FROM + [dbo].[Group] + WHERE + [OrganizationId] = @OrganizationId + ) + INSERT INTO [dbo].[CollectionGroup] + ( + [CollectionId], + [GroupId], + [ReadOnly] + ) + SELECT + @Id, + [Id], + [ReadOnly] + FROM + @Groups + WHERE + [Id] IN (SELECT [Id] FROM [AvailableGroupsCTE]) + + EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId +END +GO + +IF OBJECT_ID('[dbo].[Collection_UpdateWithGroups]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[Collection_UpdateWithGroups] +END +GO + +CREATE PROCEDURE [dbo].[Collection_UpdateWithGroups] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @Name VARCHAR(MAX), + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Groups AS [dbo].[SelectionReadOnlyArray] READONLY +AS +BEGIN + SET NOCOUNT ON + + EXEC [dbo].[Collection_Update] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate + + ;WITH [AvailableGroupsCTE] AS( + SELECT + Id + FROM + [dbo].[Group] + WHERE + OrganizationId = @OrganizationId + ) + MERGE + [dbo].[CollectionGroup] AS [Target] + USING + @Groups AS [Source] + ON + [Target].[CollectionId] = @Id + AND [Target].[GroupId] = [Source].[Id] + WHEN NOT MATCHED BY TARGET + AND [Source].[Id] IN (SELECT [Id] FROM [AvailableGroupsCTE]) THEN + INSERT VALUES + ( + @Id, + [Source].[Id], + [Source].[ReadOnly] + ) + WHEN MATCHED AND [Target].[ReadOnly] != [Source].[ReadOnly] THEN + UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly] + WHEN NOT MATCHED BY SOURCE + AND [Target].[CollectionId] = @Id THEN + DELETE + ; + + EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId +END +GO + +IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'CollectionView') +BEGIN + DROP VIEW [dbo].[CollectionView] +END +GO + +CREATE VIEW [dbo].[CollectionView] +AS +SELECT + * +FROM + [dbo].[Collection] +GO