Extracted some pages to their own assembly and finished the artifact display page code
@@ -18,6 +18,8 @@
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<script src=@Assets["_content/MudBlazor/MudBlazor.min.js"]></script>
|
||||
<script src="_content/CodeBeam.MudBlazor.Extensions/MudExtensions.min.js"></script>
|
||||
<script src="js/downloadHelper.js"></script>
|
||||
<script src="js/imageSizeGetter.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -5,9 +5,17 @@
|
||||
@* Loop through and display each item as a chip *@
|
||||
@foreach (var item in Items)
|
||||
{
|
||||
<MudChip Color="Color.Primary" OnClose="() => RemoveItem(item)" T="T">
|
||||
@DisplayFunc(item)
|
||||
</MudChip>
|
||||
@if (DeleteEnabled)
|
||||
{
|
||||
<MudChip Color="Color.Primary" OnClose="() => RemoveItem(item)" T="T">
|
||||
@DisplayFunc(item)
|
||||
</MudChip>
|
||||
} else
|
||||
{
|
||||
<MudChip Color="Color.Primary" T="T">
|
||||
@DisplayFunc(item)
|
||||
</MudChip>
|
||||
}
|
||||
}
|
||||
|
||||
@* Render the input control provided by the consumer *@
|
||||
@@ -22,6 +30,9 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public bool DeleteEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The list of items to display and manage.
|
||||
/// </summary>
|
||||
@@ -51,8 +62,6 @@
|
||||
[Parameter]
|
||||
public Func<T, string> DisplayFunc { get; set; } = item => item?.ToString() ?? string.Empty;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A public method that the consumer's input control can call to add a new item.
|
||||
/// </summary>
|
||||
|
||||
@@ -230,4 +230,19 @@
|
||||
|
||||
private void ClearDragClass()
|
||||
=> _dragClass = DefaultDragClass;
|
||||
|
||||
public void RemoveFile(string filename)
|
||||
{
|
||||
var existingFile = ExistingFiles.Where(f => f.OriginalName == filename).FirstOrDefault();
|
||||
if (existingFile is not null)
|
||||
{
|
||||
ExistingFiles.Remove(existingFile);
|
||||
}
|
||||
|
||||
var file = Files.Where(f => f.Name == filename).FirstOrDefault();
|
||||
if (file is not null)
|
||||
{
|
||||
Files.Remove(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@using OpenArchival.Blazor.Components.Pages.Administration.Categories
|
||||
@using OpenArchival.DataAccess;
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using MudBlazor
|
||||
|
||||
@inject IDialogService DialogService
|
||||
@inject NavigationManager NavigationManager;
|
||||
@@ -193,6 +194,9 @@
|
||||
{
|
||||
// The data entry should only be shown if a category has been selected
|
||||
_isFormDivVisible = true;
|
||||
} else
|
||||
{
|
||||
_isFormDivVisible = false;
|
||||
}
|
||||
|
||||
if (Model is not null)
|
||||
@@ -223,11 +227,11 @@
|
||||
|
||||
if (IsValid && ClearOnPublish)
|
||||
{
|
||||
Model = new();
|
||||
Model = new();
|
||||
await _uploadComponent.ClearClicked.InvokeAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
await GroupingPublished.InvokeAsync(oldModel);
|
||||
}
|
||||
|
||||
@@ -343,10 +347,10 @@
|
||||
return categories;
|
||||
}
|
||||
|
||||
private async void OnDeleteEntryClicked(int index)
|
||||
private async void OnDeleteEntryClicked((int index, string filename) data)
|
||||
{
|
||||
Model.ArtifactEntries.RemoveAt(index);
|
||||
_uploadComponent.Files.RemoveAt(index);
|
||||
Model.ArtifactEntries.RemoveAt(data.index);
|
||||
_uploadComponent.RemoveFile(data.filename);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
<MudDivider DividerType="DividerType.Middle"></MudDivider>
|
||||
<ChipContainer T="DateTime" @ref="_assocaitedDatesChipContainer" @bind-Items="Model.AssociatedDates" DisplayFunc="date => date.ToShortDateString()">
|
||||
<InputContent>
|
||||
<MudDatePicker @bind-Date=_associatedDateInputValue>
|
||||
<MudDatePicker @bind-Date=_associatedDateInputValue MinDate="new DateTime(1000, 1, 1)">
|
||||
</MudDatePicker>
|
||||
</InputContent>
|
||||
<SubmitButton>
|
||||
@@ -149,7 +149,7 @@
|
||||
For="@(() => Model.FileTextContent)"></MudTextField>
|
||||
|
||||
<MudText Typo=Typo.h6 Color="Color.Primary">Additional files</MudText>
|
||||
<UploadDropBox FilesUploaded="OnFilesUploaded"></UploadDropBox>
|
||||
<UploadDropBox @ref=_uploadDropBox FilesUploaded="OnFilesUploaded"></UploadDropBox>
|
||||
</MudPaper>
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
public required int ArtifactEntryIndex {get; set;}
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<int> OnEntryDeletedClicked { get; set; }
|
||||
public EventCallback<(int index, string filename)> OnEntryDeletedClicked { get; set; }
|
||||
|
||||
private ChipContainer<string> _tagsChipContainer;
|
||||
|
||||
@@ -198,6 +198,23 @@
|
||||
|
||||
public List<ValidationResult> ValidationResults { get; private set; } = [];
|
||||
|
||||
public UploadDropBox _uploadDropBox = default!;
|
||||
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
if (_uploadDropBox is not null && Model is not null && Model.Files is not null)
|
||||
{
|
||||
_uploadDropBox.ExistingFiles = Model.Files.GetRange(1, Model.Files.Count - 1);
|
||||
}
|
||||
|
||||
if (Model.Files is not null && Model.Files.Any())
|
||||
{
|
||||
MainFilePath = Model.Files[0];
|
||||
}
|
||||
|
||||
return base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
public async Task OnInputsChanged()
|
||||
{
|
||||
// 1. Clear previous validation errors
|
||||
@@ -217,12 +234,17 @@
|
||||
{
|
||||
if (MainFilePath is not null)
|
||||
{
|
||||
var oldFiles = Model.Files.GetRange(1, Model.Files.Count - 1);
|
||||
Model.Files = [MainFilePath];
|
||||
Model.Files.AddRange(oldFiles);
|
||||
Model.Files.AddRange(filePathListings);
|
||||
} else
|
||||
{
|
||||
Model.Files = [];
|
||||
}
|
||||
Model.Files.AddRange(filePathListings);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task OnFilesCleared()
|
||||
@@ -296,6 +318,6 @@
|
||||
}
|
||||
private async Task OnDeleteEntryClicked(MouseEventArgs args)
|
||||
{
|
||||
await OnEntryDeletedClicked.InvokeAsync(ArtifactEntryIndex);
|
||||
await OnEntryDeletedClicked.InvokeAsync((ArtifactEntryIndex, MainFilePath.OriginalName));
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,11 @@ using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class ArtifactEntryValidationModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Used when translating between the validation model and the database model
|
||||
/// </summary>
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Required(AllowEmptyStrings = false, ErrorMessage = "An artifact numbering must be supplied")]
|
||||
public string? ArtifactNumber { get; set; }
|
||||
|
||||
@@ -33,14 +38,8 @@ public class ArtifactEntryValidationModel
|
||||
public string? FileTextContent { get; set; }
|
||||
|
||||
public List<ArtifactEntry> RelatedArtifacts { get; set; } = [];
|
||||
|
||||
/*
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext context)
|
||||
{
|
||||
|
||||
}
|
||||
*/
|
||||
public bool IsPublicallyVisible { get; set; }
|
||||
|
||||
public bool IsPublicallyVisible { get; set; } = true;
|
||||
|
||||
public ArtifactEntry ToArtifactEntry(ArtifactGrouping? parent = null)
|
||||
{
|
||||
@@ -59,10 +58,9 @@ public class ArtifactEntryValidationModel
|
||||
defects.Add(new ArtifactDefect() { Description=defect});
|
||||
}
|
||||
|
||||
|
||||
|
||||
var entry = new ArtifactEntry()
|
||||
{
|
||||
Id = Id ?? 0,
|
||||
Files = Files,
|
||||
Type = new DataAccess.ArtifactType() { Name = Type },
|
||||
ArtifactNumber = ArtifactNumber,
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ArtifactGroupingValidationModel : IValidatableObject
|
||||
|
||||
public List<ArtifactEntryValidationModel> ArtifactEntries { get; set; } = new();
|
||||
|
||||
public bool IsPublicallyVisible { get; set; }
|
||||
public bool IsPublicallyVisible { get; set; } = true;
|
||||
|
||||
public ArtifactGrouping ToArtifactGrouping()
|
||||
{
|
||||
@@ -75,6 +75,7 @@ public class ArtifactGroupingValidationModel : IValidatableObject
|
||||
|
||||
var validationModel = new ArtifactEntryValidationModel()
|
||||
{
|
||||
Id = entry.Id,
|
||||
Title = entry.Title,
|
||||
StorageLocation = entry.StorageLocation.Location,
|
||||
ArtifactNumber = entry.ArtifactNumber,
|
||||
@@ -131,7 +132,7 @@ public class ArtifactGroupingValidationModel : IValidatableObject
|
||||
}
|
||||
}
|
||||
|
||||
if (ArtifactEntries.IsNullOrEmpty())
|
||||
if (ArtifactEntries is null || ArtifactEntries.Count == 0)
|
||||
{
|
||||
yield return new ValidationResult("Must upload one or more files");
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class CategoryValidationModel
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext context)
|
||||
{
|
||||
if (FieldNames.IsNullOrEmpty() || FieldDescriptions.IsNullOrEmpty())
|
||||
if ((FieldNames is null || FieldNames.Count == 0) || (FieldDescriptions is null || FieldDescriptions.Count == 0))
|
||||
{
|
||||
yield return new ValidationResult(
|
||||
"Either the FieldNames or FieldDescriptions were null or empty. At least one is required",
|
||||
|
||||
@@ -1,5 +1,85 @@
|
||||
<h3>ArchiveEntryDisplay</h3>
|
||||
@using OpenArchival.Blazor.FileViewer
|
||||
|
||||
<MudPaper Class="pa-4 ma-2 rounded" Elevation="3">
|
||||
<MudGrid Spacing="2">
|
||||
<MudItem lg="8" xs="12" Class="d-flex align-center justify-center flex-column">
|
||||
<MudText Class="d-flex" Typo=Typo.h6>@ArtifactEntry.Title</MudText>
|
||||
<FileViewerCarousel FilePathListings="ArtifactEntry.Files" MaxHeight="350" ShowUnsupportedFiles=true></FileViewerCarousel>
|
||||
</MudItem>
|
||||
|
||||
<MudItem lg="4" xs="12">
|
||||
<MudText Typo="Typo.h6">Artifact Identifier</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.caption">@ArtifactEntry.ArtifactIdentifier</MudText>
|
||||
|
||||
<MudText Typo="Typo.h6">Primary Artifact Type</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.caption">@ArtifactEntry.Type.Name</MudText>
|
||||
|
||||
@if (!string.IsNullOrEmpty(ArtifactEntry.StorageLocation.Location))
|
||||
{
|
||||
<MudText Typo="Typo.h6">Storage Location</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.caption">@ArtifactEntry.StorageLocation.Location</MudText>
|
||||
}
|
||||
|
||||
@if (ArtifactEntry.Tags.Count > 0)
|
||||
{
|
||||
<MudText Typo="Typo.h6">Tags</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<OpenArchival.Blazor.Components.CustomComponents.ChipContainer DeleteEnabled=false @bind-Items="ArtifactEntry.Tags"></OpenArchival.Blazor.Components.CustomComponents.ChipContainer>
|
||||
}
|
||||
|
||||
@if (ArtifactEntry.ListedNames.Count > 0)
|
||||
{
|
||||
<MudText Typo="Typo.h6">Listed Names</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<OpenArchival.Blazor.Components.CustomComponents.ChipContainer DeleteEnabled=false @bind-Items="ArtifactEntry.ListedNames"></OpenArchival.Blazor.Components.CustomComponents.ChipContainer>
|
||||
}
|
||||
|
||||
@if (ArtifactEntry.AssociatedDates.Count > 0)
|
||||
{
|
||||
<MudText Typo="Typo.h6">Associated Dates</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<OpenArchival.Blazor.Components.CustomComponents.ChipContainer DeleteEnabled=false @bind-Items="ArtifactEntry.AssociatedDates" DisplayFunc="@(date => date.ToString("d"))"></OpenArchival.Blazor.Components.CustomComponents.ChipContainer>
|
||||
}
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudText Class="mt-4" Typo="Typo.h6">Description</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.body1">@ArtifactEntry.Description</MudText>
|
||||
|
||||
<MudExpansionPanel Text="Downloads">
|
||||
<MudList T="string">
|
||||
@foreach (FilePathListing file in ArtifactEntry.Files)
|
||||
{
|
||||
<MudListItem Icon="@Icons.Material.Filled.Download" IconColor="Color.Primary" OnClick="() => OnFileDownloadClicked(file)">@file.OriginalName</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
</MudExpansionPanel>
|
||||
</MudPaper>
|
||||
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject ISnackbar Snackbar
|
||||
@code {
|
||||
[Parameter]
|
||||
public required ArtifactEntry ArtifactEntry { get; set; }
|
||||
|
||||
private async Task OnFileDownloadClicked(FilePathListing file)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] fileBytes = await File.ReadAllBytesAsync(file.Path);
|
||||
|
||||
string mimeType = "";
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("downloadFileFromBytes", file.OriginalName, mimeType, Convert.ToBase64String(fileBytes));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"Failed to download file {file.OriginalName}", Severity.Error);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,55 @@
|
||||
@page "/archive/{GroupingIdString}"
|
||||
@using OpenArchival.DataAccess;
|
||||
@using OpenArchival.Blazor.FileViewer
|
||||
|
||||
@inject IArtifactGroupingProvider GroupingProvider;
|
||||
@inject NavigationManager NavigationManager;
|
||||
|
||||
@if (_artifactGrouping is not null)
|
||||
{
|
||||
<MudText Typo="Typo.h1">@_artifactGrouping.Title</MudText>
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudPaper Class="pa-4 ma-2 rounded d-flex justify-center" Elevation="3">
|
||||
<MudText Typo="Typo.h3">@_artifactGrouping.Title</MudText>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Class="pa-4 ma-2 rounded d-flex justify-center" Elevation="3">
|
||||
@*<MudImage Class="d-flex justify-center" Src="https://dummyimage.com/600x400/000/fff"></MudImage>*@
|
||||
<FileViewerCarousel FilePathListings="_artifactGrouping.ChildFilePathListings" MaxHeight="500" ShowUnsupportedFiles=false></FileViewerCarousel>
|
||||
</MudPaper>
|
||||
|
||||
<MudGrid Spacing="2">
|
||||
<MudItem xs="8">
|
||||
<MudPaper Style="height: 100%;" Class="pa-4 ma-2 rounded" Elevation="3">
|
||||
<MudText Typo="Typo.h6">Description</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.body2">@_artifactGrouping.Description</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<MudPaper Style="height: 100%;" Class="pa-4 ma-2 rounded" Elevation="3">
|
||||
<MudText Typo="Typo.h6">Artifact Identifier</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.caption">@_artifactGrouping.ArtifactGroupingIdentifier</MudText>
|
||||
|
||||
<MudText Typo="Typo.h6">Primary Artifact Category</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.caption">@_artifactGrouping.Category.Name</MudText>
|
||||
|
||||
<MudText Typo="Typo.h6">Primary Artifact Type</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
<MudText Typo="Typo.caption">@_artifactGrouping.Type.Name</MudText>
|
||||
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudPaper Class="pa-4 mt-8 ma-2 rounded" Elevation="3">
|
||||
@foreach (ArtifactEntry child in _artifactGrouping.ChildArtifactEntries) {
|
||||
<ArchiveEntryDisplay ArtifactEntry="child"></ArchiveEntryDisplay>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
</MudContainer>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<h3>FileDisplayBase</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
@if (File is not null)
|
||||
{
|
||||
<MudImage Fluid="true" Src="@File.Path" Alt="Swedish Farm House" Class="rounded-lg"/>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public required FilePathListing File { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the width of the image box while it loads
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int Width { get; set; } = 600;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the height of the image box while it loads
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int Height { get; set; } = 400;
|
||||
|
||||
[Parameter]
|
||||
public string AltText { get; set; } = "";
|
||||
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
if (File is not null || !string.IsNullOrEmpty(AltText))
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
return base.OnParametersSetAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using OpenArchival.Blazor.Components.Pages.ArchiveDisplay;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace OpenArchival.Blazor;
|
||||
|
||||
public class FileDisplayComponentFactory
|
||||
{
|
||||
private Dictionary<string, Type> _extensionToComponents { get; set; } = [];
|
||||
|
||||
public FileDisplayComponentFactory()
|
||||
{
|
||||
// Supported image file types taken from https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types
|
||||
RegisterComponent<FileDisplayImage>(".apng");
|
||||
RegisterComponent<FileDisplayImage>(".png");
|
||||
RegisterComponent<FileDisplayImage>(".avif");
|
||||
RegisterComponent<FileDisplayImage>(".gif");
|
||||
RegisterComponent<FileDisplayImage>(".jpg");
|
||||
RegisterComponent<FileDisplayImage>(".jpeg");
|
||||
RegisterComponent<FileDisplayImage>(".jfif");
|
||||
RegisterComponent<FileDisplayImage>(".pjpeg");
|
||||
RegisterComponent<FileDisplayImage>(".pjg");
|
||||
RegisterComponent<FileDisplayImage>(".png");
|
||||
RegisterComponent<FileDisplayImage>(".svg");
|
||||
RegisterComponent<FileDisplayImage>(".webp");
|
||||
}
|
||||
|
||||
private string GetExtensionKey(string pathOrExtension)
|
||||
{
|
||||
return Path.GetExtension(pathOrExtension).ToUpperInvariant();
|
||||
}
|
||||
|
||||
public bool RegisterComponent<ComponentType>(string filenameOrExtension) where ComponentType : IFileDisplayComponent
|
||||
{
|
||||
string extensionString = GetExtensionKey(filenameOrExtension);
|
||||
|
||||
_extensionToComponents.Add(extensionString, typeof(ComponentType));
|
||||
return true;
|
||||
}
|
||||
|
||||
public Type? GetDisplayComponentType(string filenameOrExtension) {
|
||||
var result = _extensionToComponents.TryGetValue(GetExtensionKey(filenameOrExtension), out var component);
|
||||
|
||||
return (result) ? component : null;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<h3>FileDisplayImage</h3>
|
||||
@implements IFileDisplayComponent
|
||||
<h3>FileDisplayImage</h3>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public required FilePathListing FilePath { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace OpenArchival.Blazor;
|
||||
using OpenArchival.DataAccess;
|
||||
|
||||
namespace OpenArchival.Blazor;
|
||||
|
||||
public interface IFileDisplayComponent
|
||||
{
|
||||
public FilePathListing FilePath { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
@using OpenArchival.Blazor.Components.Account.Shared
|
||||
<Router AppAssembly="typeof(Program).Assembly">
|
||||
|
||||
<Router AppAssembly="typeof(Program).Assembly"
|
||||
AdditionalAssemblies="new[] {typeof(OpenArchival.Blazor.AdminPages.ArchiveConfiguration).Assembly}">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)">
|
||||
<NotAuthorized>
|
||||
|
||||
53
OpenArchival.Blazor/Controllers/FilesController.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OpenArchival.DataAccess; // Assuming your DbContext or service is here
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class FilesController : ControllerBase
|
||||
{
|
||||
// Inject your database context or a service to find file paths
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _context;
|
||||
|
||||
public FilesController(IDbContextFactory<ApplicationDbContext> dbFactory)
|
||||
{
|
||||
_context = dbFactory;
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetFile(int id)
|
||||
{
|
||||
await using var context = await _context.CreateDbContextAsync();
|
||||
|
||||
FilePathListing fileRecord = await context.ArtifactFilePaths.FindAsync(id);
|
||||
|
||||
if (fileRecord == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var physicalPath = fileRecord.Path;
|
||||
|
||||
if (!System.IO.File.Exists(physicalPath))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var fileStream = new FileStream(physicalPath, FileMode.Open, FileAccess.Read);
|
||||
|
||||
return new FileStreamResult(fileStream, GetMimeType(physicalPath));
|
||||
}
|
||||
|
||||
private static string GetMimeType(string filePath)
|
||||
{
|
||||
var extension = Path.GetExtension(filePath).ToLowerInvariant();
|
||||
return extension switch
|
||||
{
|
||||
".jpg" => "image/jpeg",
|
||||
".jpeg" => "image/jpeg",
|
||||
".png" => "image/png",
|
||||
".gif" => "image/gif",
|
||||
_ => "application/octet-stream", // Default for unknown file types
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ WORKDIR /src
|
||||
COPY ["nuget.config", "."]
|
||||
COPY ["OpenArchival.Blazor/OpenArchival.Blazor.csproj", "OpenArchival.Blazor/"]
|
||||
COPY ["OpenArchival.DataAccess/OpenArchival.DataAccess.csproj", "OpenArchival.DataAccess/"]
|
||||
COPY ["OpenArchival.FileViewer/OpenArchival.FileViewer.csproj", "OpenArchival.FileViewer/"]
|
||||
RUN dotnet restore "./OpenArchival.Blazor/OpenArchival.Blazor.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/OpenArchival.Blazor"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<PackageReference Include="CodeBeam.MudExtensions" Version="6.3.0" />
|
||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.*" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
|
||||
@@ -22,10 +22,14 @@
|
||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||
<PackageReference Include="Npgsql.DependencyInjection" Version="9.0.3" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="System.Collections" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenArchival.Blazor.AdminPages\OpenArchival.Blazor.AdminPages.csproj" />
|
||||
<ProjectReference Include="..\OpenArchival.Blazor.CustomComponents\OpenArchival.Blazor.CustomComponents.csproj" />
|
||||
<ProjectReference Include="..\OpenArchival.Blazor.FileViewer\OpenArchival.Blazor.FileViewer.csproj" />
|
||||
<ProjectReference Include="..\OpenArchival.DataAccess\OpenArchival.DataAccess.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
@@ -0,0 +1,196 @@
|
||||
# Language part removed. With clang-format >=20.1, the C and Cpp are separately handled,
|
||||
# so either there is no language at all, or we need to create 2 formats for C and Cpp, separately
|
||||
|
||||
---
|
||||
# Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: true
|
||||
AcrossComments: true
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
SortIncludes: true
|
||||
InsertBraces: true # Control statements must have curly brackets
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: AllDefinitions
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ""
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: "^<(.*)>"
|
||||
Priority: 0
|
||||
- Regex: '^"(.*)"'
|
||||
Priority: 1
|
||||
- Regex: "(.*)"
|
||||
Priority: 2
|
||||
IncludeIsMainRegex: "(Test)?$"
|
||||
IncludeIsMainSourceRegex: ""
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ""
|
||||
MacroBlockEnd: ""
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false
|
||||
RemoveBracesLLVM: false
|
||||
SeparateDefinitionBlocks: Always
|
||||
ShortNamespaceLines: 1
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
---
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 130 KiB |
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -0,0 +1,10 @@
|
||||
[Interface]
|
||||
PrivateKey = SHZ+vDoQyTFLr+sEYBY8r0TXMFnMtsMaA5pcxcKSUWI=
|
||||
Address = 10.88.203.3/24,fd11:5ee:bad:c0de::a58:cb03/64
|
||||
DNS = 10.88.203.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = FVK/Fqod0nha+1l1sGZi2cx1LUU+Ihj6IKF4+g4dmA0=
|
||||
PresharedKey = UdNe7MRgwjEBZ05wg+x7kXEfZJGOCggvtSwCYvMhU4s=
|
||||
Endpoint = pihole.vtallen.com:51820
|
||||
AllowedIPs = 0.0.0.0/0, ::0/0
|
||||
@@ -14,6 +14,7 @@ builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
builder.Services.AddMudServices();
|
||||
builder.Services.AddMudExtensions();
|
||||
builder.Services.AddControllers();
|
||||
|
||||
// --- Database & Identity Configuration ---
|
||||
// Get the single connection string for your PostgreSQL database.
|
||||
@@ -69,6 +70,8 @@ builder.Services.AddLogging();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var serviceProvider = scope.ServiceProvider;
|
||||
|
||||