Seperation of concerns: Seperated used File Management form Overall FIle Management

This commit is contained in:
schnulller
2022-06-05 15:18:32 +02:00
parent abc27c6d04
commit c95059b2e8
22 changed files with 211 additions and 186 deletions

View File

@@ -1,6 +1,7 @@
namespace HaWeb.XMLParser;
using System.Xml.Linq;
using System.Xml.XPath;
using HaWeb.Models;
public interface IXMLRoot {
// Name of the IXMLRoot

View File

@@ -1,12 +1,15 @@
namespace HaWeb.XMLParser;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using HaWeb.Models;
public interface IXMLService {
public IXMLRoot? GetRoot(string name);
public List<IXMLRoot>? GetRoots();
public List<IXMLRoot>? GetRootsList();
public Dictionary<string, IXMLRoot>? GetRootsDictionary();
public Task<List<XMLRootDocument>?> ProbeHamannFile(XDocument document, ModelStateDictionary ModelState);
public Task UpdateAvailableFiles(XMLRootDocument doc, string basefilepath, ModelStateDictionary ModelState);
public Dictionary<string, List<XMLRootDocument>> GetUsed();
public List<XMLRootDocument>? GetAvailableFiles(string prefix);
public Dictionary<string, FileList?>? GetUsedDictionary();
public void Use(XMLRootDocument doc);
public void AutoUse(string prefix);
public void AutoUse(FileList filelist);
}

View File

@@ -1,133 +0,0 @@
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 IXMLService _xmlService;
[JsonIgnore]
public XElement Root {
get {
if (_Element == null) {
_Element = _GetElement();
}
return _Element;
}
}
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, IFileInfo file) {
_xmlService = xmlService;
SetFile(file);
}
// Entry point for XML upload reading
public XMLRootDocument(IXMLService xmlService, string prefix, (string?, string?) idString, XElement element) {
_xmlService = xmlService;
Prefix = prefix;
IdentificationString = idString;
Date = DateTime.Today;
_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)) {
var hash = IdentificationString.Item1.GetHashCode().ToString("X8");
filename += hash + "_";
}
if (!String.IsNullOrWhiteSpace(IdentificationString.Item2)) filename += _removeInvalidChars(IdentificationString.Item2) + "_";
filename += _removeInvalidChars(Date.Year.ToString() + "-" + Date.Month.ToString() + "-" + Date.Day.ToString());
return filename + ".xml";
}
private string _removeInvalidChars(string? s) {
if (String.IsNullOrWhiteSpace(s)) return "";
foreach (var c in Path.GetInvalidFileNameChars()) {
s = s.Replace(c, '-');
}
s = s.Replace('_', '-');
return s;
}
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: " + File.PhysicalPath + "Vom Prefix: " + Prefix);
XDocument? doc = null;
try {
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: " + File.PhysicalPath);
var element = root.IsTypeOf(doc.Root);
if (element == null || !element.Any())
throw new Exception("Kein gültiges Hamann-Dokument: " + File.PhysicalPath + "Vom Prefix: " + Prefix);
return element.First();
}
public async Task Save(Stream stream, ModelStateDictionary state) {
var root = _xmlService.GetRoot(Prefix);
if (root == null) {
state.AddModelError("Error", "No corresponding Root Element found.");
return;
}
await root.CreateHamannDocument(Root).SaveAsync(stream, SaveOptions.DisableFormatting, new CancellationToken());
}
}

View File

@@ -1,35 +1,14 @@
namespace HaWeb.XMLParser;
using HaWeb.Settings.XMLRoots;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.FileProviders;
using Microsoft.FeatureManagement;
using HaWeb.Models;
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, FileList?>? _Used;
private Dictionary<string, IXMLRoot>? _Roots;
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
public XMLService() {
// Getting all classes which implement IXMLRoot for possible document endpoints
var types = _GetAllTypesThatImplementInterface<IXMLRoot>().ToList();
types.ForEach( x => {
if (this._Roots == null) this._Roots = new Dictionary<string, IXMLRoot>();
@@ -42,11 +21,14 @@ public class XMLService : IXMLService {
}
public IXMLRoot? GetRoot(string name) {
if (_Roots == null) return null;
_Roots.TryGetValue(name, out var root);
return root;
}
public List<IXMLRoot>? GetRoots() => this._Roots == null ? null : this._Roots.Values.ToList();
public List<IXMLRoot>? GetRootsList() => this._Roots == null ? null : this._Roots.Values.ToList();
public Dictionary<string, IXMLRoot>? GetRootsDictionary() => this._Roots == null ? null : this._Roots;
public async Task<List<XMLRootDocument>?> ProbeHamannFile(XDocument document, ModelStateDictionary ModelState) {
if (document.Root!.Name != "opus") {
@@ -69,72 +51,43 @@ public class XMLService : IXMLService {
return res;
}
public void UpdateAvailableFiles() {
_availableFilesObj = _GetAvailableFiles();
public Dictionary<string, FileList?>? GetUsedDictionary()
=> this._Used;
// Adds a document and sets it to used
public void Use(XMLRootDocument doc) {
if (_Used == null) _Used = new Dictionary<string, FileList?>();
if (!_Used.ContainsKey(doc.Prefix)) _Used.Add(doc.Prefix, new FileList(doc.XMLRoot));
_Used[doc.Prefix]!.Add(doc);
}
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);
// Performs detection of using on the specified document type
public void AutoUse(string prefix) {
if (_Used == null || !_Used.ContainsKey(prefix)) return;
AutoUse(_Used[prefix]!);
}
public List<XMLRootDocument>? GetAvailableFiles(string prefix) {
if (_Roots == null || _availableFiles == null) return null;
if(!_Roots.ContainsKey(prefix) || !_availableFiles.ContainsKey(prefix)) return null;
// Performs detection of using given a list of files
public void AutoUse(FileList filelist) {
FileList? res = null;
var list = filelist.GetFileList();
var prefix = filelist.XMLRoot.Prefix;
return _availableFiles[prefix];
if (list == null) return;
if (_Used != null && _Used.ContainsKey(prefix)) _Used.Remove(prefix);
// TODO: Item1
var lookup = list.ToLookup(x => x.IdentificationString.Item2);
foreach (var idstring in lookup) {
var ordered = idstring.OrderBy(x => x.Date);
if (res == null) res = new FileList(filelist.XMLRoot);
Use(ordered.Last());
}
}
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);
var doc = new XMLRootDocument(Root, Root.Prefix, Root.GenerateIdentificationString(element), element);
doc.Fields = Root.GenerateFields(doc);
return doc;
}
@@ -145,64 +98,4 @@ public class XMLService : IXMLService {
.GetTypes()
.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);
}
}