DMS Layout mit Fehlern
All checks were successful
Build & Deploy PLDpro.Web Test to 192.168.1.100 / build-and-deploy (push) Successful in 1m15s
All checks were successful
Build & Deploy PLDpro.Web Test to 192.168.1.100 / build-and-deploy (push) Successful in 1m15s
This commit is contained in:
95
Services/UI/StorageDocumentClient.cs
Normal file
95
Services/UI/StorageDocumentClient.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Pldpro.Web.UI.Models;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace Pldpro.Web.UI.Services;
|
||||
|
||||
public sealed class StorageDocumentClient(IHttpClientFactory factory) : IDocumentClient
|
||||
{
|
||||
private readonly HttpClient _http = factory.CreateClient("AppApi");
|
||||
|
||||
private sealed record BucketVm(string Name, DateTime? CreationDate);
|
||||
private sealed record ObjectVm(string Key, long? Size, DateTime? LastModified);
|
||||
|
||||
public async Task<IReadOnlyList<string>> ListBucketsAsync(CancellationToken ct = default)
|
||||
{
|
||||
var list = await _http.GetFromJsonAsync<List<BucketVm>>("/api/storage/buckets", ct) ?? new();
|
||||
return list.Select(b => b.Name).ToList();
|
||||
}
|
||||
|
||||
public async Task<(IReadOnlyList<DocumentListItem> Items, int Total)> SearchAsync(
|
||||
string bucket, string? query, string? pathPrefix, int page, int pageSize, CancellationToken ct = default)
|
||||
{
|
||||
var objs = await _http.GetFromJsonAsync<List<ObjectVm>>($"/api/storage/buckets/{Uri.EscapeDataString(bucket)}/objects", ct) ?? new();
|
||||
|
||||
IEnumerable<DocumentListItem> q = objs.Select(o => new DocumentListItem
|
||||
{
|
||||
Bucket = bucket,
|
||||
Key = o.Key,
|
||||
Size = o.Size,
|
||||
LastModified = o.LastModified
|
||||
});
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(pathPrefix))
|
||||
q = q.Where(d => d.Key.StartsWith(pathPrefix!.Trim('/') + "/", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
q = q.Where(d =>
|
||||
d.FileName.Contains(query, StringComparison.OrdinalIgnoreCase) ||
|
||||
d.PathPrefix.Contains(query, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
var total = q.Count();
|
||||
var pageItems = q
|
||||
.OrderByDescending(d => d.LastModified ?? DateTime.MinValue)
|
||||
.Skip(page * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToList();
|
||||
|
||||
return (pageItems, total);
|
||||
}
|
||||
|
||||
public async Task<DocumentDetail?> GetAsync(string bucket, string key, CancellationToken ct = default)
|
||||
{
|
||||
// Da es keinen Einzel-Endpoint gibt, holen wir die Liste und picken das Objekt.
|
||||
var (items, _) = await SearchAsync(bucket, null, null, 0, int.MaxValue, ct);
|
||||
var d = items.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.Ordinal));
|
||||
return d is null ? null : new DocumentDetail
|
||||
{
|
||||
Bucket = d.Bucket,
|
||||
Key = d.Key,
|
||||
Size = d.Size,
|
||||
LastModified = d.LastModified,
|
||||
Status = d.Status
|
||||
};
|
||||
}
|
||||
|
||||
public async Task UploadAsync(string bucket, string? pathPrefix, IBrowserFile file, long streamLimit, CancellationToken ct = default)
|
||||
{
|
||||
using var stream = file.OpenReadStream(streamLimit);
|
||||
using var content = new MultipartFormDataContent();
|
||||
content.Add(new StreamContent(stream), "file", file.Name);
|
||||
if (!string.IsNullOrWhiteSpace(pathPrefix))
|
||||
content.Add(new StringContent(pathPrefix!.Trim('/')), "path");
|
||||
|
||||
var resp = await _http.PostAsync($"/api/storage/buckets/{Uri.EscapeDataString(bucket)}/upload", content, ct);
|
||||
resp.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(string bucket, string key, CancellationToken ct = default)
|
||||
{
|
||||
var url = $"/api/storage/buckets/{Uri.EscapeDataString(bucket)}/objects/{EncodeKeyForPath(key)}";
|
||||
var resp = await _http.DeleteAsync(url, ct);
|
||||
resp.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public string GetDownloadUrl(string bucket, string key)
|
||||
=> $"/api/storage/buckets/{Uri.EscapeDataString(bucket)}/download/{EncodeKeyForPath(key)}";
|
||||
|
||||
// Pfadsegment-weise encodieren: Slashes bleiben Trennzeichen
|
||||
private static string EncodeKeyForPath(string key)
|
||||
=> string.Join("/", (key ?? string.Empty)
|
||||
.Split('/', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(Uri.EscapeDataString));
|
||||
}
|
||||
Reference in New Issue
Block a user