Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions src/Api/Dirt/Controllers/OrganizationReportsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,15 @@ public async Task<IActionResult> GetLatestOrganizationReportAsync(Guid organizat

await AuthorizeAsync(organizationId);

var latestReport = await _getOrganizationReportQuery.GetLatestOrganizationReportAsync(organizationId);
var isAccessIntelligenceV2 = _featureService.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2);

if (latestReport == null)
{
throw new NotFoundException();
}
Comment thread
Banrion marked this conversation as resolved.
var latestReport = isAccessIntelligenceV2
? await _getOrganizationReportQuery.ReadLatestOrganizationReportAsync(organizationId)
: await _getOrganizationReportQuery.GetLatestOrganizationReportAsync(organizationId);

var response = new OrganizationReportResponseModel(latestReport);

if (_featureService.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2))
if (isAccessIntelligenceV2)
{
var fileData = latestReport.GetReportFile();
if (fileData is { Validated: true })
Expand Down Expand Up @@ -393,7 +392,7 @@ public async Task UploadReportFileAsync(Guid organizationId, Guid reportId, [Fro
}

var fileData = report.GetReportFile();
if (fileData == null || fileData.Id != reportFileId)
if (fileData == null || fileData.Id != reportFileId || fileData.Validated)
{
throw new NotFoundException();
}
Expand Down Expand Up @@ -449,6 +448,11 @@ public async Task<IActionResult> DownloadReportFileAsync(Guid organizationId, Gu
throw new NotFoundException();
}

if (_featureService.IsEnabled(FeatureFlagKeys.AccessIntelligenceVersion2) && !fileData.Validated)
Comment thread
Banrion marked this conversation as resolved.
{
throw new NotFoundException();
}

var stream = await _storageService.GetReportReadStreamAsync(report, fileData);
if (stream == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ public async Task<OrganizationReport> GetLatestOrganizationReportAsync(Guid orga
return result;
}

public async Task<OrganizationReport> ReadLatestOrganizationReportAsync(Guid organizationId)
{
_logger.LogInformation(Constants.BypassFiltersEventId,
"Reading latest validated-file organization report for organization {organizationId}",
organizationId);
var result = await _organizationReportRepo.ReadLatestByOrganizationIdAsync(organizationId);

if (result == null)
{
throw new NotFoundException($"No validated report found for organization: {organizationId}");
}

return result;
}

public async Task<OrganizationReport> GetOrganizationReportAsync(Guid reportId)
{
_logger.LogInformation(Constants.BypassFiltersEventId, "Fetching organization reports for organization by Id: {reportId}", reportId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public interface IGetOrganizationReportQuery
{
Task<OrganizationReport> GetOrganizationReportAsync(Guid organizationId);
Task<OrganizationReport> GetLatestOrganizationReportAsync(Guid organizationId);
Task<OrganizationReport> ReadLatestOrganizationReportAsync(Guid organizationId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public interface IOrganizationReportRepository : IRepository<OrganizationReport,
{
// Whole OrganizationReport methods
Task<OrganizationReport> GetLatestByOrganizationIdAsync(Guid organizationId);
Task<OrganizationReport> ReadLatestByOrganizationIdAsync(Guid organizationId);

// SummaryData methods
Task<IEnumerable<OrganizationReportSummaryDataResponse>> GetSummaryDataByDateRangeAsync(Guid organizationId, DateTime startDate, DateTime endDate);
Expand Down
13 changes: 13 additions & 0 deletions src/Infrastructure.Dapper/Dirt/OrganizationReportRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ public async Task<OrganizationReport> GetLatestByOrganizationIdAsync(Guid organi
}
}

public async Task<OrganizationReport> ReadLatestByOrganizationIdAsync(Guid organizationId)
{
using (var connection = new SqlConnection(ReadOnlyConnectionString))
{
var result = await connection.QuerySingleOrDefaultAsync<OrganizationReport>(
$"[{Schema}].[OrganizationReport_ReadLatestByOrganizationId]",
new { OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);

return result;
}
}

public async Task<OrganizationReport> UpdateSummaryDataAsync(Guid organizationId, Guid reportId, string summaryData)
{
using (var connection = new SqlConnection(ConnectionString))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,34 @@ public async Task<OrganizationReport> GetLatestByOrganizationIdAsync(Guid organi
{
var dbContext = GetDatabaseContext(scope);
var result = await dbContext.OrganizationReports
.Where(p => p.OrganizationId == organizationId)
.Where(p => p.OrganizationId == organizationId
&& p.ReportData != string.Empty)
.OrderByDescending(p => p.RevisionDate)
.Take(1)
.FirstOrDefaultAsync();

if (result == null) return default;

return Mapper.Map<OrganizationReport>(result);
}
}

public async Task<OrganizationReport> ReadLatestByOrganizationIdAsync(Guid organizationId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
// Substring match relies on SetReportFile (OrganizationReport.cs) serializing via
// JsonHelpers.IgnoreWritingNull (PascalCase, no whitespace). If those serializer
// options ever change, the substring stops matching V2 rows on non-MSSQL providers
// and the OR fallback silently serves the latest V1 inline row instead, masking
// the bug. The Dapper/MSSQL path uses JSON_VALUE which is format-agnostic.
var result = await dbContext.OrganizationReports
.Where(p => p.OrganizationId == organizationId
&& (
(p.ReportFile != null && p.ReportFile.Contains("\"Validated\":true"))
|| p.ReportData != string.Empty
))
.OrderByDescending(p => p.RevisionDate)
.Take(1)
.FirstOrDefaultAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ BEGIN

SELECT TOP 1
*
FROM [dbo].[OrganizationReportView]
WHERE [OrganizationId] = @OrganizationId
ORDER BY [RevisionDate] DESC
FROM
[dbo].[OrganizationReportView]
WHERE
[OrganizationId] = @OrganizationId
AND [ReportData] <> ''
ORDER BY
[RevisionDate] DESC
END
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
CREATE PROCEDURE [dbo].[OrganizationReport_ReadLatestByOrganizationId]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since OrganizationReport_GetLatestByOrganizationId should have been named OrganizationReport_ReadLatestByOrganizationId, the naming of this new procedure insinuates these two procs return the same data. If this new proc will eventually replace OrganizationReport_GetLatestByOrganizationId, then I'm okay with it; otherwise I think it should be named something else to differentiate that it returns different data, maybe OrganizationReport_ReadLatestValidatedByOrganizationId?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this new proc will eventually replace OrganizationReport_GetLatestByOrganizationId, then I'm okay with it

Yes that's the plan, once pm-31920-access-intelligence-azure-file-storage flag is permanently ON, the V1 OrganizationReport_GetLatestByOrganizationId SP becomes dead code and we remove it, leaving OrganizationReport_ReadLatestByOrganizationId as the only latest-by-org SP.

@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON

SELECT TOP 1
*
FROM
[dbo].[OrganizationReportView]
WHERE
[OrganizationId] = @OrganizationId
AND (
JSON_VALUE([ReportFile], '$.Validated') = 'true'
OR [ReportData] <> ''
)
ORDER BY
[RevisionDate] DESC
END
Loading
Loading