mirror of
https://github.com/bitwarden/server.git
synced 2024-11-30 13:33:24 +01:00
PM-15066 added drop feature and unit tests. (#5053)
This commit is contained in:
parent
052235bed6
commit
92b94fd4ee
@ -7,7 +7,6 @@ using Bit.Core.Tools.Models.Data;
|
|||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
||||||
using Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
|
using Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
|
||||||
using Bit.Core.Tools.ReportFeatures.Requests;
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
using Bit.Core.Tools.Requests;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -21,18 +20,21 @@ public class ReportsController : Controller
|
|||||||
private readonly IMemberAccessCipherDetailsQuery _memberAccessCipherDetailsQuery;
|
private readonly IMemberAccessCipherDetailsQuery _memberAccessCipherDetailsQuery;
|
||||||
private readonly IAddPasswordHealthReportApplicationCommand _addPwdHealthReportAppCommand;
|
private readonly IAddPasswordHealthReportApplicationCommand _addPwdHealthReportAppCommand;
|
||||||
private readonly IGetPasswordHealthReportApplicationQuery _getPwdHealthReportAppQuery;
|
private readonly IGetPasswordHealthReportApplicationQuery _getPwdHealthReportAppQuery;
|
||||||
|
private readonly IDropPasswordHealthReportApplicationCommand _dropPwdHealthReportAppCommand;
|
||||||
|
|
||||||
public ReportsController(
|
public ReportsController(
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
IMemberAccessCipherDetailsQuery memberAccessCipherDetailsQuery,
|
IMemberAccessCipherDetailsQuery memberAccessCipherDetailsQuery,
|
||||||
IAddPasswordHealthReportApplicationCommand addPasswordHealthReportApplicationCommand,
|
IAddPasswordHealthReportApplicationCommand addPasswordHealthReportApplicationCommand,
|
||||||
IGetPasswordHealthReportApplicationQuery getPasswordHealthReportApplicationQuery
|
IGetPasswordHealthReportApplicationQuery getPasswordHealthReportApplicationQuery,
|
||||||
|
IDropPasswordHealthReportApplicationCommand dropPwdHealthReportAppCommand
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_memberAccessCipherDetailsQuery = memberAccessCipherDetailsQuery;
|
_memberAccessCipherDetailsQuery = memberAccessCipherDetailsQuery;
|
||||||
_addPwdHealthReportAppCommand = addPasswordHealthReportApplicationCommand;
|
_addPwdHealthReportAppCommand = addPasswordHealthReportApplicationCommand;
|
||||||
_getPwdHealthReportAppQuery = getPasswordHealthReportApplicationQuery;
|
_getPwdHealthReportAppQuery = getPasswordHealthReportApplicationQuery;
|
||||||
|
_dropPwdHealthReportAppCommand = dropPwdHealthReportAppCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -161,4 +163,26 @@ public class ReportsController : Controller
|
|||||||
|
|
||||||
return await _addPwdHealthReportAppCommand.AddPasswordHealthReportApplicationAsync(commandRequests);
|
return await _addPwdHealthReportAppCommand.AddPasswordHealthReportApplicationAsync(commandRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Drops a record from PasswordHealthReportApplication
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">
|
||||||
|
/// A single instance of DropPasswordHealthReportApplicationRequest
|
||||||
|
/// { OrganizationId, array of PasswordHealthReportApplicationIds }
|
||||||
|
/// </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="NotFoundException">If user does not have access to the organization</exception>
|
||||||
|
/// <exception cref="BadRequestException">If the organization does not have any records</exception>
|
||||||
|
[HttpDelete("password-health-report-application")]
|
||||||
|
public async Task DropPasswordHealthReportApplication(
|
||||||
|
[FromBody] DropPasswordHealthReportApplicationRequest request)
|
||||||
|
{
|
||||||
|
if (!await _currentContext.AccessReports(request.OrganizationId))
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _dropPwdHealthReportAppCommand.DropPasswordHealthReportApplicationAsync(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Tools.Entities;
|
||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
||||||
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
using Bit.Core.Tools.Repositories;
|
using Bit.Core.Tools.Repositories;
|
||||||
using Bit.Core.Tools.Requests;
|
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures;
|
namespace Bit.Core.Tools.ReportFeatures;
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
||||||
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
|
using Bit.Core.Tools.Repositories;
|
||||||
|
|
||||||
|
namespace Bit.Core.Tools.ReportFeatures;
|
||||||
|
|
||||||
|
public class DropPasswordHealthReportApplicationCommand : IDropPasswordHealthReportApplicationCommand
|
||||||
|
{
|
||||||
|
private IPasswordHealthReportApplicationRepository _passwordHealthReportApplicationRepo;
|
||||||
|
|
||||||
|
public DropPasswordHealthReportApplicationCommand(
|
||||||
|
IPasswordHealthReportApplicationRepository passwordHealthReportApplicationRepository)
|
||||||
|
{
|
||||||
|
_passwordHealthReportApplicationRepo = passwordHealthReportApplicationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DropPasswordHealthReportApplicationAsync(DropPasswordHealthReportApplicationRequest request)
|
||||||
|
{
|
||||||
|
var data = await _passwordHealthReportApplicationRepo.GetByOrganizationIdAsync(request.OrganizationId);
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Organization does not have any records.");
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Where(_ => request.PasswordHealthReportApplicationIds.Contains(_.Id)).ToList().ForEach(async _ =>
|
||||||
|
{
|
||||||
|
await _passwordHealthReportApplicationRepo.DeleteAsync(_);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Tools.Entities;
|
||||||
using Bit.Core.Tools.Requests;
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
|
|
||||||
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
|
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
|
||||||
|
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
|
|
||||||
|
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
|
||||||
|
|
||||||
|
public interface IDropPasswordHealthReportApplicationCommand
|
||||||
|
{
|
||||||
|
Task DropPasswordHealthReportApplicationAsync(DropPasswordHealthReportApplicationRequest request);
|
||||||
|
}
|
||||||
|
|
@ -11,5 +11,6 @@ public static class ReportingServiceCollectionExtensions
|
|||||||
services.AddScoped<IMemberAccessCipherDetailsQuery, MemberAccessCipherDetailsQuery>();
|
services.AddScoped<IMemberAccessCipherDetailsQuery, MemberAccessCipherDetailsQuery>();
|
||||||
services.AddScoped<IAddPasswordHealthReportApplicationCommand, AddPasswordHealthReportApplicationCommand>();
|
services.AddScoped<IAddPasswordHealthReportApplicationCommand, AddPasswordHealthReportApplicationCommand>();
|
||||||
services.AddScoped<IGetPasswordHealthReportApplicationQuery, GetPasswordHealthReportApplicationQuery>();
|
services.AddScoped<IGetPasswordHealthReportApplicationQuery, GetPasswordHealthReportApplicationQuery>();
|
||||||
|
services.AddScoped<IDropPasswordHealthReportApplicationCommand, DropPasswordHealthReportApplicationCommand>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Bit.Core.Tools.Requests;
|
namespace Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
|
|
||||||
public class AddPasswordHealthReportApplicationRequest
|
public class AddPasswordHealthReportApplicationRequest
|
||||||
{
|
{
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
|
|
||||||
|
public class DropPasswordHealthReportApplicationRequest
|
||||||
|
{
|
||||||
|
public Guid OrganizationId { get; set; }
|
||||||
|
public IEnumerable<Guid> PasswordHealthReportApplicationIds { get; set; }
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
using Bit.Api.Tools.Controllers;
|
using AutoFixture;
|
||||||
|
using Bit.Api.Tools.Controllers;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
using Bit.Core.Tools.ReportFeatures.Interfaces;
|
||||||
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
@ -45,5 +47,98 @@ public class ReportsControllerTests
|
|||||||
.Received(0);
|
.Received(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task AddPasswordHealthReportApplicationAsync_withAccess_success(SutProvider<ReportsController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().AccessReports(Arg.Any<Guid>()).Returns(true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var request = new Api.Tools.Models.PasswordHealthReportApplicationModel
|
||||||
|
{
|
||||||
|
OrganizationId = Guid.NewGuid(),
|
||||||
|
Url = "https://example.com",
|
||||||
|
};
|
||||||
|
await sutProvider.Sut.AddPasswordHealthReportApplication(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_ = sutProvider.GetDependency<IAddPasswordHealthReportApplicationCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.AddPasswordHealthReportApplicationAsync(Arg.Is<AddPasswordHealthReportApplicationRequest>(_ =>
|
||||||
|
_.OrganizationId == request.OrganizationId && _.Url == request.Url));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task AddPasswordHealthReportApplicationAsync_multiple_withAccess_success(
|
||||||
|
SutProvider<ReportsController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().AccessReports(Arg.Any<Guid>()).Returns(true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var fixture = new Fixture();
|
||||||
|
var request = fixture.CreateMany<Api.Tools.Models.PasswordHealthReportApplicationModel>(2);
|
||||||
|
await sutProvider.Sut.AddPasswordHealthReportApplications(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_ = sutProvider.GetDependency<IAddPasswordHealthReportApplicationCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.AddPasswordHealthReportApplicationAsync(Arg.Any<IEnumerable<AddPasswordHealthReportApplicationRequest>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task AddPasswordHealthReportApplicationAsync_withoutAccess(SutProvider<ReportsController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().AccessReports(Arg.Any<Guid>()).Returns(false);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var request = new Api.Tools.Models.PasswordHealthReportApplicationModel
|
||||||
|
{
|
||||||
|
OrganizationId = Guid.NewGuid(),
|
||||||
|
Url = "https://example.com",
|
||||||
|
};
|
||||||
|
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||||
|
await sutProvider.Sut.AddPasswordHealthReportApplication(request));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_ = sutProvider.GetDependency<IAddPasswordHealthReportApplicationCommand>()
|
||||||
|
.Received(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task DropPasswordHealthReportApplicationAsync_withoutAccess(SutProvider<ReportsController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().AccessReports(Arg.Any<Guid>()).Returns(false);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var fixture = new Fixture();
|
||||||
|
var request = fixture.Create<Api.Tools.Models.PasswordHealthReportApplicationModel>();
|
||||||
|
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||||
|
await sutProvider.Sut.AddPasswordHealthReportApplication(request));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_ = sutProvider.GetDependency<IDropPasswordHealthReportApplicationCommand>()
|
||||||
|
.Received(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task DropPasswordHealthReportApplicationAsync_withAccess_success(SutProvider<ReportsController> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().AccessReports(Arg.Any<Guid>()).Returns(true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var fixture = new Fixture();
|
||||||
|
var request = fixture.Create<DropPasswordHealthReportApplicationRequest>();
|
||||||
|
await sutProvider.Sut.DropPasswordHealthReportApplication(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_ = sutProvider.GetDependency<IDropPasswordHealthReportApplicationCommand>()
|
||||||
|
.Received(1)
|
||||||
|
.DropPasswordHealthReportApplicationAsync(Arg.Is<DropPasswordHealthReportApplicationRequest>(_ =>
|
||||||
|
_.OrganizationId == request.OrganizationId &&
|
||||||
|
_.PasswordHealthReportApplicationIds == request.PasswordHealthReportApplicationIds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ using Bit.Core.Exceptions;
|
|||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Tools.Entities;
|
||||||
using Bit.Core.Tools.ReportFeatures;
|
using Bit.Core.Tools.ReportFeatures;
|
||||||
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
using Bit.Core.Tools.Repositories;
|
using Bit.Core.Tools.Repositories;
|
||||||
using Bit.Core.Tools.Requests;
|
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
using AutoFixture;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Tools.Entities;
|
||||||
|
using Bit.Core.Tools.ReportFeatures;
|
||||||
|
using Bit.Core.Tools.ReportFeatures.Requests;
|
||||||
|
using Bit.Core.Tools.Repositories;
|
||||||
|
using Bit.Test.Common.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
using NSubstitute;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Core.Test.Tools.ReportFeatures;
|
||||||
|
|
||||||
|
[SutProviderCustomize]
|
||||||
|
public class DeletePasswordHealthReportApplicationCommandTests
|
||||||
|
{
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task DropPasswordHealthReportApplicationAsync_withValidRequest_Success(
|
||||||
|
SutProvider<DropPasswordHealthReportApplicationCommand> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var fixture = new Fixture();
|
||||||
|
var passwordHealthReportApplications = fixture.CreateMany<PasswordHealthReportApplication>(2).ToList();
|
||||||
|
// only take one id from the list - we only want to drop one record
|
||||||
|
var request = fixture.Build<DropPasswordHealthReportApplicationRequest>()
|
||||||
|
.With(x => x.PasswordHealthReportApplicationIds,
|
||||||
|
passwordHealthReportApplications.Select(x => x.Id).Take(1).ToList())
|
||||||
|
.Create();
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.GetByOrganizationIdAsync(Arg.Any<Guid>())
|
||||||
|
.Returns(passwordHealthReportApplications);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.DropPasswordHealthReportApplicationAsync(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.Received(1)
|
||||||
|
.GetByOrganizationIdAsync(request.OrganizationId);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.Received(1)
|
||||||
|
.DeleteAsync(Arg.Is<PasswordHealthReportApplication>(_ =>
|
||||||
|
request.PasswordHealthReportApplicationIds.Contains(_.Id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task DropPasswordHealthReportApplicationAsync_withValidRequest_nothingToDrop(
|
||||||
|
SutProvider<DropPasswordHealthReportApplicationCommand> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var fixture = new Fixture();
|
||||||
|
var passwordHealthReportApplications = fixture.CreateMany<PasswordHealthReportApplication>(2).ToList();
|
||||||
|
// we are passing invalid data
|
||||||
|
var request = fixture.Build<DropPasswordHealthReportApplicationRequest>()
|
||||||
|
.With(x => x.PasswordHealthReportApplicationIds, new List<Guid> { Guid.NewGuid() })
|
||||||
|
.Create();
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.GetByOrganizationIdAsync(Arg.Any<Guid>())
|
||||||
|
.Returns(passwordHealthReportApplications);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await sutProvider.Sut.DropPasswordHealthReportApplicationAsync(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.Received(1)
|
||||||
|
.GetByOrganizationIdAsync(request.OrganizationId);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.DeleteAsync(Arg.Any<PasswordHealthReportApplication>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task DropPasswordHealthReportApplicationAsync_withNodata_fails(
|
||||||
|
SutProvider<DropPasswordHealthReportApplicationCommand> sutProvider)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var fixture = new Fixture();
|
||||||
|
// we are passing invalid data
|
||||||
|
var request = fixture.Build<DropPasswordHealthReportApplicationRequest>()
|
||||||
|
.Create();
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.GetByOrganizationIdAsync(Arg.Any<Guid>())
|
||||||
|
.Returns(null as List<PasswordHealthReportApplication>);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||||
|
sutProvider.Sut.DropPasswordHealthReportApplicationAsync(request));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.Received(1)
|
||||||
|
.GetByOrganizationIdAsync(request.OrganizationId);
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IPasswordHealthReportApplicationRepository>()
|
||||||
|
.Received(0)
|
||||||
|
.DeleteAsync(Arg.Any<PasswordHealthReportApplication>());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user