1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 23:52:50 -05:00

PM-13237 password health report application add get (#5000)

* PM-13236 PasswordHealthReportApplications db

* PM-13236 incorporated pr comments

* PM-13236 fixed error in SQL script

* PM-13236 resolve quality scan errors SQL71006, SQL7101, SQL70001

* PM-13236 fixed warnings on procedures

* PM-13236 added efMigrations

* PM-13236 renamed files to PasswordHealthReportApplication (singular)

* PM-13236 changed file name to more appropriate naming

* PM-13236 changed the file name singular

* PM-13236 PasswordHealthReportApplication Entities and Repos

* PM-13236 moved files under tools from core

* PM-13236 Entity PasswordHealthReportApplication namespace changed to tools/entities

* PM-13236 moved Repos and Interfaces to tools

* PM-13236 migrated model to tools namespace

* PM-13236 minor fixes to the unit tests

* PM-13236 fixed script errors during build

* PM-13236 Script to drop PasswordHealthReportApplications if it exists

* PM-13236 fixes to database snapshot

* PM-13236 updated databasesnapshots

* PM-13236 Update database model changes for Mysql

* PM-13236 update model changes for Sqlite

* PM-13236 updated the models to remove commented code

* PM-13236 added correct db snapshot for MySql

* PM-13236 updated database snapshot for Postgres

* PM-13236 updated database snapshot for Sqlite

* PM-13236 removed unwanted directive to fix linting error

* PM-13236 removed redundant script files

* PM-13237 Add entity command and unit tests

* PM-13237 Get query added with unit tests

* PM-13237 Controller to add/get PasswordHealthReportApplication

* PM-13237 Setup dependencies in the EF Service collection extensions

* PM-13237 Added unit tests for ReportsController
This commit is contained in:
Vijay Oommen
2024-11-11 11:54:52 -06:00
committed by GitHub
parent 0e23a07bbc
commit 9fb3f1d346
13 changed files with 498 additions and 3 deletions

View File

@ -0,0 +1,101 @@
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.ReportFeatures.Interfaces;
using Bit.Core.Tools.Repositories;
using Bit.Core.Tools.Requests;
namespace Bit.Core.Tools.ReportFeatures;
public class AddPasswordHealthReportApplicationCommand : IAddPasswordHealthReportApplicationCommand
{
private IOrganizationRepository _organizationRepo;
private IPasswordHealthReportApplicationRepository _passwordHealthReportApplicationRepo;
public AddPasswordHealthReportApplicationCommand(
IOrganizationRepository organizationRepository,
IPasswordHealthReportApplicationRepository passwordHealthReportApplicationRepository)
{
_organizationRepo = organizationRepository;
_passwordHealthReportApplicationRepo = passwordHealthReportApplicationRepository;
}
public async Task<PasswordHealthReportApplication> AddPasswordHealthReportApplicationAsync(AddPasswordHealthReportApplicationRequest request)
{
var (req, IsValid, errorMessage) = await ValidateRequestAsync(request);
if (!IsValid)
{
throw new BadRequestException(errorMessage);
}
var passwordHealthReportApplication = new PasswordHealthReportApplication
{
OrganizationId = request.OrganizationId,
Uri = request.Url,
};
passwordHealthReportApplication.SetNewId();
var data = await _passwordHealthReportApplicationRepo.CreateAsync(passwordHealthReportApplication);
return data;
}
public async Task<IEnumerable<PasswordHealthReportApplication>> AddPasswordHealthReportApplicationAsync(IEnumerable<AddPasswordHealthReportApplicationRequest> requests)
{
var requestsList = requests.ToList();
// create tasks to validate each request
var tasks = requestsList.Select(async request =>
{
var (req, IsValid, errorMessage) = await ValidateRequestAsync(request);
if (!IsValid)
{
throw new BadRequestException(errorMessage);
}
});
// run validations and allow exceptions to bubble
await Task.WhenAll(tasks);
// create PasswordHealthReportApplication entities
var passwordHealthReportApplications = requestsList.Select(request =>
{
var pwdHealthReportApplication = new PasswordHealthReportApplication
{
OrganizationId = request.OrganizationId,
Uri = request.Url,
};
pwdHealthReportApplication.SetNewId();
return pwdHealthReportApplication;
});
// create and return the entities
var response = new List<PasswordHealthReportApplication>();
foreach (var record in passwordHealthReportApplications)
{
var data = await _passwordHealthReportApplicationRepo.CreateAsync(record);
response.Add(data);
}
return response;
}
private async Task<Tuple<AddPasswordHealthReportApplicationRequest, bool, string>> ValidateRequestAsync(
AddPasswordHealthReportApplicationRequest request)
{
// verify that the organization exists
var organization = await _organizationRepo.GetByIdAsync(request.OrganizationId);
if (organization == null)
{
return new Tuple<AddPasswordHealthReportApplicationRequest, bool, string>(request, false, "Invalid Organization");
}
// ensure that we have a URL
if (string.IsNullOrWhiteSpace(request.Url))
{
return new Tuple<AddPasswordHealthReportApplicationRequest, bool, string>(request, false, "URL is required");
}
return new Tuple<AddPasswordHealthReportApplicationRequest, bool, string>(request, true, string.Empty);
}
}

View File

@ -0,0 +1,27 @@
using Bit.Core.Exceptions;
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.ReportFeatures.Interfaces;
using Bit.Core.Tools.Repositories;
namespace Bit.Core.Tools.ReportFeatures;
public class GetPasswordHealthReportApplicationQuery : IGetPasswordHealthReportApplicationQuery
{
private IPasswordHealthReportApplicationRepository _passwordHealthReportApplicationRepo;
public GetPasswordHealthReportApplicationQuery(
IPasswordHealthReportApplicationRepository passwordHealthReportApplicationRepo)
{
_passwordHealthReportApplicationRepo = passwordHealthReportApplicationRepo;
}
public async Task<IEnumerable<PasswordHealthReportApplication>> GetPasswordHealthReportApplicationAsync(Guid organizationId)
{
if (organizationId == Guid.Empty)
{
throw new BadRequestException("OrganizationId is required.");
}
return await _passwordHealthReportApplicationRepo.GetByOrganizationIdAsync(organizationId);
}
}

View File

@ -0,0 +1,10 @@
using Bit.Core.Tools.Entities;
using Bit.Core.Tools.Requests;
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
public interface IAddPasswordHealthReportApplicationCommand
{
Task<PasswordHealthReportApplication> AddPasswordHealthReportApplicationAsync(AddPasswordHealthReportApplicationRequest request);
Task<IEnumerable<PasswordHealthReportApplication>> AddPasswordHealthReportApplicationAsync(IEnumerable<AddPasswordHealthReportApplicationRequest> requests);
}

View File

@ -0,0 +1,8 @@
using Bit.Core.Tools.Entities;
namespace Bit.Core.Tools.ReportFeatures.Interfaces;
public interface IGetPasswordHealthReportApplicationQuery
{
Task<IEnumerable<PasswordHealthReportApplication>> GetPasswordHealthReportApplicationAsync(Guid organizationId);
}

View File

@ -1,4 +1,4 @@

using Bit.Core.Tools.ReportFeatures.Interfaces;
using Bit.Core.Tools.ReportFeatures.OrganizationReportMembers.Interfaces;
using Microsoft.Extensions.DependencyInjection;
@ -9,5 +9,7 @@ public static class ReportingServiceCollectionExtensions
public static void AddReportingServices(this IServiceCollection services)
{
services.AddScoped<IMemberAccessCipherDetailsQuery, MemberAccessCipherDetailsQuery>();
services.AddScoped<IAddPasswordHealthReportApplicationCommand, AddPasswordHealthReportApplicationCommand>();
services.AddScoped<IGetPasswordHealthReportApplicationQuery, GetPasswordHealthReportApplicationQuery>();
}
}

View File

@ -0,0 +1,7 @@
namespace Bit.Core.Tools.Requests;
public class AddPasswordHealthReportApplicationRequest
{
public Guid OrganizationId { get; set; }
public string Url { get; set; }
}