Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expanded GetFiles / File Search with RecipientFileStatus #276

Merged
merged 2 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
56 changes: 56 additions & 0 deletions Test/Altinn.Broker.Tests/FileControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,60 @@ public async Task Search_SearchFileWith_To_Status_Success()
// Assert
Assert.Contains(fileId, contentstring);
}

[Fact]
public async Task Search_SearchFileWith_RecipientStatus_Success()
{
// Arrange
string status = "Published";
string recipientStatus = "Initialized";
var initializeFileResponse = await _senderClient.PostAsJsonAsync("broker/api/v1/file", FileInitializeExtTestFactory.BasicFile());
var fileId = await initializeFileResponse.Content.ReadAsStringAsync();
var initializedFile = await _senderClient.GetFromJsonAsync<FileOverviewExt>($"broker/api/v1/file/{fileId}", _responseSerializerOptions);
Assert.NotNull(initializedFile);
var uploadedFileBytes = Encoding.UTF8.GetBytes("This is the contents of the uploaded file");
using (var content = new ByteArrayContent(uploadedFileBytes))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
var uploadResponse = await _senderClient.PostAsync($"broker/api/v1/file/{fileId}/upload", content);
Assert.True(uploadResponse.IsSuccessStatusCode);
}
var uploadedFile = await _senderClient.GetFromJsonAsync<FileOverviewExt>($"broker/api/v1/file/{fileId}", _responseSerializerOptions);

// Act
var searchResult = await _recipientClient.GetAsync($"broker/api/v1/file?status={status}&recipientStatus={recipientStatus}");
string contentstring = await searchResult.Content.ReadAsStringAsync();

// Assert
Assert.Contains(fileId, contentstring);
}

[Fact]
public async Task Search_SearchFileWith_RecipientStatus_NotFound()
{
// Arrange
string status = "Published";
string recipientStatus = "DownloadConfirmed";
DateTimeOffset dateTimeFrom = DateTime.Now.AddMinutes(-2);
var initializeFileResponse = await _senderClient.PostAsJsonAsync("broker/api/v1/file", FileInitializeExtTestFactory.BasicFile());
DateTimeOffset dateTimeTo = DateTime.Now.AddMinutes(2);
var fileId = await initializeFileResponse.Content.ReadAsStringAsync();
var initializedFile = await _senderClient.GetFromJsonAsync<FileOverviewExt>($"broker/api/v1/file/{fileId}", _responseSerializerOptions);
Assert.NotNull(initializedFile);
var uploadedFileBytes = Encoding.UTF8.GetBytes("This is the contents of the uploaded file");
using (var content = new ByteArrayContent(uploadedFileBytes))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
var uploadResponse = await _senderClient.PostAsync($"broker/api/v1/file/{fileId}/upload", content);
Assert.True(uploadResponse.IsSuccessStatusCode);
}
var uploadedFile = await _senderClient.GetFromJsonAsync<FileOverviewExt>($"broker/api/v1/file/{fileId}", _responseSerializerOptions);

// Act
var searchResult = await _recipientClient.GetAsync($"broker/api/v1/file?status={status}&recipientStatus={recipientStatus}");
string contentstring = await searchResult.Content.ReadAsStringAsync();

// Assert
Assert.DoesNotContain(fileId, contentstring);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Altinn.Broker.Core.Application;
using Altinn.Broker.Core.Domain;
using Altinn.Broker.Core.Domain.Enums;
using Altinn.Broker.Core.Repositories;

using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -52,7 +53,14 @@ public async Task<OneOf<List<Guid>, Error>> Process(GetFilesQueryRequest request
fileSearchEntity.To = new DateTimeOffset(request.To.Value.UtcDateTime, TimeSpan.Zero);
}

var files = await _fileRepository.GetFilesAssociatedWithActor(fileSearchEntity);
return files;
if (request.RecipientStatus.HasValue)
{
fileSearchEntity.RecipientStatus = request.RecipientStatus;
return await _fileRepository.GetFilesForRecipientWithRecipientStatus(fileSearchEntity);
}
else
{
return await _fileRepository.GetFilesAssociatedWithActor(fileSearchEntity);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class GetFilesQueryRequest
public string Consumer { get; set; }
public string Supplier { get; set; }
public FileStatus? Status { get; set; }
public ActorFileStatus? RecipientStatus { get; set; }
public DateTimeOffset? From { get; set; }
public DateTimeOffset? To { get; set; }
}
1 change: 1 addition & 0 deletions src/Altinn.Broker.Core/Domain/FileSearchEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class FileSearchEntity
{
public ActorEntity Actor { get; set; }
public FileStatus? Status { get; set; }
public ActorFileStatus? RecipientStatus { get; set; }
public DateTimeOffset? From { get; set; }
public DateTimeOffset? To { get; set; }
}
1 change: 1 addition & 0 deletions src/Altinn.Broker.Core/Repositories/IFileRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Task<Guid> AddFile(
string? checksum);
Task<Domain.FileEntity?> GetFile(Guid fileId);
Task<List<Guid>> GetFilesAssociatedWithActor(FileSearchEntity fileSearch);
Task<List<Guid>> GetFilesForRecipientWithRecipientStatus(FileSearchEntity fileSearch);
Task SetStorageReference(
Guid fileId,
long storageProviderId,
Expand Down
51 changes: 51 additions & 0 deletions src/Altinn.Broker.Persistence/Repositories/FileRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,57 @@ public async Task<List<Guid>> GetFilesAssociatedWithActor(FileSearchEntity fileS
}
}

public async Task<List<Guid>> GetFilesForRecipientWithRecipientStatus(FileSearchEntity fileSearch)
{
StringBuilder commandString = new StringBuilder();
commandString.AppendLine("SELECT DISTINCT f.file_id_pk");
commandString.AppendLine("FROM broker.file f");
commandString.AppendLine("INNER JOIN LATERAL (SELECT afs.actor_file_status_id_fk FROM broker.actor_file_status afs WHERE afs.file_id_fk = f.file_id_pk AND afs.actor_id_fk = @recipientId ORDER BY afs.actor_file_status_id_fk desc LIMIT 1) AS recipientfilestatus ON true");
commandString.AppendLine("INNER JOIN LATERAL (SELECT fs.file_status_description_id_fk FROM broker.file_status fs where fs.file_id_fk = f.file_id_pk ORDER BY fs.file_status_id_pk desc LIMIT 1 ) AS filestatus ON true");
commandString.AppendLine("WHERE actor_file_status_id_fk = @recipientFileStatus");
if (fileSearch.Status.HasValue)
{
commandString.AppendLine("AND file_status_description_id_fk = @fileStatus");
}
if (fileSearch.From.HasValue && fileSearch.To.HasValue)
{
commandString.AppendLine("AND f.created between @from AND @to");
}
else if (fileSearch.From.HasValue)
{
commandString.AppendLine("AND f.created > @from");
}
else if (fileSearch.To.HasValue)
{
commandString.AppendLine("AND f.created < @to");
}

await using (var command = await _connectionProvider.CreateCommand(
commandString.ToString()))
{
command.Parameters.AddWithValue("@recipientId", fileSearch.Actor.ActorId);
if (fileSearch.From.HasValue)
command.Parameters.AddWithValue("@From", fileSearch.From);
if (fileSearch.To.HasValue)
command.Parameters.AddWithValue("@To", fileSearch.To);
if (fileSearch.Status.HasValue)
command.Parameters.AddWithValue("@fileStatus", (int)fileSearch.Status);
if (fileSearch.RecipientStatus.HasValue)
command.Parameters.AddWithValue("@recipientFileStatus", (int)fileSearch.RecipientStatus);

var files = new List<Guid>();
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
var fileId = reader.GetGuid(0);
files.Add(fileId);
}
}
return files;
}
}

public async Task SetStorageReference(Guid fileId, long storageProviderId, string fileLocation)
{
await using (var command = await _connectionProvider.CreateCommand(
Expand Down
4 changes: 3 additions & 1 deletion src/Altinn.Broker/Controllers/FileController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,10 @@ public async Task<ActionResult<FileStatusDetailsExt>> GetFileDetails(
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize(Policy = "Sender")]
[Authorize(Policy = "SenderOrRecipient")]
public async Task<ActionResult<List<Guid>>> GetFiles(
[FromQuery] FileStatusExt? status,
[FromQuery] RecipientFileStatusExt? recipientStatus,
[FromQuery] DateTimeOffset? from,
[FromQuery] DateTimeOffset? to,
[ModelBinder(typeof(MaskinportenModelBinder))] MaskinportenToken token,
Expand All @@ -199,6 +200,7 @@ public async Task<ActionResult<List<Guid>>> GetFiles(
Consumer = token.Consumer,
Supplier = token.Supplier,
Status = status is not null ? (FileStatus)status : null,
RecipientStatus = recipientStatus is not null ? (ActorFileStatus)recipientStatus : null,
From = from,
To = to
});
Expand Down
1 change: 1 addition & 0 deletions src/Altinn.Broker/Controllers/LegacyFileController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public async Task<ActionResult<FileStatusDetailsExt>> GetFileDetails(
[HttpGet]
public async Task<ActionResult<List<Guid>>> GetFiles(
[FromQuery] FileStatusExt? status,
[FromQuery] RecipientFileStatusExt? recipientStatus,
[FromQuery] DateTimeOffset? from,
[FromQuery] DateTimeOffset? to,
[ModelBinder(typeof(MaskinportenModelBinder))] MaskinportenToken token,
Expand Down
3 changes: 2 additions & 1 deletion src/Altinn.Broker/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,9 @@ static void ConfigureServices(IServiceCollection services, IConfiguration config

services.AddAuthorization(options =>
{
options.AddPolicy("Sender", policy => policy.RequireClaim("scope", ["altinn:broker.write"]));
options.AddPolicy("Sender", policy => policy.RequireClaim("scope", ["altinn:broker.write", "altinn:broker.write altinn:broker.read"]));
options.AddPolicy("Recipient", policy => policy.RequireClaim("scope", ["altinn:broker.read", "altinn:broker.write altinn:broker.read"]));
options.AddPolicy("SenderOrRecipient", policy => policy.RequireClaim("scope", ["altinn:broker.read", "altinn:broker.write", "altinn:broker.write altinn:broker.read"]));
options.AddPolicy("Legacy", policy => policy.RequireClaim("scope", ["altinn:broker.legacy"]));
});

Expand Down