mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
[PM-22974] Cascade delete NotificationStatus entities (#6011)
* cascade delete NotificationStatus entities * add userId to test for foreign constraint * add missing properties for Notification * add check for foreign key
This commit is contained in:
@ -13,6 +13,12 @@ public class NotificationStatusEntityTypeConfiguration : IEntityTypeConfiguratio
|
|||||||
.HasKey(ns => new { ns.UserId, ns.NotificationId })
|
.HasKey(ns => new { ns.UserId, ns.NotificationId })
|
||||||
.IsClustered();
|
.IsClustered();
|
||||||
|
|
||||||
|
builder
|
||||||
|
.HasOne(ns => ns.Notification)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(ns => ns.NotificationId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
builder.ToTable(nameof(NotificationStatus));
|
builder.ToTable(nameof(NotificationStatus));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@ CREATE TABLE [dbo].[NotificationStatus]
|
|||||||
[ReadDate] DATETIME2 (7) NULL,
|
[ReadDate] DATETIME2 (7) NULL,
|
||||||
[DeletedDate] DATETIME2 (7) NULL,
|
[DeletedDate] DATETIME2 (7) NULL,
|
||||||
CONSTRAINT [PK_NotificationStatus] PRIMARY KEY CLUSTERED ([NotificationId] ASC, [UserId] ASC),
|
CONSTRAINT [PK_NotificationStatus] PRIMARY KEY CLUSTERED ([NotificationId] ASC, [UserId] ASC),
|
||||||
CONSTRAINT [FK_NotificationStatus_Notification] FOREIGN KEY ([NotificationId]) REFERENCES [dbo].[Notification] ([Id]),
|
CONSTRAINT [FK_NotificationStatus_Notification] FOREIGN KEY ([NotificationId]) REFERENCES [dbo].[Notification] ([Id]) ON DELETE CASCADE,
|
||||||
CONSTRAINT [FK_NotificationStatus_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
|
CONSTRAINT [FK_NotificationStatus_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
|
||||||
);
|
);
|
||||||
|
|
||||||
GO
|
GO
|
||||||
CREATE NONCLUSTERED INDEX [IX_NotificationStatus_UserId]
|
CREATE NONCLUSTERED INDEX [IX_NotificationStatus_UserId]
|
||||||
ON [dbo].[NotificationStatus]([UserId] ASC);
|
ON [dbo].[NotificationStatus]([UserId] ASC);
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ using Bit.Core.Billing.Enums;
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
|
using Bit.Core.NotificationCenter.Repositories;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Vault.Entities;
|
using Bit.Core.Vault.Entities;
|
||||||
using Bit.Core.Vault.Enums;
|
using Bit.Core.Vault.Enums;
|
||||||
@ -976,8 +978,11 @@ public class CipherRepositoryTests
|
|||||||
[DatabaseTheory, DatabaseData]
|
[DatabaseTheory, DatabaseData]
|
||||||
public async Task DeleteCipherWithSecurityTaskAsync_Works(
|
public async Task DeleteCipherWithSecurityTaskAsync_Works(
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
|
IUserRepository userRepository,
|
||||||
ICipherRepository cipherRepository,
|
ICipherRepository cipherRepository,
|
||||||
ISecurityTaskRepository securityTaskRepository)
|
ISecurityTaskRepository securityTaskRepository,
|
||||||
|
INotificationRepository notificationRepository,
|
||||||
|
INotificationStatusRepository notificationStatusRepository)
|
||||||
{
|
{
|
||||||
var organization = await organizationRepository.CreateAsync(new Organization
|
var organization = await organizationRepository.CreateAsync(new Organization
|
||||||
{
|
{
|
||||||
@ -987,6 +992,14 @@ public class CipherRepositoryTests
|
|||||||
BillingEmail = ""
|
BillingEmail = ""
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var user = await userRepository.CreateAsync(new User
|
||||||
|
{
|
||||||
|
Name = "Test User",
|
||||||
|
Email = $"test+{Guid.NewGuid()}@email.com",
|
||||||
|
ApiKey = "TEST",
|
||||||
|
SecurityStamp = "stamp",
|
||||||
|
});
|
||||||
|
|
||||||
var cipher1 = new Cipher { Type = CipherType.Login, OrganizationId = organization.Id, Data = "", };
|
var cipher1 = new Cipher { Type = CipherType.Login, OrganizationId = organization.Id, Data = "", };
|
||||||
await cipherRepository.CreateAsync(cipher1);
|
await cipherRepository.CreateAsync(cipher1);
|
||||||
|
|
||||||
@ -1012,6 +1025,20 @@ public class CipherRepositoryTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
await securityTaskRepository.CreateManyAsync(tasks);
|
await securityTaskRepository.CreateManyAsync(tasks);
|
||||||
|
var notification = await notificationRepository.CreateAsync(new Notification
|
||||||
|
{
|
||||||
|
OrganizationId = organization.Id,
|
||||||
|
UserId = user.Id,
|
||||||
|
TaskId = tasks[1].Id,
|
||||||
|
CreationDate = DateTime.UtcNow,
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
});
|
||||||
|
await notificationStatusRepository.CreateAsync(new NotificationStatus
|
||||||
|
{
|
||||||
|
NotificationId = notification.Id,
|
||||||
|
UserId = user.Id,
|
||||||
|
ReadDate = DateTime.UtcNow,
|
||||||
|
});
|
||||||
|
|
||||||
// Delete cipher with pending security task
|
// Delete cipher with pending security task
|
||||||
await cipherRepository.DeleteAsync(cipher1);
|
await cipherRepository.DeleteAsync(cipher1);
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_NotificationStatus_Notification')
|
||||||
|
BEGIN
|
||||||
|
ALTER TABLE [dbo].[NotificationStatus] DROP CONSTRAINT [FK_NotificationStatus_Notification]
|
||||||
|
END
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[NotificationStatus]
|
||||||
|
ADD CONSTRAINT [FK_NotificationStatus_Notification] FOREIGN KEY ([NotificationId]) REFERENCES [dbo].[Notification]([Id]) ON DELETE CASCADE
|
||||||
|
END
|
||||||
|
GO
|
Reference in New Issue
Block a user