1. Beta-Version mit Korrekturanmerkungen

This commit is contained in:
Simon Martens
2023-05-11 17:15:04 +02:00
parent 0ef63bfde4
commit fdaffb2f91
20 changed files with 240 additions and 46 deletions

View File

@@ -275,11 +275,11 @@ public class APIController : Controller {
[HttpPost] [HttpPost]
[Route("API/SetUsedHamann")] [Route("API/SetInProduction")]
[DisableFormValueModelBinding] [DisableFormValueModelBinding]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
[FeatureGate(Features.UploadService, Features.AdminService)] [FeatureGate(Features.UploadService, Features.AdminService)]
public async Task<IActionResult> SetUsedHamann() { public async Task<IActionResult> SetInProduction() {
var hF = _xmlProvider.GetHamannFiles(); var hF = _xmlProvider.GetHamannFiles();
if (hF == null) { if (hF == null) {
ModelState.AddModelError("Error", "There are no Hamman.xml files available."); ModelState.AddModelError("Error", "There are no Hamman.xml files available.");
@@ -354,12 +354,11 @@ public class APIController : Controller {
[HttpPost] [HttpPost]
[Route("API/SetStartEndYear")] [Route("API/SetYearSetting")]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
[FeatureGate(Features.UploadService, Features.AdminService)] [FeatureGate(Features.UploadService, Features.AdminService)]
public async Task<IActionResult>? SetStartEndYear(StartEndYear startendyear) { public async Task<IActionResult>? SetEndYear(YearSetting startendyear) {
if (startendyear.StartYear > startendyear.EndYear) return BadRequest(); _lib.SetEndYear(startendyear.EndYear);
_lib.SetStartEndYear(startendyear.StartYear, startendyear.EndYear);
return Created("/", "");; return Created("/", "");;
} }
} }

View File

@@ -44,8 +44,7 @@ public class HaDocumentWrapper : IHaDocumentWrappper {
public int GetEndYear() => EndYear; public int GetEndYear() => EndYear;
public void SetStartEndYear(int start, int end) { public void SetEndYear(int end) {
this.StartYear = start;
this.EndYear = end; this.EndYear = end;
SetLibrary(_filepath); SetLibrary(_filepath);
} }

View File

@@ -11,5 +11,5 @@ public interface IHaDocumentWrappper {
public int GetStartYear(); public int GetStartYear();
public int GetEndYear(); public int GetEndYear();
public void SetStartEndYear(int start, int end); public void SetEndYear(int end);
} }

View File

@@ -3,6 +3,7 @@ using Microsoft.Extensions.FileProviders;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using HaWeb.Models; using HaWeb.Models;
using HaWeb.XMLParser; using HaWeb.XMLParser;
using HaWeb.XMLTests;
using System.Xml.Linq; using System.Xml.Linq;
// XMLProvider provides a wrapper around the available XML data on a FILE basis // XMLProvider provides a wrapper around the available XML data on a FILE basis
@@ -13,7 +14,7 @@ public class XMLProvider : IXMLProvider {
private List<IFileInfo>? _HamannFiles; private List<IFileInfo>? _HamannFiles;
private Stack<IFileInfo>? _InProduction; private Stack<IFileInfo>? _InProduction;
public XMLProvider(IFileProvider provider, IXMLService xmlservice) { public XMLProvider(IFileProvider provider, IXMLService xmlservice, IXMLTestService testService) {
_fileProvider = provider; _fileProvider = provider;
_Roots = xmlservice.GetRootsDictionary(); _Roots = xmlservice.GetRootsDictionary();
_Files = _ScanFiles(); _Files = _ScanFiles();
@@ -23,6 +24,8 @@ public class XMLProvider : IXMLProvider {
foreach (var category in _Files) foreach (var category in _Files)
if (category.Value != null) if (category.Value != null)
xmlservice.AutoUse(category.Value); xmlservice.AutoUse(category.Value);
testService.Test();
} }
public List<IFileInfo>? GetHamannFiles() => this._HamannFiles; public List<IFileInfo>? GetHamannFiles() => this._HamannFiles;
@@ -67,7 +70,7 @@ public class XMLProvider : IXMLProvider {
var info = _fileProvider.GetFileInfo(Path.Combine(doc.Prefix, doc.FileName)); var info = _fileProvider.GetFileInfo(Path.Combine(doc.Prefix, doc.FileName));
if (info == null) { if (info == null) {
ModelState.AddModelError("Error", "Auf die neu erstellte Dtaei konnte nicht zugegriffen werden."); ModelState.AddModelError("Error", "Auf die neu erstellte Datei konnte nicht zugegriffen werden.");
return; return;
} }

View File

@@ -1,9 +1,6 @@
namespace HaWeb.Models; namespace HaWeb.Models;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
public class StartEndYear { public class YearSetting {
[Required]
public int StartYear { get; set; }
[Required] [Required]
public int EndYear { get; set; } public int EndYear { get; set; }
} }

View File

@@ -10,7 +10,6 @@ public class XMLRootDocument {
private XElement? _Element; private XElement? _Element;
private string? _filename; private string? _filename;
private IFileInfo? _file; private IFileInfo? _file;
private StringBuilder? _log; private StringBuilder? _log;
[JsonIgnore] [JsonIgnore]
@@ -31,9 +30,7 @@ public class XMLRootDocument {
} }
set { set {
_file = value; _file = value;
// After saving, we don't need to save the ELement anymore, it can get read in if it's used. _Element = null;
// We do this to prevent memory hogging. TODO: MAKE IT MORE EFFICIENT, EG ALL USED FILES HAVE SET ELEMENTS OR SO
// if (value != null) _Element = null;
} } } }
public string Prefix { get; private set; } public string Prefix { get; private set; }
public DateTime Date { get; private set; } public DateTime Date { get; private set; }
@@ -99,9 +96,9 @@ public class XMLRootDocument {
public void Log(string msg) { public void Log(string msg) {
if (_log == null) _log = new StringBuilder(); if (_log == null) _log = new StringBuilder();
var prefix = DateTime.Now.ToString() + " "; var prefix = DateTime.Now.ToShortTimeString() + " ";
if (File != null) prefix += File.Name + ": "; if (File != null) prefix += File.Name + ": ";
_log.Append("<br>" + prefix + msg); _log.AppendLine(prefix + msg);
} }
public void ResetLog() { public void ResetLog() {

View File

@@ -35,6 +35,12 @@ There is a chance you need to set the Environment Variable to 'Development' in W
Recommended vscode plugins include the XML Tools, c#, Tailwind CSS IntelliSense & TODO Tree. Recommended vscode plugins include the XML Tools, c#, Tailwind CSS IntelliSense & TODO Tree.
## Release
To build a release version for the current server, run:
`dotnet publish -a x64 --os win -c Release`
## Redesign der Hamann-Vebseite, drittes Update ## Redesign der Hamann-Vebseite, drittes Update
Veränderungenen in der Funktionalität für den Benutzer Veränderungenen in der Funktionalität für den Benutzer
- Behutsames Redesign der Webseite: - Behutsames Redesign der Webseite:

View File

@@ -0,0 +1,16 @@
namespace HaWeb.Settings.NodeRules;
using System.Collections.Generic;
using HaWeb.XMLTests;
public class AppNode : INodeRule
{
public string Name => "app";
public string XPath => "//app";
public string[]? Attributes { get; } = { "ref" };
public string? uniquenessAttribute => null;
public List<(string, string, string)>? References { get; } = new List<(string, string, string)>()
{
("ref", "//appDef", "index")
};
}

View File

@@ -0,0 +1,17 @@
namespace HaWeb.Settings.NodeRules;
using System.Collections.Generic;
using HaWeb.XMLTests;
public class LinkNode : INodeRule
{
public string Name => "link";
public string XPath => "//link";
public string[]? Attributes { get; } = null;
public string? uniquenessAttribute => null;
public List<(string, string, string)>? References { get; } = new List<(string, string, string)>()
{
("ref", "//kommentar", "id"),
("subref", "//subsection", "id")
};
}

View File

@@ -0,0 +1,40 @@
using HaWeb.Models;
using System.Xml.Linq;
using HaWeb.XMLTests;
namespace HaWeb.Settings.NodeRules;
public class StructureCollection : ICollectionRule {
public string Name { get; } = "structure";
public string[] Bases { get; } = { "//letterText", "//letterTradition" };
public string[] Backlinks { get; } = { "//intlink", "//marginal" };
public IEnumerable<(string, XElement, XMLRootDocument)> GenerateIdentificationStrings(IEnumerable<(XElement, XMLRootDocument)> list) {
foreach (var e in list) {
var id = e.Item1.Name == "letterText" ? e.Item1.Attribute("index")!.Value : e.Item1.Attribute("ref")!.Value;
var currpage = String.Empty;
var currline = String.Empty;
foreach (var el in e.Item1.Descendants()) {
if (el.Name == "page" && el.Attribute("index") != null) currpage = el.Attribute("index")!.Value;
if (el.Name == "line" && el.Attribute("index") != null) {
currline = el.Attribute("index")!.Value;
yield return (
id + "-" + currpage + "-" + currline,
e.Item1,
e.Item2);
}
}
}
}
public IEnumerable<(string, XElement, XMLRootDocument, bool)> GenerateBacklinkString(IEnumerable<(XElement, XMLRootDocument)> list) {
foreach (var e in list) {
var letter = e.Item1.Attribute("letter") != null ? e.Item1.Attribute("letter")!.Value : "NA";
var page = e.Item1.Attribute("page") != null ? e.Item1.Attribute("page")!.Value : "NA";
var line = e.Item1.Attribute("line") != null ? e.Item1.Attribute("line")!.Value : "NA";
var partialmatch = e.Item1.Name == "marginal" ? false : true;
yield return (
letter + "-" + page + "-" + line,
e.Item1,
e.Item2,
partialmatch);
}
}
}

View File

@@ -70,14 +70,12 @@
</div> </div>
@if (Model.UsedFiles != null && Model.Prefix != null && Model.UsedFiles.ContainsKey(Model.Prefix)) { @if (Model.UsedFiles != null && Model.Prefix != null && Model.UsedFiles.ContainsKey(Model.Prefix)) {
<div class="ha-crossfilechecking text-sm"> <textarea class="py-2 px-3 mx-8 mb-8 shadow-lg font-mono text-sm border rounded" id="errormessagebox" name="errormessagebox" rows="25" cols="90" readonly>
@foreach (var f in Model.UsedFiles[Model.Prefix]) @foreach (var f in Model.UsedFiles[Model.Prefix])
{ {
<div> @f.Messages
@Html.Raw(f.Messages)
</div>
} }
</div> </textarea>
} }
} }
@@ -89,21 +87,17 @@
</div> </div>
<div class="ha-hamannfilechooser"> <div class="ha-hamannfilechooser">
@await Html.PartialAsync("/Views/Shared/_FileListForm.cshtml", (Model.HamannFiles, "Verfügbare Hamann-Dateien", "API", "SetUsedHamann", string.Empty, "/Download/XML/", false)) @await Html.PartialAsync("/Views/Shared/_FileListForm.cshtml", (Model.HamannFiles, "Verfügbare Hamann-Dateien", "API", "SetInProduction", string.Empty, "/Download/XML/", false))
</div> </div>
<form id="seatstartendyearform" enctype="application/x-www-form-urlencoded" asp-controller="API" asp-action="SetStartEndYear"> <form class="ha-setendyearform" id="ha-setendyearform" enctype="application/x-www-form-urlencoded" asp-controller="API" asp-action="SetEndYear" onsubmit="YEARSUBMIT(this);return false;">
<select name="StartYear" id=""> Verfügbare Jahre: bis&nbsp;
@foreach (var y in Model.AvailableYears) {
<option>@y</option>
}
</select>
<select name="EndYear" id=""> <select name="EndYear" id="">
@foreach (var y in Model.AvailableYears) { @foreach (var y in Model.AvailableYears) {
<option>@y</option> <option>@y</option>
} }
</select> </select>
<button type="submit">Setzen</button> <button id="ha-setendyearbutton" class="ha-setendyearbutton" type="submit">Setzen</button>
</form> </form>
} }

View File

@@ -43,7 +43,7 @@
<output id ="ha-filelistoutput"></output> <output id ="ha-filelistoutput"></output>
<button type="submit" class="ha-filelistbutton" id="ha-filelistbutton" > <button type="submit" class="ha-filelistbutton" id="ha-filelistbutton" >
Laden Laden
<div class="ha-lds-ellipsis-load" id="ha-lds-ellipsis-load"><div></div><div></div><div></div><div></div></div> <div class="ha-lds-ellipsis-load" id="ha-lds-ellipsis-load"></div>
</button> </button>
</form> </form>
} }

View File

@@ -20,8 +20,8 @@ public class XMLService : IXMLService {
private Stack<Dictionary<string, FileList?>>? _InProduction; private Stack<Dictionary<string, FileList?>>? _InProduction;
private Dictionary<string, ItemsCollection> _collectedProduction; private Dictionary<string, ItemsCollection>? _collectedProduction;
private Dictionary<string, ItemsCollection> _collectedUsed; private Dictionary<string, ItemsCollection>? _collectedUsed;
public XMLService() { public XMLService() {
// Getting all classes which implement IXMLRoot for possible document endpoints // Getting all classes which implement IXMLRoot for possible document endpoints

View File

@@ -0,0 +1,11 @@
namespace HaWeb.XMLTests;
using HaWeb.Models;
using System.Xml.Linq;
public interface ICollectionRule {
public string Name { get; }
public string[] Bases { get; }
public string[] Backlinks { get; }
public IEnumerable<(string, XElement, XMLRootDocument)> GenerateIdentificationStrings(IEnumerable<(XElement, XMLRootDocument)> List);
public IEnumerable<(string, XElement, XMLRootDocument, bool)> GenerateBacklinkString(IEnumerable<(XElement, XMLRootDocument)> List);
}

View File

@@ -3,6 +3,7 @@ namespace HaWeb.XMLTests;
public interface IXMLTestService { public interface IXMLTestService {
public Dictionary<string, INodeRule>? Ruleset { get; } public Dictionary<string, INodeRule>? Ruleset { get; }
public Dictionary<string, ICollectionRule>? CollectionRuleset { get; }
public void Test(); public void Test();
} }

View File

@@ -4,6 +4,7 @@ using HaWeb.XMLParser;
public class XMLTestService : IXMLTestService { public class XMLTestService : IXMLTestService {
private IXMLService _XMLService; private IXMLService _XMLService;
public Dictionary<string, INodeRule>? Ruleset { get; private set; } public Dictionary<string, INodeRule>? Ruleset { get; private set; }
public Dictionary<string, ICollectionRule>? CollectionRuleset { get; private set; }
public XMLTestService(IXMLService xmlService) { public XMLTestService(IXMLService xmlService) {
_XMLService = xmlService; _XMLService = xmlService;
@@ -13,6 +14,13 @@ public class XMLTestService : IXMLTestService {
var instance = (INodeRule)Activator.CreateInstance(x)!; var instance = (INodeRule)Activator.CreateInstance(x)!;
if (instance != null) this.Ruleset.Add(instance.Name, instance); if (instance != null) this.Ruleset.Add(instance.Name, instance);
}); });
var collectionruleset = _GetAllTypesThatImplementInterface<ICollectionRule>().ToList();
collectionruleset.ForEach( x => {
if (this.CollectionRuleset == null) this.CollectionRuleset = new Dictionary<string, ICollectionRule>();
var instance = (ICollectionRule)Activator.CreateInstance(x)!;
if (instance != null) this.CollectionRuleset.Add(instance.Name, instance);
});
} }
public void Test() { public void Test() {

View File

@@ -7,11 +7,14 @@ using System.Xml.XPath;
public class XMLTester { public class XMLTester {
private Dictionary<string, INodeRule>? _Ruleset; private Dictionary<string, INodeRule>? _Ruleset;
private Dictionary<string, ICollectionRule>? _CollectionRuleset;
private List<XMLRootDocument>? _Documents; private List<XMLRootDocument>? _Documents;
private Dictionary<string, HashSet<string>>? _IDs; private Dictionary<string, HashSet<string>>? _IDs;
private Dictionary<string, HashSet<string>>? _CollectionIDs;
private Dictionary<string, List<(XElement, XMLRootDocument)>?> _XPathEvaluated; private Dictionary<string, List<(XElement, XMLRootDocument)>?> _XPathEvaluated;
public XMLTester (IXMLTestService testService, Dictionary<string, Models.FileList?>? filelists) { public XMLTester (IXMLTestService testService, Dictionary<string, Models.FileList?>? filelists) {
_Ruleset = testService.Ruleset; _Ruleset = testService.Ruleset;
_CollectionRuleset = testService.CollectionRuleset;
if (filelists != null) { if (filelists != null) {
foreach (var fl in filelists) { foreach (var fl in filelists) {
if (fl.Value != null) { if (fl.Value != null) {
@@ -30,6 +33,64 @@ public class XMLTester {
foreach (var rule in _Ruleset) { foreach (var rule in _Ruleset) {
buildIDs(rule.Value); buildIDs(rule.Value);
checkRequiredAttributes(rule.Value); checkRequiredAttributes(rule.Value);
checkReferences(rule.Value);
}
if (_CollectionRuleset == null) return;
_CollectionIDs = new Dictionary<string, HashSet<string>>();
foreach (var collectionrule in _CollectionRuleset) {
buildIDs(collectionrule.Value);
checkReferences(collectionrule.Value);
}
}
private void checkReferences(INodeRule rule) {
if (rule.References == null || !rule.References.Any()) return;
var elements = GetEvaluateXPath(rule.XPath);
if (elements != null && elements.Any()) {
foreach (var e in elements) {
foreach (var r in rule.References) {
var hasattr = checkAttribute(e.Item1, r.LinkAttribute, e.Item2, false);
var keyname = r.RemoteElement + "-" + r.RemoteAttribute;
if (_IDs != null && _IDs.ContainsKey(keyname) && hasattr) {
var val = e.Item1.Attribute(r.LinkAttribute)!.Value;
if (!_IDs[keyname].Contains(val)) {
e.Item2.Log(generateLogMessage(e.Item1) + "Verlinktes Element " + val + " nicht gefunden.");
}
}
}
}
}
}
private void checkReferences(ICollectionRule rule) {
if (rule.Backlinks == null || !rule.Backlinks.Any() || !_CollectionIDs.ContainsKey(rule.Name)) return;
foreach (var bl in rule.Backlinks) {
var elemens = GetEvaluateXPath(bl);
if (elemens != null && elemens.Any()) {
foreach(var r in rule.GenerateBacklinkString(elemens)) {
if (!r.Item4 && !_CollectionIDs[rule.Name].Contains(r.Item1)) {
r.Item3.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden.");
}
if (r.Item4) {
var coll = _CollectionIDs[rule.Name];
var items = r.Item1.Split('-');
var searchterm = items[0];
var found = coll.Where(x => x.StartsWith(searchterm));
if (items[0] == "NA" || found == null || !found.Any()) {
r.Item3.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden.");
} else {
for (var i = 1; i < items.Length; i++) {
if (items[i] == "NA") break;
else {
searchterm = searchterm + "-" + items[i];
found = found.Where(x => x.StartsWith(searchterm));
if (found == null || !found.Any())
r.Item3.Log(generateLogMessage(r.Item2) + "Verlinktes Element " + r.Item1 + " nicht gefunden.");
}
}
}
}
}
}
} }
} }
@@ -47,17 +108,34 @@ public class XMLTester {
private void buildIDs(INodeRule rule) { private void buildIDs(INodeRule rule) {
if (!String.IsNullOrWhiteSpace(rule.uniquenessAttribute)) { if (!String.IsNullOrWhiteSpace(rule.uniquenessAttribute)) {
checkUniqueness(rule.Name, rule.XPath, rule.uniquenessAttribute); checkUniqueness(rule.XPath, rule.uniquenessAttribute);
} }
if (rule.References != null && rule.References.Any()) { if (rule.References != null && rule.References.Any()) {
foreach (var reference in rule.References) { foreach (var reference in rule.References) {
checkUniqueness(rule.Name, reference.RemoteElement, reference.RemoteAttribute); checkUniqueness(reference.RemoteElement, reference.RemoteAttribute);
} }
} }
} }
private void checkUniqueness(string name, string xpathelement, string attribute) { private void buildIDs(ICollectionRule rule) {
if (_Documents == null || _IDs == null || _IDs.ContainsKey(name)) return; if (rule.Bases != null && rule.Bases.Any()) {
var hs = new HashSet<string>();
foreach (var b in rule.Bases) {
var elemens = GetEvaluateXPath(b);
if (elemens != null && elemens.Any()) {
foreach (var r in rule.GenerateIdentificationStrings(elemens)) {
if (!hs.Add(r.Item1)) {
r.Item3.Log(generateLogMessage(r.Item2) + "Brief-Seite-Zeile " + r.Item1 + " mehrdeutig.");
}
}
}
}
_CollectionIDs!.TryAdd(rule.Name, hs);
}
}
private void checkUniqueness(string xpathelement, string attribute) {
if (_Documents == null || _IDs == null || _IDs.ContainsKey(xpathelement + "-" + attribute)) return;
var hs = new HashSet<string>(); var hs = new HashSet<string>();
var elements = GetEvaluateXPath(xpathelement); var elements = GetEvaluateXPath(xpathelement);
if (elements != null) if (elements != null)
@@ -68,12 +146,12 @@ public class XMLTester {
} }
} }
} }
_IDs.TryAdd(name, hs); _IDs.TryAdd(xpathelement + "-" + attribute, hs);
} }
private bool checkAttribute(XElement element, string attributename, XMLRootDocument doc) { private bool checkAttribute(XElement element, string attributename, XMLRootDocument doc, bool log = true) {
if (!element.HasAttributes || element.Attribute(attributename) == null) { if (!element.HasAttributes || element.Attribute(attributename) == null) {
doc.Log(generateLogMessage(element) + "Attribut " + attributename + " fehlt."); if (log) doc.Log(generateLogMessage(element) + "Attribut " + attributename + " fehlt.");
return false; return false;
} }
return true; return true;

File diff suppressed because one or more lines are too long

View File

@@ -108,7 +108,7 @@
} }
.ha-filesheader { .ha-filesheader {
@apply mb-8 @apply mb-4
} }
.ha-availablefileslist { .ha-availablefileslist {
@@ -140,6 +140,14 @@
@apply px-16 pb-16 @apply px-16 pb-16
} }
.ha-uploadcontainer .ha-setendyearform {
@apply px-16 pb-16 float-right
}
.ha-uploadcontainer .ha-setendyearform .ha-setendyearbutton {
@apply mt-4 ml-6 rounded-md px-3 border-2 border-blue-600 hover:border-2 hover:shadow active:shadow-inner hover:border-blue-800 cursor-pointer
}
/* Classes for FileList Component */ /* Classes for FileList Component */
.ha-filelistfieldset { .ha-filelistfieldset {

View File

@@ -27,4 +27,24 @@ const USESubmit = async function (oFormElement, file = null) {
document.getElementById("ha-lds-ellipsis-load").style.display = "none"; document.getElementById("ha-lds-ellipsis-load").style.display = "none";
document.getElementById("ha-filelistoutput").textContent = e; document.getElementById("ha-filelistoutput").textContent = e;
}) })
}
const YEARSUBMIT = async function (oFormElement, file = null) {
let fd = new FormData(oFormElement);
document.getElementById("ha-setendyearbutton").style.pointerEvents = "none";
await fetch(oFormElement.action, {
method: 'POST',
headers: {
'RequestVerificationToken': getCookie('RequestVerificationToken')
},
body: fd
})
.then(response => response.json())
.then(json => {
document.getElementById("ha-setendyearbutton").style.pointerEvents = "auto";
location.reload();
})
.catch ((e) => {
document.getElementById("ha-setendyearbutton").style.pointerEvents = "auto";
})
} }