mirror of
https://github.com/bitwarden/server
synced 2025-12-06 00:03:34 +00:00
[PM-26967] Added new metric properties (#6519)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Bit.Core.Context;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
using Bit.Core.Exceptions;
|
||||
@@ -61,8 +62,9 @@ public class OrganizationReportsController : Controller
|
||||
}
|
||||
|
||||
var latestReport = await _getOrganizationReportQuery.GetLatestOrganizationReportAsync(organizationId);
|
||||
var response = latestReport == null ? null : new OrganizationReportResponseModel(latestReport);
|
||||
|
||||
return Ok(latestReport);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpGet("{organizationId}/{reportId}")]
|
||||
@@ -102,7 +104,8 @@ public class OrganizationReportsController : Controller
|
||||
}
|
||||
|
||||
var report = await _addOrganizationReportCommand.AddOrganizationReportAsync(request);
|
||||
return Ok(report);
|
||||
var response = report == null ? null : new OrganizationReportResponseModel(report);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPatch("{organizationId}/{reportId}")]
|
||||
@@ -119,7 +122,8 @@ public class OrganizationReportsController : Controller
|
||||
}
|
||||
|
||||
var updatedReport = await _updateOrganizationReportCommand.UpdateOrganizationReportAsync(request);
|
||||
return Ok(updatedReport);
|
||||
var response = new OrganizationReportResponseModel(updatedReport);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -182,10 +186,10 @@ public class OrganizationReportsController : Controller
|
||||
{
|
||||
throw new BadRequestException("Report ID in the request body must match the route parameter");
|
||||
}
|
||||
|
||||
var updatedReport = await _updateOrganizationReportSummaryCommand.UpdateOrganizationReportSummaryAsync(request);
|
||||
var response = new OrganizationReportResponseModel(updatedReport);
|
||||
|
||||
return Ok(updatedReport);
|
||||
return Ok(response);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -228,7 +232,9 @@ public class OrganizationReportsController : Controller
|
||||
}
|
||||
|
||||
var updatedReport = await _updateOrganizationReportDataCommand.UpdateOrganizationReportDataAsync(request);
|
||||
return Ok(updatedReport);
|
||||
var response = new OrganizationReportResponseModel(updatedReport);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -265,7 +271,6 @@ public class OrganizationReportsController : Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (!await _currentContext.AccessReports(organizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@@ -282,10 +287,9 @@ public class OrganizationReportsController : Controller
|
||||
}
|
||||
|
||||
var updatedReport = await _updateOrganizationReportApplicationDataCommand.UpdateOrganizationReportApplicationDataAsync(request);
|
||||
var response = new OrganizationReportResponseModel(updatedReport);
|
||||
|
||||
|
||||
|
||||
return Ok(updatedReport);
|
||||
return Ok(response);
|
||||
}
|
||||
catch (Exception ex) when (!(ex is BadRequestException || ex is NotFoundException))
|
||||
{
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using Bit.Core.Dirt.Entities;
|
||||
|
||||
namespace Bit.Api.Dirt.Models.Response;
|
||||
|
||||
public class OrganizationReportResponseModel
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid OrganizationId { get; set; }
|
||||
public string? ReportData { get; set; }
|
||||
public string? ContentEncryptionKey { get; set; }
|
||||
public string? SummaryData { get; set; }
|
||||
public string? ApplicationData { get; set; }
|
||||
public int? PasswordCount { get; set; }
|
||||
public int? PasswordAtRiskCount { get; set; }
|
||||
public int? MemberCount { get; set; }
|
||||
public DateTime? CreationDate { get; set; } = null;
|
||||
public DateTime? RevisionDate { get; set; } = null;
|
||||
|
||||
public OrganizationReportResponseModel(OrganizationReport organizationReport)
|
||||
{
|
||||
if (organizationReport == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Id = organizationReport.Id;
|
||||
OrganizationId = organizationReport.OrganizationId;
|
||||
ReportData = organizationReport.ReportData;
|
||||
ContentEncryptionKey = organizationReport.ContentEncryptionKey;
|
||||
SummaryData = organizationReport.SummaryData;
|
||||
ApplicationData = organizationReport.ApplicationData;
|
||||
PasswordCount = organizationReport.PasswordCount;
|
||||
PasswordAtRiskCount = organizationReport.PasswordAtRiskCount;
|
||||
MemberCount = organizationReport.MemberCount;
|
||||
CreationDate = organizationReport.CreationDate;
|
||||
RevisionDate = organizationReport.RevisionDate;
|
||||
}
|
||||
}
|
||||
48
src/Core/Dirt/Models/Data/OrganizationReportMetricsData.cs
Normal file
48
src/Core/Dirt/Models/Data/OrganizationReportMetricsData.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
|
||||
namespace Bit.Core.Dirt.Reports.Models.Data;
|
||||
|
||||
public class OrganizationReportMetricsData
|
||||
{
|
||||
public Guid OrganizationId { get; set; }
|
||||
public int? ApplicationCount { get; set; }
|
||||
public int? ApplicationAtRiskCount { get; set; }
|
||||
public int? CriticalApplicationCount { get; set; }
|
||||
public int? CriticalApplicationAtRiskCount { get; set; }
|
||||
public int? MemberCount { get; set; }
|
||||
public int? MemberAtRiskCount { get; set; }
|
||||
public int? CriticalMemberCount { get; set; }
|
||||
public int? CriticalMemberAtRiskCount { get; set; }
|
||||
public int? PasswordCount { get; set; }
|
||||
public int? PasswordAtRiskCount { get; set; }
|
||||
public int? CriticalPasswordCount { get; set; }
|
||||
public int? CriticalPasswordAtRiskCount { get; set; }
|
||||
|
||||
public static OrganizationReportMetricsData From(Guid organizationId, OrganizationReportMetricsRequest? request)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
return new OrganizationReportMetricsData
|
||||
{
|
||||
OrganizationId = organizationId
|
||||
};
|
||||
}
|
||||
|
||||
return new OrganizationReportMetricsData
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
ApplicationCount = request.ApplicationCount,
|
||||
ApplicationAtRiskCount = request.ApplicationAtRiskCount,
|
||||
CriticalApplicationCount = request.CriticalApplicationCount,
|
||||
CriticalApplicationAtRiskCount = request.CriticalApplicationAtRiskCount,
|
||||
MemberCount = request.MemberCount,
|
||||
MemberAtRiskCount = request.MemberAtRiskCount,
|
||||
CriticalMemberCount = request.CriticalMemberCount,
|
||||
CriticalMemberAtRiskCount = request.CriticalMemberAtRiskCount,
|
||||
PasswordCount = request.PasswordCount,
|
||||
PasswordAtRiskCount = request.PasswordAtRiskCount,
|
||||
CriticalPasswordCount = request.CriticalPasswordCount,
|
||||
CriticalPasswordAtRiskCount = request.CriticalPasswordAtRiskCount
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -35,14 +35,28 @@ public class AddOrganizationReportCommand : IAddOrganizationReportCommand
|
||||
throw new BadRequestException(errorMessage);
|
||||
}
|
||||
|
||||
var requestMetrics = request.Metrics ?? new OrganizationReportMetricsRequest();
|
||||
|
||||
var organizationReport = new OrganizationReport
|
||||
{
|
||||
OrganizationId = request.OrganizationId,
|
||||
ReportData = request.ReportData,
|
||||
ReportData = request.ReportData ?? string.Empty,
|
||||
CreationDate = DateTime.UtcNow,
|
||||
ContentEncryptionKey = request.ContentEncryptionKey,
|
||||
ContentEncryptionKey = request.ContentEncryptionKey ?? string.Empty,
|
||||
SummaryData = request.SummaryData,
|
||||
ApplicationData = request.ApplicationData,
|
||||
ApplicationCount = requestMetrics.ApplicationCount,
|
||||
ApplicationAtRiskCount = requestMetrics.ApplicationAtRiskCount,
|
||||
CriticalApplicationCount = requestMetrics.CriticalApplicationCount,
|
||||
CriticalApplicationAtRiskCount = requestMetrics.CriticalApplicationAtRiskCount,
|
||||
MemberCount = requestMetrics.MemberCount,
|
||||
MemberAtRiskCount = requestMetrics.MemberAtRiskCount,
|
||||
CriticalMemberCount = requestMetrics.CriticalMemberCount,
|
||||
CriticalMemberAtRiskCount = requestMetrics.CriticalMemberAtRiskCount,
|
||||
PasswordCount = requestMetrics.PasswordCount,
|
||||
PasswordAtRiskCount = requestMetrics.PasswordAtRiskCount,
|
||||
CriticalPasswordCount = requestMetrics.CriticalPasswordCount,
|
||||
CriticalPasswordAtRiskCount = requestMetrics.CriticalPasswordAtRiskCount,
|
||||
RevisionDate = DateTime.UtcNow
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
|
||||
public class AddOrganizationReportRequest
|
||||
{
|
||||
public Guid OrganizationId { get; set; }
|
||||
public string ReportData { get; set; }
|
||||
public string? ReportData { get; set; }
|
||||
|
||||
public string ContentEncryptionKey { get; set; }
|
||||
public string? ContentEncryptionKey { get; set; }
|
||||
|
||||
public string SummaryData { get; set; }
|
||||
public string? SummaryData { get; set; }
|
||||
|
||||
public string ApplicationData { get; set; }
|
||||
public string? ApplicationData { get; set; }
|
||||
|
||||
public OrganizationReportMetricsRequest? Metrics { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
|
||||
public class OrganizationReportMetricsRequest
|
||||
{
|
||||
[JsonPropertyName("totalApplicationCount")]
|
||||
public int? ApplicationCount { get; set; } = null;
|
||||
[JsonPropertyName("totalAtRiskApplicationCount")]
|
||||
public int? ApplicationAtRiskCount { get; set; } = null;
|
||||
[JsonPropertyName("totalCriticalApplicationCount")]
|
||||
public int? CriticalApplicationCount { get; set; } = null;
|
||||
[JsonPropertyName("totalCriticalAtRiskApplicationCount")]
|
||||
public int? CriticalApplicationAtRiskCount { get; set; } = null;
|
||||
[JsonPropertyName("totalMemberCount")]
|
||||
public int? MemberCount { get; set; } = null;
|
||||
[JsonPropertyName("totalAtRiskMemberCount")]
|
||||
public int? MemberAtRiskCount { get; set; } = null;
|
||||
[JsonPropertyName("totalCriticalMemberCount")]
|
||||
public int? CriticalMemberCount { get; set; } = null;
|
||||
[JsonPropertyName("totalCriticalAtRiskMemberCount")]
|
||||
public int? CriticalMemberAtRiskCount { get; set; } = null;
|
||||
[JsonPropertyName("totalPasswordCount")]
|
||||
public int? PasswordCount { get; set; } = null;
|
||||
[JsonPropertyName("totalAtRiskPasswordCount")]
|
||||
public int? PasswordAtRiskCount { get; set; } = null;
|
||||
[JsonPropertyName("totalCriticalPasswordCount")]
|
||||
public int? CriticalPasswordCount { get; set; } = null;
|
||||
[JsonPropertyName("totalCriticalAtRiskPasswordCount")]
|
||||
public int? CriticalPasswordAtRiskCount { get; set; } = null;
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
|
||||
public class UpdateOrganizationReportApplicationDataRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid OrganizationId { get; set; }
|
||||
public string ApplicationData { get; set; }
|
||||
public string? ApplicationData { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
namespace Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
|
||||
public class UpdateOrganizationReportSummaryRequest
|
||||
{
|
||||
public Guid OrganizationId { get; set; }
|
||||
public Guid ReportId { get; set; }
|
||||
public string SummaryData { get; set; }
|
||||
public string? SummaryData { get; set; }
|
||||
public OrganizationReportMetricsRequest? Metrics { get; set; }
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class UpdateOrganizationReportApplicationDataCommand : IUpdateOrganizatio
|
||||
throw new BadRequestException("Organization report does not belong to the specified organization");
|
||||
}
|
||||
|
||||
var updatedReport = await _organizationReportRepo.UpdateApplicationDataAsync(request.OrganizationId, request.Id, request.ApplicationData);
|
||||
var updatedReport = await _organizationReportRepo.UpdateApplicationDataAsync(request.OrganizationId, request.Id, request.ApplicationData ?? string.Empty);
|
||||
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Successfully updated organization report application data {reportId} for organization {organizationId}",
|
||||
request.Id, request.OrganizationId);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Reports.Models.Data;
|
||||
using Bit.Core.Dirt.Reports.ReportFeatures.Interfaces;
|
||||
using Bit.Core.Dirt.Reports.ReportFeatures.Requests;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
@@ -53,7 +54,8 @@ public class UpdateOrganizationReportSummaryCommand : IUpdateOrganizationReportS
|
||||
throw new BadRequestException("Organization report does not belong to the specified organization");
|
||||
}
|
||||
|
||||
var updatedReport = await _organizationReportRepo.UpdateSummaryDataAsync(request.OrganizationId, request.ReportId, request.SummaryData);
|
||||
await _organizationReportRepo.UpdateMetricsAsync(request.ReportId, OrganizationReportMetricsData.From(request.OrganizationId, request.Metrics));
|
||||
var updatedReport = await _organizationReportRepo.UpdateSummaryDataAsync(request.OrganizationId, request.ReportId, request.SummaryData ?? string.Empty);
|
||||
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId, "Successfully updated organization report summary {reportId} for organization {organizationId}",
|
||||
request.ReportId, request.OrganizationId);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Models.Data;
|
||||
using Bit.Core.Dirt.Reports.Models.Data;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.Dirt.Repositories;
|
||||
@@ -21,5 +22,8 @@ public interface IOrganizationReportRepository : IRepository<OrganizationReport,
|
||||
// ApplicationData methods
|
||||
Task<OrganizationReportApplicationDataResponse> GetApplicationDataAsync(Guid reportId);
|
||||
Task<OrganizationReport> UpdateApplicationDataAsync(Guid orgId, Guid reportId, string applicationData);
|
||||
|
||||
// Metrics methods
|
||||
Task UpdateMetricsAsync(Guid reportId, OrganizationReportMetricsData metrics);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System.Data;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Models.Data;
|
||||
using Bit.Core.Dirt.Reports.Models.Data;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Infrastructure.Dapper.Repositories;
|
||||
@@ -173,4 +174,31 @@ public class OrganizationReportRepository : Repository<OrganizationReport, Guid>
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateMetricsAsync(Guid reportId, OrganizationReportMetricsData metrics)
|
||||
{
|
||||
using var connection = new SqlConnection(ConnectionString);
|
||||
var parameters = new
|
||||
{
|
||||
Id = reportId,
|
||||
ApplicationCount = metrics.ApplicationCount,
|
||||
ApplicationAtRiskCount = metrics.ApplicationAtRiskCount,
|
||||
CriticalApplicationCount = metrics.CriticalApplicationCount,
|
||||
CriticalApplicationAtRiskCount = metrics.CriticalApplicationAtRiskCount,
|
||||
MemberCount = metrics.MemberCount,
|
||||
MemberAtRiskCount = metrics.MemberAtRiskCount,
|
||||
CriticalMemberCount = metrics.CriticalMemberCount,
|
||||
CriticalMemberAtRiskCount = metrics.CriticalMemberAtRiskCount,
|
||||
PasswordCount = metrics.PasswordCount,
|
||||
PasswordAtRiskCount = metrics.PasswordAtRiskCount,
|
||||
CriticalPasswordCount = metrics.CriticalPasswordCount,
|
||||
CriticalPasswordAtRiskCount = metrics.CriticalPasswordAtRiskCount,
|
||||
RevisionDate = DateTime.UtcNow
|
||||
};
|
||||
|
||||
await connection.ExecuteAsync(
|
||||
$"[{Schema}].[OrganizationReport_UpdateMetrics]",
|
||||
parameters,
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using AutoMapper;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Models.Data;
|
||||
using Bit.Core.Dirt.Reports.Models.Data;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using LinqToDB;
|
||||
@@ -184,4 +185,31 @@ public class OrganizationReportRepository :
|
||||
return Mapper.Map<OrganizationReport>(updatedReport);
|
||||
}
|
||||
}
|
||||
|
||||
public Task UpdateMetricsAsync(Guid reportId, OrganizationReportMetricsData metrics)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
|
||||
return dbContext.OrganizationReports
|
||||
.Where(p => p.Id == reportId)
|
||||
.UpdateAsync(p => new Models.OrganizationReport
|
||||
{
|
||||
ApplicationCount = metrics.ApplicationCount,
|
||||
ApplicationAtRiskCount = metrics.ApplicationAtRiskCount,
|
||||
CriticalApplicationCount = metrics.CriticalApplicationCount,
|
||||
CriticalApplicationAtRiskCount = metrics.CriticalApplicationAtRiskCount,
|
||||
MemberCount = metrics.MemberCount,
|
||||
MemberAtRiskCount = metrics.MemberAtRiskCount,
|
||||
CriticalMemberCount = metrics.CriticalMemberCount,
|
||||
CriticalMemberAtRiskCount = metrics.CriticalMemberAtRiskCount,
|
||||
PasswordCount = metrics.PasswordCount,
|
||||
PasswordAtRiskCount = metrics.PasswordAtRiskCount,
|
||||
CriticalPasswordCount = metrics.CriticalPasswordCount,
|
||||
CriticalPasswordAtRiskCount = metrics.CriticalPasswordAtRiskCount,
|
||||
RevisionDate = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
CREATE PROCEDURE [dbo].[OrganizationReport_UpdateMetrics]
|
||||
@Id UNIQUEIDENTIFIER,
|
||||
@ApplicationCount INT,
|
||||
@ApplicationAtRiskCount INT,
|
||||
@CriticalApplicationCount INT,
|
||||
@CriticalApplicationAtRiskCount INT,
|
||||
@MemberCount INT,
|
||||
@MemberAtRiskCount INT,
|
||||
@CriticalMemberCount INT,
|
||||
@CriticalMemberAtRiskCount INT,
|
||||
@PasswordCount INT,
|
||||
@PasswordAtRiskCount INT,
|
||||
@CriticalPasswordCount INT,
|
||||
@CriticalPasswordAtRiskCount INT,
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
UPDATE
|
||||
[dbo].[OrganizationReport]
|
||||
SET
|
||||
[ApplicationCount] = @ApplicationCount,
|
||||
[ApplicationAtRiskCount] = @ApplicationAtRiskCount,
|
||||
[CriticalApplicationCount] = @CriticalApplicationCount,
|
||||
[CriticalApplicationAtRiskCount] = @CriticalApplicationAtRiskCount,
|
||||
[MemberCount] = @MemberCount,
|
||||
[MemberAtRiskCount] = @MemberAtRiskCount,
|
||||
[CriticalMemberCount] = @CriticalMemberCount,
|
||||
[CriticalMemberAtRiskCount] = @CriticalMemberAtRiskCount,
|
||||
[PasswordCount] = @PasswordCount,
|
||||
[PasswordAtRiskCount] = @PasswordAtRiskCount,
|
||||
[CriticalPasswordCount] = @CriticalPasswordCount,
|
||||
[CriticalPasswordAtRiskCount] = @CriticalPasswordAtRiskCount,
|
||||
[RevisionDate] = @RevisionDate
|
||||
WHERE
|
||||
[Id] = @Id
|
||||
|
||||
END
|
||||
@@ -1,4 +1,5 @@
|
||||
using Bit.Api.Dirt.Controllers;
|
||||
using Bit.Api.Dirt.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Models.Data;
|
||||
@@ -39,7 +40,8 @@ public class OrganizationReportControllerTests
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(expectedReport, okResult.Value);
|
||||
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
|
||||
Assert.Equivalent(expectedResponse, okResult.Value);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@@ -262,7 +264,8 @@ public class OrganizationReportControllerTests
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(expectedReport, okResult.Value);
|
||||
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
|
||||
Assert.Equivalent(expectedResponse, okResult.Value);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@@ -365,7 +368,8 @@ public class OrganizationReportControllerTests
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(expectedReport, okResult.Value);
|
||||
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
|
||||
Assert.Equivalent(expectedResponse, okResult.Value);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@@ -597,7 +601,8 @@ public class OrganizationReportControllerTests
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(expectedReport, okResult.Value);
|
||||
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
|
||||
Assert.Equivalent(expectedResponse, okResult.Value);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@@ -812,7 +817,8 @@ public class OrganizationReportControllerTests
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(expectedReport, okResult.Value);
|
||||
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
|
||||
Assert.Equivalent(expectedResponse, okResult.Value);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
@@ -1050,7 +1056,8 @@ public class OrganizationReportControllerTests
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(expectedReport, okResult.Value);
|
||||
var expectedResponse = new OrganizationReportResponseModel(expectedReport);
|
||||
Assert.Equivalent(expectedResponse, okResult.Value);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using AutoFixture;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Dirt.Entities;
|
||||
using Bit.Core.Dirt.Reports.Models.Data;
|
||||
using Bit.Core.Dirt.Repositories;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Test.AutoFixture.Attributes;
|
||||
@@ -489,6 +490,49 @@ public class OrganizationReportRepositoryTests
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[CiSkippedTheory, EfOrganizationReportAutoData]
|
||||
public async Task UpdateMetricsAsync_ShouldUpdateMetricsCorrectly(
|
||||
OrganizationReportRepository sqlOrganizationReportRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrganizationRepo)
|
||||
{
|
||||
// Arrange
|
||||
var (org, report) = await CreateOrganizationAndReportAsync(sqlOrganizationRepo, sqlOrganizationReportRepo);
|
||||
var metrics = new OrganizationReportMetricsData
|
||||
{
|
||||
ApplicationCount = 10,
|
||||
ApplicationAtRiskCount = 2,
|
||||
CriticalApplicationCount = 5,
|
||||
CriticalApplicationAtRiskCount = 1,
|
||||
MemberCount = 20,
|
||||
MemberAtRiskCount = 4,
|
||||
CriticalMemberCount = 10,
|
||||
CriticalMemberAtRiskCount = 2,
|
||||
PasswordCount = 100,
|
||||
PasswordAtRiskCount = 15,
|
||||
CriticalPasswordCount = 50,
|
||||
CriticalPasswordAtRiskCount = 5
|
||||
};
|
||||
|
||||
// Act
|
||||
await sqlOrganizationReportRepo.UpdateMetricsAsync(report.Id, metrics);
|
||||
var updatedReport = await sqlOrganizationReportRepo.GetByIdAsync(report.Id);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(metrics.ApplicationCount, updatedReport.ApplicationCount);
|
||||
Assert.Equal(metrics.ApplicationAtRiskCount, updatedReport.ApplicationAtRiskCount);
|
||||
Assert.Equal(metrics.CriticalApplicationCount, updatedReport.CriticalApplicationCount);
|
||||
Assert.Equal(metrics.CriticalApplicationAtRiskCount, updatedReport.CriticalApplicationAtRiskCount);
|
||||
Assert.Equal(metrics.MemberCount, updatedReport.MemberCount);
|
||||
Assert.Equal(metrics.MemberAtRiskCount, updatedReport.MemberAtRiskCount);
|
||||
Assert.Equal(metrics.CriticalMemberCount, updatedReport.CriticalMemberCount);
|
||||
Assert.Equal(metrics.CriticalMemberAtRiskCount, updatedReport.CriticalMemberAtRiskCount);
|
||||
Assert.Equal(metrics.PasswordCount, updatedReport.PasswordCount);
|
||||
Assert.Equal(metrics.PasswordAtRiskCount, updatedReport.PasswordAtRiskCount);
|
||||
Assert.Equal(metrics.CriticalPasswordCount, updatedReport.CriticalPasswordCount);
|
||||
Assert.Equal(metrics.CriticalPasswordAtRiskCount, updatedReport.CriticalPasswordAtRiskCount);
|
||||
}
|
||||
|
||||
|
||||
private async Task<(Organization, OrganizationReport)> CreateOrganizationAndReportAsync(
|
||||
IOrganizationRepository orgRepo,
|
||||
IOrganizationReportRepository orgReportRepo)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
CREATE OR ALTER PROCEDURE [dbo].[OrganizationReport_UpdateMetrics]
|
||||
@Id UNIQUEIDENTIFIER,
|
||||
@ApplicationCount INT,
|
||||
@ApplicationAtRiskCount INT,
|
||||
@CriticalApplicationCount INT,
|
||||
@CriticalApplicationAtRiskCount INT,
|
||||
@MemberCount INT,
|
||||
@MemberAtRiskCount INT,
|
||||
@CriticalMemberCount INT,
|
||||
@CriticalMemberAtRiskCount INT,
|
||||
@PasswordCount INT,
|
||||
@PasswordAtRiskCount INT,
|
||||
@CriticalPasswordCount INT,
|
||||
@CriticalPasswordAtRiskCount INT,
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
UPDATE
|
||||
[dbo].[OrganizationReport]
|
||||
SET
|
||||
[ApplicationCount] = @ApplicationCount,
|
||||
[ApplicationAtRiskCount] = @ApplicationAtRiskCount,
|
||||
[CriticalApplicationCount] = @CriticalApplicationCount,
|
||||
[CriticalApplicationAtRiskCount] = @CriticalApplicationAtRiskCount,
|
||||
[MemberCount] = @MemberCount,
|
||||
[MemberAtRiskCount] = @MemberAtRiskCount,
|
||||
[CriticalMemberCount] = @CriticalMemberCount,
|
||||
[CriticalMemberAtRiskCount] = @CriticalMemberAtRiskCount,
|
||||
[PasswordCount] = @PasswordCount,
|
||||
[PasswordAtRiskCount] = @PasswordAtRiskCount,
|
||||
[CriticalPasswordCount] = @CriticalPasswordCount,
|
||||
[CriticalPasswordAtRiskCount] = @CriticalPasswordAtRiskCount,
|
||||
[RevisionDate] = @RevisionDate
|
||||
WHERE
|
||||
[Id] = @Id
|
||||
|
||||
END
|
||||
Reference in New Issue
Block a user