mirror of
https://github.com/Theodor-Springmann-Stiftung/hamann-ausgabe-core.git
synced 2025-10-30 01:35:32 +00:00
Formatted everything; completed upload capabilities
This commit is contained in:
@@ -8,7 +8,7 @@ public interface IXMLRoot {
|
||||
|
||||
// Name of the file prefix
|
||||
public abstract string Prefix { get; }
|
||||
|
||||
|
||||
// XPaths to determine if container is present
|
||||
public abstract string[] XPathContainer { get; }
|
||||
|
||||
@@ -25,13 +25,14 @@ public interface IXMLRoot {
|
||||
var elements = root.XPathSelectElements(p);
|
||||
if (elements != null && elements.Any()) {
|
||||
if (ret == null) ret = new List<XElement>();
|
||||
ret.AddRange(elements);
|
||||
foreach (var e in elements)
|
||||
if (!ret.Contains(e)) ret.Add(e);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Generate certain metadat fields to display about this root
|
||||
// Generate certain metadata fields to display about this root
|
||||
public abstract List<(string, string?)>? GenerateFields(XMLRootDocument document);
|
||||
|
||||
// Generate an identification string of which the hash will be the filename.
|
||||
|
||||
@@ -5,5 +5,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
public interface IXMLService {
|
||||
public IXMLRoot? GetRoot(string name);
|
||||
public List<IXMLRoot>? GetRoots();
|
||||
public List<XMLRootDocument>? ProbeHamannFile(XDocument document, ModelStateDictionary ModelState);
|
||||
public Task<List<XMLRootDocument>?> ProbeHamannFile(XDocument document, ModelStateDictionary ModelState);
|
||||
public Task UpdateAvailableFiles(XMLRootDocument doc, string basefilepath, ModelStateDictionary ModelState);
|
||||
public Dictionary<string, List<XMLRootDocument>> GetUsed();
|
||||
}
|
||||
34
HaWeb/XMLParser/JSONConverters.cs
Normal file
34
HaWeb/XMLParser/JSONConverters.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace HaWeb.XMLParser;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
||||
public class IdentificationStringJSONConverter : JsonConverter<(string?, string?)>
|
||||
{
|
||||
public override (string?, string?) Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options) {
|
||||
var s = reader.GetString();
|
||||
if (s == null) return (null, null);
|
||||
var split = s.Split('-');
|
||||
string? str1 = null;
|
||||
if (!String.IsNullOrWhiteSpace(split[0])) str1 = split[0];
|
||||
if (s.Length > 1 && !String.IsNullOrWhiteSpace(split[1])) return (str1, split[1]);
|
||||
else return (str1, null);
|
||||
}
|
||||
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
(string?, string?) value,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
if (value.Item1 == null && value.Item2 == null) return;
|
||||
var res = "";
|
||||
if (value.Item1 != null) res += value.Item1;
|
||||
if (value.Item2 != null) res += "-" + value.Item2;
|
||||
writer.WriteStringValue(res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,42 +2,45 @@ namespace HaWeb.XMLParser;
|
||||
using System.Xml.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
public class XMLRootDocument {
|
||||
private XElement? _Element;
|
||||
private string? _filename;
|
||||
private string? _path;
|
||||
private IXMLService _xmlService;
|
||||
|
||||
[JsonIgnore]
|
||||
public XElement Root {
|
||||
public XElement Root {
|
||||
get {
|
||||
if (_Element == null) {
|
||||
_Element = GetElement();
|
||||
_Element = _GetElement();
|
||||
}
|
||||
return _Element;
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
public string FileName { get {
|
||||
if (_filename == null)
|
||||
_filename = _CreateFilename();
|
||||
return _filename;
|
||||
} }
|
||||
public string FileName {
|
||||
get {
|
||||
if (_filename == null)
|
||||
_filename = _CreateFilename();
|
||||
return _filename;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public IFileInfo? File { get; private set; }
|
||||
public string Prefix { get; private set; }
|
||||
public DateTime Date { get; private set; }
|
||||
|
||||
public bool Used { get; private set; } = false;
|
||||
|
||||
public (string?, string?) IdentificationString { get; private set; }
|
||||
[JsonIgnore]
|
||||
public List<(string, string)>? Fields { get; set; }
|
||||
|
||||
// Entry point for file reading
|
||||
public XMLRootDocument(IXMLService xmlService, string prefix, (string?, string?) idString, DateTime date, string path) {
|
||||
public XMLRootDocument(IXMLService xmlService, IFileInfo file) {
|
||||
_xmlService = xmlService;
|
||||
_path = path;
|
||||
Prefix = prefix;
|
||||
IdentificationString = idString;
|
||||
Date = date;
|
||||
SetFile(file);
|
||||
}
|
||||
|
||||
// Entry point for XML upload reading
|
||||
@@ -49,6 +52,19 @@ public class XMLRootDocument {
|
||||
_Element = element;
|
||||
}
|
||||
|
||||
public void SetFile(IFileInfo file) {
|
||||
File = file;
|
||||
Date = file.LastModified.DateTime;
|
||||
_GenerateFieldsFromFilename(file.Name);
|
||||
}
|
||||
|
||||
public void SetUsed(bool used) {
|
||||
Used = used;
|
||||
if (used && _Element == null) {
|
||||
_GetElement();
|
||||
}
|
||||
}
|
||||
|
||||
private string _CreateFilename() {
|
||||
var filename = _removeInvalidChars(Prefix) + "_";
|
||||
if (!String.IsNullOrWhiteSpace(IdentificationString.Item1)) {
|
||||
@@ -69,28 +85,39 @@ public class XMLRootDocument {
|
||||
return s;
|
||||
}
|
||||
|
||||
private XElement GetElement() {
|
||||
if (_path == null || String.IsNullOrWhiteSpace(_path))
|
||||
private void _GenerateFieldsFromFilename(string filename) {
|
||||
var split = filename.Split('_');
|
||||
Prefix = split[0];
|
||||
if (split.Length == 3) {
|
||||
IdentificationString = (null, split[1]);
|
||||
} else if (split.Length == 4) {
|
||||
IdentificationString = (split[1], split[2]);
|
||||
} else {
|
||||
IdentificationString = (null, null);
|
||||
}
|
||||
}
|
||||
|
||||
private XElement _GetElement() {
|
||||
if (File == null || String.IsNullOrWhiteSpace(File.PhysicalPath) || !File.Exists)
|
||||
throw new Exception("Es ist kein Pfad für die XML-Datei vorhanden.");
|
||||
|
||||
|
||||
var root = _xmlService.GetRoot(Prefix);
|
||||
if (root == null)
|
||||
throw new Exception("Kein gültiges Hamann-Dokument: " + _path + "Vom Prefix: " + Prefix);
|
||||
|
||||
throw new Exception("Kein gültiges Hamann-Dokument: " + File.PhysicalPath + "Vom Prefix: " + Prefix);
|
||||
|
||||
XDocument? doc = null;
|
||||
try {
|
||||
doc = XDocument.Load(_path, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
doc = XDocument.Load(File.PhysicalPath, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Fehler beim Lesen des Dokuments: " + ex.Message);
|
||||
}
|
||||
|
||||
if (doc == null || doc.Root == null)
|
||||
throw new Exception("Das Dokument ist ungültig und kann nicht gelesen werden: " + _path);
|
||||
throw new Exception("Das Dokument ist ungültig und kann nicht gelesen werden: " + File.PhysicalPath);
|
||||
|
||||
var element = root.IsTypeOf(doc.Root);
|
||||
if (element == null || !element.Any())
|
||||
throw new Exception("Kein gültiges Hamann-Dokument: " + _path + "Vom Prefix: " + Prefix);
|
||||
throw new Exception("Kein gültiges Hamann-Dokument: " + File.PhysicalPath + "Vom Prefix: " + Prefix);
|
||||
|
||||
return element.First();
|
||||
}
|
||||
|
||||
@@ -2,17 +2,43 @@ namespace HaWeb.XMLParser;
|
||||
using HaWeb.Settings.XMLRoots;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.FeatureManagement;
|
||||
|
||||
public class XMLService : IXMLService {
|
||||
private Dictionary<string, List<XMLRootDocument>?>? _availableFilesObj;
|
||||
private Dictionary<string, List<XMLRootDocument>?>? _availableFiles {
|
||||
get {
|
||||
if (_availableFilesObj == null) {
|
||||
_availableFilesObj = _GetAvailableFiles();
|
||||
AutoDetermineUsed();
|
||||
}
|
||||
return _availableFilesObj;
|
||||
} }
|
||||
|
||||
private IFileProvider _fileProvider;
|
||||
private IFeatureManager _featureManager;
|
||||
private Dictionary<string, IXMLRoot>? _Roots;
|
||||
|
||||
public XMLService() {
|
||||
public bool UploadEnabled = false;
|
||||
public bool UpdateEnabled = false;
|
||||
|
||||
public XMLService(IFileProvider provider, IFeatureManager featureManager) {
|
||||
_fileProvider = provider;
|
||||
_featureManager = featureManager;
|
||||
if (provider == null)
|
||||
throw new Exception("To Upload Files you need a FileProvider");
|
||||
|
||||
// Getting all classes which implement IXMLRoot for possible upload endpoints
|
||||
var types = _GetAllTypesThatImplementInterface<IXMLRoot>().ToList();
|
||||
types.ForEach( x => {
|
||||
if (this._Roots == null) this._Roots = new Dictionary<string, IXMLRoot>();
|
||||
var instance = (IXMLRoot)Activator.CreateInstance(x)!;
|
||||
if (instance != null) this._Roots.Add(instance.Prefix, instance);
|
||||
});
|
||||
|
||||
if (_Roots == null || !_Roots.Any())
|
||||
throw new Exception("No classes for upload endpoints were found!");
|
||||
}
|
||||
|
||||
public IXMLRoot? GetRoot(string name) {
|
||||
@@ -22,7 +48,7 @@ public class XMLService : IXMLService {
|
||||
|
||||
public List<IXMLRoot>? GetRoots() => this._Roots == null ? null : this._Roots.Values.ToList();
|
||||
|
||||
public List<XMLRootDocument>? ProbeHamannFile(XDocument document, ModelStateDictionary ModelState) {
|
||||
public async Task<List<XMLRootDocument>?> ProbeHamannFile(XDocument document, ModelStateDictionary ModelState) {
|
||||
if (document.Root!.Name != "opus") {
|
||||
ModelState.AddModelError("Error", "A valid Hamann-Docuemnt must begin with <opus>");
|
||||
return null;
|
||||
@@ -43,6 +69,63 @@ public class XMLService : IXMLService {
|
||||
return res;
|
||||
}
|
||||
|
||||
public void UpdateAvailableFiles() {
|
||||
_availableFilesObj = _GetAvailableFiles();
|
||||
}
|
||||
|
||||
public void UpdateAvailableFiles(string prefix) {
|
||||
if (_availableFilesObj == null) {
|
||||
UpdateAvailableFiles();
|
||||
return;
|
||||
}
|
||||
if (_availableFilesObj.ContainsKey(prefix))
|
||||
_availableFilesObj.Remove(prefix);
|
||||
if (_fileProvider.GetDirectoryContents(prefix).Exists) {
|
||||
_availableFilesObj.Add(prefix, _GetAvailableFiles(prefix));
|
||||
}
|
||||
|
||||
AutoDetermineUsed(prefix);
|
||||
}
|
||||
|
||||
public async Task UpdateAvailableFiles(XMLRootDocument doc, string basefilepath, ModelStateDictionary ModelState) {
|
||||
await _setEnabled();
|
||||
if (!UploadEnabled) {
|
||||
ModelState.AddModelError("Error", "The uploading of files is deactivated");
|
||||
return;
|
||||
}
|
||||
|
||||
await _Save(doc, basefilepath, ModelState);
|
||||
if (!ModelState.IsValid) return;
|
||||
|
||||
UpdateAvailableFiles(doc.Prefix);
|
||||
}
|
||||
|
||||
private async Task _Save(XMLRootDocument doc, string basefilepath, ModelStateDictionary ModelState) {
|
||||
var type = doc.Prefix;
|
||||
var directory = Path.Combine(basefilepath, type);
|
||||
if (!Directory.Exists(directory))
|
||||
Directory.CreateDirectory(directory);
|
||||
var path = Path.Combine(directory, doc.FileName);
|
||||
try {
|
||||
using (var targetStream = System.IO.File.Create(path))
|
||||
await doc.Save(targetStream, ModelState);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ModelState.AddModelError("Error", "Speichern der Datei fehlgeschlagen: " + ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
var info = _fileProvider.GetFileInfo(Path.Combine(doc.Prefix, doc.FileName));
|
||||
if (info == null) {
|
||||
ModelState.AddModelError("Error", "Auf die neu erstellte Dtaei konnte nicht zugegriffen werden");
|
||||
return;
|
||||
}
|
||||
doc.SetFile(info);
|
||||
|
||||
UpdateAvailableFiles(type);
|
||||
}
|
||||
|
||||
|
||||
private XMLRootDocument _createXMLRootDocument(IXMLRoot Root, XElement element) {
|
||||
var doc = new XMLRootDocument(this, Root.Prefix, Root.GenerateIdentificationString(element), element);
|
||||
doc.Fields = Root.GenerateFields(doc);
|
||||
@@ -56,4 +139,63 @@ public class XMLService : IXMLService {
|
||||
.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
|
||||
}
|
||||
|
||||
private async Task _setEnabled() {
|
||||
if (await _featureManager.IsEnabledAsync(HaWeb.Features.UploadService))
|
||||
UploadEnabled = true;
|
||||
if (await _featureManager.IsEnabledAsync(HaWeb.Features.UpdateService))
|
||||
UpdateEnabled = true;
|
||||
}
|
||||
|
||||
private Dictionary<string, List<XMLRootDocument>?>? _GetAvailableFiles() {
|
||||
if (_Roots == null) return null;
|
||||
Dictionary<string, List<XMLRootDocument>?>? res = null;
|
||||
var dirs = _fileProvider.GetDirectoryContents(string.Empty).Where(x => x.IsDirectory);
|
||||
foreach(var dir in dirs) {
|
||||
if(_Roots.ContainsKey(dir.Name)) {
|
||||
if (res == null) res = new Dictionary<string, List<XMLRootDocument>?>();
|
||||
res.Add(dir.Name, _GetAvailableFiles(dir.Name));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private List<XMLRootDocument>? _GetAvailableFiles(string prefix) {
|
||||
List<XMLRootDocument>? res = null;
|
||||
var files = _fileProvider.GetDirectoryContents(prefix).Where(x => !x.IsDirectory && x.Name.StartsWith(prefix) && x.Name.EndsWith(".xml"));
|
||||
foreach (var file in files) {
|
||||
if (res == null) res = new List<XMLRootDocument>();
|
||||
res.Add(new XMLRootDocument(this, file));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public void AutoDetermineUsed() {
|
||||
if (_availableFilesObj == null) return;
|
||||
foreach (var (prefix, _) in _availableFilesObj)
|
||||
AutoDetermineUsed(prefix);
|
||||
}
|
||||
|
||||
public void AutoDetermineUsed(string prefix) {
|
||||
if (_Roots == null || _availableFilesObj == null) return;
|
||||
_Roots.TryGetValue(prefix, out var root);
|
||||
_availableFilesObj.TryGetValue(prefix, out var files);
|
||||
if (files == null || root == null) return;
|
||||
|
||||
//TODO: Item1
|
||||
var lookup = files.ToLookup(x => x.IdentificationString.Item2);
|
||||
foreach (var idstring in lookup) {
|
||||
var ordered = idstring.OrderBy(x => x.Date);
|
||||
ordered.Last().SetUsed(true);
|
||||
ordered.Take(ordered.Count() - 1).ToList().ForEach(x => x.SetUsed(false));
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, List<XMLRootDocument>>? GetUsed() {
|
||||
if (_availableFiles == null) return null;
|
||||
return _availableFiles
|
||||
.Where(x => x.Value != null)
|
||||
.Select(x => x.Value!.Where(x => x.Used).ToList())
|
||||
.Where(x => x.Any())
|
||||
.ToDictionary(x => x.First().Prefix);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user