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

View File

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

View File

@@ -11,5 +11,5 @@ public interface IHaDocumentWrappper {
public int GetStartYear();
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 HaWeb.Models;
using HaWeb.XMLParser;
using HaWeb.XMLTests;
using System.Xml.Linq;
// 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 Stack<IFileInfo>? _InProduction;
public XMLProvider(IFileProvider provider, IXMLService xmlservice) {
public XMLProvider(IFileProvider provider, IXMLService xmlservice, IXMLTestService testService) {
_fileProvider = provider;
_Roots = xmlservice.GetRootsDictionary();
_Files = _ScanFiles();
@@ -23,6 +24,8 @@ public class XMLProvider : IXMLProvider {
foreach (var category in _Files)
if (category.Value != null)
xmlservice.AutoUse(category.Value);
testService.Test();
}
public List<IFileInfo>? GetHamannFiles() => this._HamannFiles;
@@ -67,7 +70,7 @@ public class XMLProvider : IXMLProvider {
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.");
ModelState.AddModelError("Error", "Auf die neu erstellte Datei konnte nicht zugegriffen werden.");
return;
}

View File

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

View File

@@ -10,7 +10,6 @@ public class XMLRootDocument {
private XElement? _Element;
private string? _filename;
private IFileInfo? _file;
private StringBuilder? _log;
[JsonIgnore]
@@ -31,9 +30,7 @@ public class XMLRootDocument {
}
set {
_file = value;
// After saving, we don't need to save the ELement anymore, it can get read in if it's used.
// 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;
_Element = null;
} }
public string Prefix { get; private set; }
public DateTime Date { get; private set; }
@@ -99,9 +96,9 @@ public class XMLRootDocument {
public void Log(string msg) {
if (_log == null) _log = new StringBuilder();
var prefix = DateTime.Now.ToString() + " ";
var prefix = DateTime.Now.ToShortTimeString() + " ";
if (File != null) prefix += File.Name + ": ";
_log.Append("<br>" + prefix + msg);
_log.AppendLine(prefix + msg);
}
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.
## 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
Veränderungenen in der Funktionalität für den Benutzer
- 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>
@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])
{
<div>
@Html.Raw(f.Messages)
</div>
@f.Messages
}
</div>
</textarea>
}
}
@@ -89,21 +87,17 @@
</div>
<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>
<form id="seatstartendyearform" enctype="application/x-www-form-urlencoded" asp-controller="API" asp-action="SetStartEndYear">
<select name="StartYear" id="">
@foreach (var y in Model.AvailableYears) {
<option>@y</option>
}
</select>
<form class="ha-setendyearform" id="ha-setendyearform" enctype="application/x-www-form-urlencoded" asp-controller="API" asp-action="SetEndYear" onsubmit="YEARSUBMIT(this);return false;">
Verfügbare Jahre: bis&nbsp;
<select name="EndYear" id="">
@foreach (var y in Model.AvailableYears) {
<option>@y</option>
}
</select>
<button type="submit">Setzen</button>
<button id="ha-setendyearbutton" class="ha-setendyearbutton" type="submit">Setzen</button>
</form>
}

View File

@@ -43,7 +43,7 @@
<output id ="ha-filelistoutput"></output>
<button type="submit" class="ha-filelistbutton" id="ha-filelistbutton" >
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>
</form>
}

View File

@@ -20,8 +20,8 @@ public class XMLService : IXMLService {
private Stack<Dictionary<string, FileList?>>? _InProduction;
private Dictionary<string, ItemsCollection> _collectedProduction;
private Dictionary<string, ItemsCollection> _collectedUsed;
private Dictionary<string, ItemsCollection>? _collectedProduction;
private Dictionary<string, ItemsCollection>? _collectedUsed;
public XMLService() {
// 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 Dictionary<string, INodeRule>? Ruleset { get; }
public Dictionary<string, ICollectionRule>? CollectionRuleset { get; }
public void Test();
}

View File

@@ -4,6 +4,7 @@ using HaWeb.XMLParser;
public class XMLTestService : IXMLTestService {
private IXMLService _XMLService;
public Dictionary<string, INodeRule>? Ruleset { get; private set; }
public Dictionary<string, ICollectionRule>? CollectionRuleset { get; private set; }
public XMLTestService(IXMLService xmlService) {
_XMLService = xmlService;
@@ -13,6 +14,13 @@ public class XMLTestService : IXMLTestService {
var instance = (INodeRule)Activator.CreateInstance(x)!;
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() {

View File

@@ -7,11 +7,14 @@ using System.Xml.XPath;
public class XMLTester {
private Dictionary<string, INodeRule>? _Ruleset;
private Dictionary<string, ICollectionRule>? _CollectionRuleset;
private List<XMLRootDocument>? _Documents;
private Dictionary<string, HashSet<string>>? _IDs;
private Dictionary<string, HashSet<string>>? _CollectionIDs;
private Dictionary<string, List<(XElement, XMLRootDocument)>?> _XPathEvaluated;
public XMLTester (IXMLTestService testService, Dictionary<string, Models.FileList?>? filelists) {
_Ruleset = testService.Ruleset;
_CollectionRuleset = testService.CollectionRuleset;
if (filelists != null) {
foreach (var fl in filelists) {
if (fl.Value != null) {
@@ -30,6 +33,64 @@ public class XMLTester {
foreach (var rule in _Ruleset) {
buildIDs(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) {
if (!String.IsNullOrWhiteSpace(rule.uniquenessAttribute)) {
checkUniqueness(rule.Name, rule.XPath, rule.uniquenessAttribute);
checkUniqueness(rule.XPath, rule.uniquenessAttribute);
}
if (rule.References != null && rule.References.Any()) {
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) {
if (_Documents == null || _IDs == null || _IDs.ContainsKey(name)) return;
private void buildIDs(ICollectionRule rule) {
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 elements = GetEvaluateXPath(xpathelement);
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) {
doc.Log(generateLogMessage(element) + "Attribut " + attributename + " fehlt.");
if (log) doc.Log(generateLogMessage(element) + "Attribut " + attributename + " fehlt.");
return false;
}
return true;

File diff suppressed because one or more lines are too long

View File

@@ -108,7 +108,7 @@
}
.ha-filesheader {
@apply mb-8
@apply mb-4
}
.ha-availablefileslist {
@@ -140,6 +140,14 @@
@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 */
.ha-filelistfieldset {

View File

@@ -28,3 +28,23 @@ const USESubmit = async function (oFormElement, file = null) {
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";
})
}