From 70dd7f7142b420cdc083e4b1e4e20e3402ca1bdb Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 2 Jan 2026 15:56:54 +0000 Subject: [PATCH] Add Upload Report functionality and navigation --- .../Components/Admin/AdminNavMenu.razor | 13 +- .../Components/Admin/Pages/Reports/List.razor | 3 + .../Admin/Pages/Reports/Upload.razor | 82 ++++++++++ .../Admin/Pages/Reports/Upload.razor.cs | 140 ++++++++++++++++++ Aaru.Server/Program.cs | 2 + 5 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 Aaru.Server/Components/Admin/Pages/Reports/Upload.razor create mode 100644 Aaru.Server/Components/Admin/Pages/Reports/Upload.razor.cs diff --git a/Aaru.Server/Components/Admin/AdminNavMenu.razor b/Aaru.Server/Components/Admin/AdminNavMenu.razor index 1249fad6..972b8b96 100644 --- a/Aaru.Server/Components/Admin/AdminNavMenu.razor +++ b/Aaru.Server/Components/Admin/AdminNavMenu.razor @@ -263,6 +263,10 @@ Uploaded Reports + + + Upload Report + @@ -744,9 +748,14 @@ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M5.5 7a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1h-5zM5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5z'/%3E%3Cpath d='M9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5L9.5 0zm0 1v2A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5z'/%3E%3C/svg%3E"); } - .bi-chevron-down-nav-menu + .bi-cloud-arrow-up-nav-menu { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M7.646 5.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708l2-2z'/%3E%3Cpath d='M4.406 3.504a.75.75 0 0 1 .992.06l2.286 2.393.992-1.391a.75.75 0 1 1 1.23.888l-1.868 2.612a.75.75 0 0 1-1.06.06L4.338 4.496a.75.75 0 0 1 .068-1.061z'/%3E%3Cpath d='M11.5 6h.5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h.5a.75.75 0 0 0 0-1.5h-.5A3.5 3.5 0 0 0 1.5 13v5a3.5 3.5 0 0 0 3.5 3.5h7a3.5 3.5 0 0 0 3.5-3.5v-5a3.5 3.5 0 0 0-3.5-3.5z'/%3E%3C/svg%3E"); + } + + { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E") + ; } .bi-chevron-right-nav-menu diff --git a/Aaru.Server/Components/Admin/Pages/Reports/List.razor b/Aaru.Server/Components/Admin/Pages/Reports/List.razor index 73039dab..3ab0592d 100644 --- a/Aaru.Server/Components/Admin/Pages/Reports/List.razor +++ b/Aaru.Server/Components/Admin/Pages/Reports/List.razor @@ -59,6 +59,9 @@

Manage device identification reports

+ + Upload Report + diff --git a/Aaru.Server/Components/Admin/Pages/Reports/Upload.razor b/Aaru.Server/Components/Admin/Pages/Reports/Upload.razor new file mode 100644 index 00000000..069cfaaf --- /dev/null +++ b/Aaru.Server/Components/Admin/Pages/Reports/Upload.razor @@ -0,0 +1,82 @@ +@page "/admin/reports/upload" +@attribute [Authorize] +@layout AdminLayout +@rendermode InteractiveServer + +Upload Device Report + +
+ +
+

+ Upload Device Report +

+

Upload a device identification report in JSON format

+
+ +
+
+
+
+
Select and Upload Report
+
+
+ @if(!string.IsNullOrEmpty(_errorMessage)) + { + + } + + @if(!string.IsNullOrEmpty(_successMessage)) + { + + } + +
+ + + + Select a valid device report JSON file (.json) + +
+ + @if(_fileSelected) + { +
+
File Information
+
+ File: @_selectedFileName
+ Size: @FormatFileSize(_selectedFileSize)
+
+
+ } + +
+ + Cancel +
+
+
+
+
+
+ diff --git a/Aaru.Server/Components/Admin/Pages/Reports/Upload.razor.cs b/Aaru.Server/Components/Admin/Pages/Reports/Upload.razor.cs new file mode 100644 index 00000000..db6a3f27 --- /dev/null +++ b/Aaru.Server/Components/Admin/Pages/Reports/Upload.razor.cs @@ -0,0 +1,140 @@ +using System.Text; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Forms; + +namespace Aaru.Server.Components.Admin.Pages.Reports; + +public partial class Upload : ComponentBase +{ + private string _errorMessage; + private byte[] _fileContent; + + private InputFile _fileInput; + private bool _fileSelected; + private bool _isUploading; + private string _selectedFileName; + private long _selectedFileSize; + private string _successMessage; + [Inject] + private HttpClient Http { get; set; } + + [Inject] + private NavigationManager NavigationManager { get; set; } + + private async Task HandleFileSelected(InputFileChangeEventArgs e) + { + _errorMessage = null; + _successMessage = null; + _fileSelected = false; + + try + { + IBrowserFile? file = e.File; + + if(file == null) + { + _errorMessage = "No file selected."; + + return; + } + + if(!file.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) + { + _errorMessage = "Please select a valid JSON file (.json)"; + + return; + } + + const long maxFileSize = 10 * 1024 * 1024; // 10 MB + + if(file.Size > maxFileSize) + { + _errorMessage = $"File size exceeds the maximum allowed size of {FormatFileSize(maxFileSize)}"; + + return; + } + + _selectedFileName = file.Name; + _selectedFileSize = file.Size; + + using var memoryStream = new MemoryStream(); + await file.OpenReadStream(maxFileSize).CopyToAsync(memoryStream); + _fileContent = memoryStream.ToArray(); + + _fileSelected = true; + } + catch(Exception ex) + { + _errorMessage = $"Error reading file: {ex.Message}"; + } + } + + private async Task UploadFile() + { + if(!_fileSelected) + { + _errorMessage = "Please select a file first."; + + return; + } + + _isUploading = true; + _errorMessage = null; + _successMessage = null; + + try + { + string jsonContent = Encoding.UTF8.GetString(_fileContent); + + using var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); + var uploadUrl = NavigationManager.ToAbsoluteUri("/api/uploadreportv2").ToString(); + using HttpResponseMessage response = await Http.PostAsync(uploadUrl, content); + + string? responseContent = await response.Content.ReadAsStringAsync(); + + if(response.IsSuccessStatusCode && responseContent == "ok") + { + _successMessage = "Report uploaded successfully!"; + _fileSelected = false; + _selectedFileName = null; + _selectedFileSize = 0; + _fileContent = null; + + // Reset file input + if(_fileInput != null) + { + // Navigate away after a short delay to show success message + await Task.Delay(1500); + NavigationManager.NavigateTo("/admin/reports"); + } + } + else if(responseContent == "notstats") + _errorMessage = "Invalid report format: The uploaded file is not a valid device report."; + else + _errorMessage = $"Upload failed: {responseContent ?? response.ReasonPhrase}"; + } + catch(Exception ex) + { + _errorMessage = $"Error uploading file: {ex.Message}"; + } + finally + { + _isUploading = false; + } + } + + private string FormatFileSize(long bytes) + { + string[] sizes = ["B", "KB", "MB", "GB"]; + double len = bytes; + var order = 0; + + while(len >= 1024 && order < sizes.Length - 1) + { + order++; + len = len / 1024; + } + + return $"{len:0.##} {sizes[order]}"; + } +} \ No newline at end of file diff --git a/Aaru.Server/Program.cs b/Aaru.Server/Program.cs index d3c71485..3d993250 100644 --- a/Aaru.Server/Program.cs +++ b/Aaru.Server/Program.cs @@ -165,6 +165,8 @@ builder.WebHost.UseSentry(o => // Add services to the container. builder.Services.AddRazorComponents().AddInteractiveServerComponents(); +builder.Services.AddScoped(); + builder.Services.AddCascadingAuthenticationState(); builder.Services.AddScoped(); builder.Services.AddScoped();