Creaded Upload Interface; Also added Wrapper around HaDocument to reload the Document

This commit is contained in:
schnulller
2022-06-04 23:18:40 +02:00
parent 37b794ea05
commit 9712574e13
21 changed files with 1043 additions and 268 deletions

View File

@@ -0,0 +1,145 @@
namespace HaWeb.Controllers;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Net.Http.Headers;
using HaWeb.Filters;
using HaWeb.FileHelpers;
using HaWeb.XMLParser;
using System.Text.Json.Serialization;
using System.Text.Json;
using HaDocument.Interfaces;
using HaXMLReader.Interfaces;
using Microsoft.FeatureManagement.Mvc;
using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Http.Features;
// Controlling all the API-Endpoints
public class APIController : Controller {
// DI
private ILibrary _lib;
private IReaderService _readerService;
private readonly long _fileSizeLimit;
private readonly string _targetFilePath;
private readonly IXMLService _xmlService;
// Options
private static readonly string[] _permittedExtensions = { ".xml" };
private static readonly FormOptions _defaultFormOptions = new FormOptions();
public APIController(ILibrary lib, IReaderService readerService, IXMLService xmlService, IConfiguration config) {
_lib = lib;
_readerService = readerService;
_xmlService = xmlService;
_fileSizeLimit = config.GetValue<long>("FileSizeLimit");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
_targetFilePath = config.GetValue<string>("StoredFilePathWindows");
} else {
_targetFilePath = config.GetValue<string>("StoredFilePathLinux");
}
}
[HttpGet]
[Route("API/Syntaxcheck/{id}")]
[DisableFormValueModelBinding]
[ValidateAntiForgeryToken]
[FeatureGate(Features.AdminService)]
public async Task<IActionResult> SyntaxCheck(string id) {
return Ok();
}
//// UPLOAD ////
[HttpPost]
[Route("API/Upload")]
[DisableFormValueModelBinding]
[ValidateAntiForgeryToken]
[FeatureGate(Features.UploadService)]
public async Task<IActionResult> Upload(string? id) {
List<XMLRootDocument>? docs = null;
//// 1. Stage: Check Request format and request spec
// Checks the Content-Type Field (must be multipart + Boundary)
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) {
ModelState.AddModelError("Error", $"Wrong / No Content Type on the Request");
return BadRequest(ModelState);
}
// Divides the multipart document into it's sections and sets up a reader
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
MultipartSection? section = null;
try {
section = await reader.ReadNextSectionAsync();
} catch (Exception ex) {
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
}
while (section != null) {
// Multipart document content disposition header read for a section:
// Starts with boundary, contains field name, content-dispo, filename, content-type
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
if (contentDisposition != null && contentDisposition.Name == "__RequestVerificationToken") {
try {
section = await reader.ReadNextSectionAsync();
} catch (Exception ex) {
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
}
continue;
}
if (hasContentDispositionHeader && contentDisposition != null) {
// Checks if it is a section with content-disposition, name, filename
if (!MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) {
ModelState.AddModelError("Error", $"Wrong Content-Dispostion Headers in Multipart Document");
return BadRequest(ModelState);
}
//// 2. Stage: Check File. Sanity checks on the file on a byte level, extension checking, is it empty etc.
var streamedFileContent = await XMLFileHelpers.ProcessStreamedFile(
section, contentDisposition, ModelState,
_permittedExtensions, _fileSizeLimit);
if (!ModelState.IsValid || streamedFileContent == null)
return BadRequest(ModelState);
//// 3. Stage: Valid XML checking using a simple XDocument.Load()
var xdocument = await XDocumentFileHelper.ProcessStreamedFile(streamedFileContent, ModelState);
if (!ModelState.IsValid || xdocument == null)
return UnprocessableEntity(ModelState);
//// 4. Stage: Is it a Hamann-Document? What kind?
var retdocs = await _xmlService.ProbeHamannFile(xdocument, ModelState);
if (!ModelState.IsValid || retdocs == null || !retdocs.Any())
return UnprocessableEntity(ModelState);
//// 5. Stage: Saving the File(s)
foreach (var doc in retdocs) {
await _xmlService.UpdateAvailableFiles(doc, _targetFilePath, ModelState);
if (!ModelState.IsValid) return StatusCode(500, ModelState);
if (docs == null) docs = new List<XMLRootDocument>();
docs.Add(doc);
}
}
try {
section = await reader.ReadNextSectionAsync();
} catch (Exception ex) {
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
}
}
// 6. Stage: Success! Returning Ok, and redirecting
JsonSerializerOptions options = new() {
ReferenceHandler = ReferenceHandler.Preserve,
Converters = {
new IdentificationStringJSONConverter()
}
};
string json = JsonSerializer.Serialize(docs);
return Created(nameof(UploadController), json);
}
}

View File

@@ -3,13 +3,13 @@ using Microsoft.AspNetCore.Mvc;
using HaDocument.Interfaces;
using HaXMLReader.Interfaces;
using Microsoft.FeatureManagement.Mvc;
using HaWeb.FileHelpers;
public class AdminController : Controller {
// DI
private ILibrary _lib;
private IHaDocumentWrappper _lib;
private IReaderService _readerService;
public AdminController(ILibrary lib, IReaderService readerService) {
public AdminController(IHaDocumentWrappper lib, IReaderService readerService) {
_lib = lib;
_readerService = readerService;
}

View File

@@ -1,6 +1,7 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using HaWeb.Models;
using HaWeb.FileHelpers;
using HaDocument.Interfaces;
using HaXMLReader.Interfaces;
using HaDocument.Models;
@@ -12,10 +13,10 @@ public class Briefecontroller : Controller {
public string? id { get; set; }
// DI
private ILibrary _lib;
private IHaDocumentWrappper _lib;
private IReaderService _readerService;
public Briefecontroller(ILibrary lib, IReaderService readerService) {
public Briefecontroller(IHaDocumentWrappper lib, IReaderService readerService) {
_lib = lib;
_readerService = readerService;
}
@@ -24,25 +25,26 @@ public class Briefecontroller : Controller {
[Route("Briefe/{id?}")]
public IActionResult Index(string? id) {
// Setup settings and variables
var lib = _lib.GetLibrary();
var url = "/Briefe/";
var defaultID = "1";
// Normalisation and Validation, (some) data aquisition
if (id == null) return Redirect(url + defaultID);
this.id = id.ToLower();
var preliminarymeta = _lib.Metas.Where(x => x.Value.Autopsic == this.id);
var preliminarymeta = lib.Metas.Where(x => x.Value.Autopsic == this.id);
if (preliminarymeta == null || !preliminarymeta.Any()) return error404();
// Get all neccessary data
var index = preliminarymeta.First().Key;
var meta = preliminarymeta.First().Value;
var text = _lib.Letters.ContainsKey(index) ? _lib.Letters[index] : null;
var marginals = _lib.MarginalsByLetter.Contains(index) ? _lib.MarginalsByLetter[index] : null;
var tradition = _lib.Traditions.ContainsKey(index) ? _lib.Traditions[index] : null;
var editreasons = _lib.Editreasons.ContainsKey(index) ? _lib.EditreasonsByLetter[index] : null; // TODO: Order
var hands = _lib.Hands.ContainsKey(index) ? _lib.Hands[index] : null;
var nextmeta = meta != _lib.MetasByDate.Last() ? _lib.MetasByDate.ItemRef(_lib.MetasByDate.IndexOf(meta) + 1) : null;
var prevmeta = meta != _lib.MetasByDate.First() ? _lib.MetasByDate.ItemRef(_lib.MetasByDate.IndexOf(meta) - 1) : null;
var text = lib.Letters.ContainsKey(index) ? lib.Letters[index] : null;
var marginals = lib.MarginalsByLetter.Contains(index) ? lib.MarginalsByLetter[index] : null;
var tradition = lib.Traditions.ContainsKey(index) ? lib.Traditions[index] : null;
var editreasons = lib.Editreasons.ContainsKey(index) ? lib.EditreasonsByLetter[index] : null; // TODO: Order
var hands = lib.Hands.ContainsKey(index) ? lib.Hands[index] : null;
var nextmeta = meta != lib.MetasByDate.Last() ? lib.MetasByDate.ItemRef(lib.MetasByDate.IndexOf(meta) + 1) : null;
var prevmeta = meta != lib.MetasByDate.First() ? lib.MetasByDate.ItemRef(lib.MetasByDate.IndexOf(meta) - 1) : null;
// More Settings and variables
ViewData["Title"] = "Brief " + id.ToLower();
@@ -52,17 +54,17 @@ public class Briefecontroller : Controller {
// Model creation
var hasMarginals = false;
if (marginals != null && marginals.Any()) hasMarginals = true;
var model = new BriefeViewModel(this.id, index, generateMetaViewModel(meta, hasMarginals));
if (nextmeta != null) model.MetaData.Next = (generateMetaViewModel(nextmeta, false), url + nextmeta.Autopsic);
if (prevmeta != null) model.MetaData.Prev = (generateMetaViewModel(prevmeta, false), url + prevmeta.Autopsic);
if (hands != null && hands.Any()) model.ParsedHands = HaWeb.HTMLHelpers.LetterHelpers.CreateHands(_lib, hands);
if (editreasons != null && editreasons.Any()) model.ParsedEdits = HaWeb.HTMLHelpers.LetterHelpers.CreateEdits(_lib, _readerService, editreasons);
var model = new BriefeViewModel(this.id, index, generateMetaViewModel(lib, meta, hasMarginals));
if (nextmeta != null) model.MetaData.Next = (generateMetaViewModel(lib, nextmeta, false), url + nextmeta.Autopsic);
if (prevmeta != null) model.MetaData.Prev = (generateMetaViewModel(lib, prevmeta, false), url + prevmeta.Autopsic);
if (hands != null && hands.Any()) model.ParsedHands = HaWeb.HTMLHelpers.LetterHelpers.CreateHands(lib, hands);
if (editreasons != null && editreasons.Any()) model.ParsedEdits = HaWeb.HTMLHelpers.LetterHelpers.CreateEdits(lib, _readerService, editreasons);
if (tradition != null && !String.IsNullOrWhiteSpace(tradition.Element)) {
var parsedTraditions = HaWeb.HTMLHelpers.LetterHelpers.CreateTraditions(_lib, _readerService, marginals, tradition, hands, editreasons);
var parsedTraditions = HaWeb.HTMLHelpers.LetterHelpers.CreateTraditions(lib, _readerService, marginals, tradition, hands, editreasons);
(model.ParsedTradition, model.ParsedMarginals, model.MinWidthTrad) = (parsedTraditions.sb_tradition.ToString(), parsedTraditions.ParsedMarginals, parsedTraditions.minwidth);
}
if (text != null && !String.IsNullOrWhiteSpace(text.Element)) {
var parsedLetter = HaWeb.HTMLHelpers.LetterHelpers.CreateLetter(_lib, _readerService, meta, text, marginals, hands, editreasons);
var parsedLetter = HaWeb.HTMLHelpers.LetterHelpers.CreateLetter(lib, _readerService, meta, text, marginals, hands, editreasons);
(model.ParsedText, model.MinWidth) = (parsedLetter.sb_lettertext.ToString(), parsedLetter.minwidth);
if (model.ParsedMarginals != null && parsedLetter.ParsedMarginals != null) model.ParsedMarginals.AddRange(parsedLetter.ParsedMarginals);
else model.ParsedMarginals = parsedLetter.ParsedMarginals;
@@ -81,9 +83,9 @@ public class Briefecontroller : Controller {
return Redirect("/Error404");
}
private BriefeMetaViewModel generateMetaViewModel(Meta meta, bool hasMarginals) {
var senders = meta.Senders.Select(x => _lib.Persons[x].Name) ?? new List<string>();
var recivers = meta.Receivers.Select(x => _lib.Persons[x].Name) ?? new List<string>();
private BriefeMetaViewModel generateMetaViewModel(ILibrary lib, Meta meta, bool hasMarginals) {
var senders = meta.Senders.Select(x => lib.Persons[x].Name) ?? new List<string>();
var recivers = meta.Receivers.Select(x => lib.Persons[x].Name) ?? new List<string>();
var zhstring = meta.ZH != null ? HaWeb.HTMLHelpers.LetterHelpers.CreateZHString(meta) : null;
return new BriefeMetaViewModel(meta, hasMarginals, false) {
ParsedZHString = zhstring,

View File

@@ -8,6 +8,7 @@ using HaXMLReader;
using HaXMLReader.EvArgs;
using HaDocument.Models;
using System.Collections.Concurrent;
using HaWeb.FileHelpers;
namespace HaWeb.Controllers;
@@ -16,20 +17,18 @@ public class RegisterController : Controller {
[BindProperty(SupportsGet = true)]
public string? search { get; set; }
[BindProperty(SupportsGet = true)]
public string? id { get; set; }
// DI
private ILibrary _lib;
private IHaDocumentWrappper _lib;
private IReaderService _readerService;
public RegisterController(ILibrary lib, IReaderService readerService) {
public RegisterController(IHaDocumentWrappper lib, IReaderService readerService) {
_lib = lib;
_readerService = readerService;
}
public IActionResult Register(string? id) {
// Setup settings and variables
var lib = _lib.GetLibrary();
var url = "/Register/Register/";
var category = "neuzeit";
var defaultLetter = "A";
@@ -39,30 +38,30 @@ public class RegisterController : Controller {
// Normalisation and validation
if (id == null) return Redirect(url + defaultLetter);
normalizeID(id, defaultLetter);
if (!_lib.CommentsByCategoryLetter[category].Contains(this.id)) return error404();
id = normalizeID(id, defaultLetter);
if (!lib.CommentsByCategoryLetter[category].Contains(id)) return error404();
// Data aquisition and validation
var comments = _lib.CommentsByCategoryLetter[category][this.id].OrderBy(x => x.Index);
var availableCategories = _lib.CommentsByCategoryLetter[category].Select(x => (x.Key.ToUpper(), url + x.Key.ToUpper())).OrderBy(x => x.Item1).ToList();
var comments = lib.CommentsByCategoryLetter[category][id].OrderBy(x => x.Index);
var availableCategories = lib.CommentsByCategoryLetter[category].Select(x => (x.Key.ToUpper(), url + x.Key.ToUpper())).OrderBy(x => x.Item1).ToList();
if (comments == null) return error404();
// Parsing
var res = new List<CommentModel>();
foreach (var comm in comments) {
var parsedComment = HTMLHelpers.CommentHelpers.CreateHTML(_lib, _readerService, comm, category, Settings.ParsingState.CommentType.Comment);
var parsedComment = HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, comm, category, Settings.ParsingState.CommentType.Comment);
List<string>? parsedSubComments = null;
if (comm.Kommentare != null) {
parsedSubComments = new List<string>();
foreach (var subcomm in comm.Kommentare.OrderBy(x => x.Value.Order)) {
parsedSubComments.Add(HTMLHelpers.CommentHelpers.CreateHTML(_lib, _readerService, subcomm.Value, category, Settings.ParsingState.CommentType.Subcomment));
parsedSubComments.Add(HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, subcomm.Value, category, Settings.ParsingState.CommentType.Subcomment));
}
}
res.Add(new CommentModel(parsedComment, parsedSubComments));
}
// Model instantiation
var model = new RegisterViewModel(category, this.id, res, title) {
var model = new RegisterViewModel(category, id, res, title) {
AvailableCategories = availableCategories,
};
@@ -72,6 +71,7 @@ public class RegisterController : Controller {
public IActionResult Bibelstellen(string? id) {
// Setup settings and variables
var lib = _lib.GetLibrary();
var url = "/Register/Bibelstellen/";
var category = "bibel";
var defaultLetter = "AT";
@@ -81,30 +81,30 @@ public class RegisterController : Controller {
// Normalisation and Validation
if (id == null) return Redirect(url + defaultLetter);
normalizeID(id, defaultLetter);
if (this.id != "AT" && this.id != "AP" && this.id != "NT") return error404();
id = normalizeID(id, defaultLetter);
if (id != "AT" && id != "AP" && id != "NT") return error404();
// Data aquisition and validation
var comments = _lib.CommentsByCategory[category].ToLookup(x => x.Index.Substring(0, 2).ToUpper())[this.id].OrderBy(x => x.Order);
var comments = lib.CommentsByCategory[category].ToLookup(x => x.Index.Substring(0, 2).ToUpper())[id].OrderBy(x => x.Order);
var availableCategories = new List<(string, string)>() { ("Altes Testament", url + "AT"), ("Apogryphen", url + "AP"), ("Neues Testament", url + "NT") };
if (comments == null) return error404();
// Parsing
var res = new List<CommentModel>();
foreach (var comm in comments) {
var parsedComment = HTMLHelpers.CommentHelpers.CreateHTML(_lib, _readerService, comm, category, Settings.ParsingState.CommentType.Comment);
var parsedComment = HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, comm, category, Settings.ParsingState.CommentType.Comment);
List<string>? parsedSubComments = null;
if (comm.Kommentare != null) {
parsedSubComments = new List<string>();
foreach (var subcomm in comm.Kommentare.OrderBy(x => x.Value.Lemma.Length).ThenBy(x => x.Value.Lemma)) {
parsedSubComments.Add(HTMLHelpers.CommentHelpers.CreateHTML(_lib, _readerService, subcomm.Value, category, Settings.ParsingState.CommentType.Subcomment));
parsedSubComments.Add(HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, subcomm.Value, category, Settings.ParsingState.CommentType.Subcomment));
}
}
res.Add(new CommentModel(parsedComment, parsedSubComments));
}
// Model instantiation
var model = new RegisterViewModel(category, this.id, res, title) {
var model = new RegisterViewModel(category, id, res, title) {
AvailableCategories = availableCategories,
};
@@ -114,6 +114,7 @@ public class RegisterController : Controller {
public IActionResult Forschung(string? id) {
// Setup settings and variables
var lib = _lib.GetLibrary();
var url = "/Register/Forschung/";
var category = "forschung";
var defaultLetter = "A";
@@ -123,37 +124,37 @@ public class RegisterController : Controller {
// Normalisation and Validation
if (id == null) return Redirect(url + defaultLetter);
normalizeID(id, defaultLetter);
if (this.id != "EDITIONEN" && !_lib.CommentsByCategoryLetter[category].Contains(this.id)) return error404();
if (this.id == "EDITIONEN" && !_lib.CommentsByCategoryLetter.Keys.Contains(this.id.ToLower())) return error404();
id = normalizeID(id, defaultLetter);
if (id != "EDITIONEN" && !lib.CommentsByCategoryLetter[category].Contains(id)) return error404();
if (id == "EDITIONEN" && !lib.CommentsByCategoryLetter.Keys.Contains(id.ToLower())) return error404();
// Data aquisition and validation
IOrderedEnumerable<Comment>? comments = null;
if (this.id == "EDITIONEN") {
comments = _lib.CommentsByCategory[this.id.ToLower()].OrderBy(x => x.Index);
if (id == "EDITIONEN") {
comments = lib.CommentsByCategory[id.ToLower()].OrderBy(x => x.Index);
} else {
comments = _lib.CommentsByCategoryLetter[category][this.id].OrderBy(x => x.Index);
comments = lib.CommentsByCategoryLetter[category][id].OrderBy(x => x.Index);
}
var availableCategories = _lib.CommentsByCategoryLetter[category].Select(x => (x.Key.ToUpper(), url + x.Key.ToUpper())).OrderBy(x => x.Item1).ToList();
var availableCategories = lib.CommentsByCategoryLetter[category].Select(x => (x.Key.ToUpper(), url + x.Key.ToUpper())).OrderBy(x => x.Item1).ToList();
var AvailableSideCategories = new List<(string, string)>() { ("Editionen", "Editionen") };
if (comments == null) return error404();
// Parsing
var res = new List<CommentModel>();
foreach (var comm in comments) {
var parsedComment = HTMLHelpers.CommentHelpers.CreateHTML(_lib, _readerService, comm, category, Settings.ParsingState.CommentType.Comment);
var parsedComment = HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, comm, category, Settings.ParsingState.CommentType.Comment);
List<string>? parsedSubComments = null;
if (comm.Kommentare != null) {
parsedSubComments = new List<string>();
foreach (var subcomm in comm.Kommentare.OrderBy(x => x.Value.Order)) {
parsedSubComments.Add(HTMLHelpers.CommentHelpers.CreateHTML(_lib, _readerService, subcomm.Value, category, Settings.ParsingState.CommentType.Subcomment));
parsedSubComments.Add(HTMLHelpers.CommentHelpers.CreateHTML(lib, _readerService, subcomm.Value, category, Settings.ParsingState.CommentType.Subcomment));
}
}
res.Add(new CommentModel(parsedComment, parsedSubComments));
}
// Model instantiation
var model = new RegisterViewModel(category, this.id, res, title) {
var model = new RegisterViewModel(category, id, res, title) {
AvailableCategories = availableCategories,
AvailableSideCategories = AvailableSideCategories
};
@@ -162,11 +163,13 @@ public class RegisterController : Controller {
return View("Index", model);
}
private void normalizeID(string? id, string defaultid) {
this.id = this.id.ToUpper();
private string? normalizeID(string? id, string defaultid) {
if (id == null) return null;
return id.ToUpper();
}
private bool validationCheck(HashSet<string> permitted) {
private bool validationCheck(string? id, HashSet<string> permitted) {
if (id == null) return false;
if (!permitted.Contains(id)) {
return false;
}

View File

@@ -1,23 +0,0 @@
namespace HaWeb.Controllers;
using Microsoft.AspNetCore.Mvc;
using HaDocument.Interfaces;
using HaXMLReader.Interfaces;
using Microsoft.FeatureManagement.Mvc;
public class UpdateController : Controller {
// DI
private ILibrary _lib;
private IReaderService _readerService;
public UpdateController(ILibrary lib, IReaderService readerService) {
_lib = lib;
_readerService = readerService;
}
[Route("Admin/Update")]
[FeatureGate(Features.UpdateService)]
public IActionResult Index() {
return View("../Admin/Upload/Index");
}
}

View File

@@ -3,27 +3,17 @@ using Microsoft.AspNetCore.Mvc;
using HaDocument.Interfaces;
using HaXMLReader.Interfaces;
using Microsoft.FeatureManagement.Mvc;
using System.IO;
using System.Net;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Net.Http.Headers;
using HaWeb.Filters;
using HaWeb.FileHelpers;
using HaWeb.XMLParser;
using HaWeb.Models;
using System.Xml.Linq;
using System.Text.Json.Serialization;
using System.Text.Json;
using HaWeb.FileHelpers;
public class UploadController : Controller {
// DI
private ILibrary _lib;
private IHaDocumentWrappper _lib;
private IReaderService _readerService;
private readonly long _fileSizeLimit;
private readonly string _targetFilePath;
@@ -34,7 +24,7 @@ public class UploadController : Controller {
private static readonly FormOptions _defaultFormOptions = new FormOptions();
public UploadController(ILibrary lib, IReaderService readerService, IXMLService xmlService, IConfiguration config) {
public UploadController(IHaDocumentWrappper lib, IReaderService readerService, IXMLService xmlService, IConfiguration config) {
_lib = lib;
_readerService = readerService;
_xmlService = xmlService;
@@ -48,94 +38,35 @@ public class UploadController : Controller {
[HttpGet]
[Route("Admin/Upload/{id?}")]
[FeatureGate(Features.UploadService)]
[FeatureGate(Features.AdminService)]
[GenerateAntiforgeryTokenCookie]
public IActionResult Index(string? id) {
var model = new UploadViewModel();
model.AvailableRoots = _xmlService.GetRoots();
model.UsedFiles = _xmlService.GetUsed();
var hello = "mama";
return View("../Admin/Upload/Index", model);
if (id != null) {
var root = _xmlService.GetRoot(id);
if (root == null) return error404();
var roots = _xmlService.GetRoots();
if (roots == null) return error404();
var usedFiles = _xmlService.GetUsed();
var availableFiles = _xmlService.GetAvailableFiles(id);
var model = new UploadViewModel(root.Type, id, roots, availableFiles, usedFiles);
return View("../Admin/Upload/Index", model);
}
else {
var roots = _xmlService.GetRoots();
if (roots == null) return error404();
var usedFiles = _xmlService.GetUsed();
var model = new UploadViewModel("Upload", id, roots, null, usedFiles);
return View("../Admin/Upload/Index", model);
}
}
//// UPLOAD ////
[HttpPost]
[Route("Admin/Upload")]
[DisableFormValueModelBinding]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Post() {
List<XMLRootDocument>? docs = null;
//// 1. Stage: Check Request format and request spec
// Checks the Content-Type Field (must be multipart + Boundary)
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) {
ModelState.AddModelError("Error", $"Wrong / No Content Type on the Request");
return BadRequest(ModelState);
}
// Divides the multipart document into it's sections and sets up a reader
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
MultipartSection? section = null;
try {
section = await reader.ReadNextSectionAsync();
} catch (Exception ex) {
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
}
while (section != null) {
// Multipart document content disposition header read for a section:
// Starts with boundary, contains field name, content-dispo, filename, content-type
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader && contentDisposition != null) {
// Checks if it is a section with content-disposition, name, filename
if (!MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) {
ModelState.AddModelError("Error", $"Wrong Content-Dispostion Headers in Multipart Document");
return BadRequest(ModelState);
}
//// 2. Stage: Check File. Sanity checks on the file on a byte level, extension checking, is it empty etc.
var streamedFileContent = await XMLFileHelpers.ProcessStreamedFile(
section, contentDisposition, ModelState,
_permittedExtensions, _fileSizeLimit);
if (!ModelState.IsValid || streamedFileContent == null)
return BadRequest(ModelState);
//// 3. Stage: Valid XML checking using a simple XDocument.Load()
var xdocument = await XDocumentFileHelper.ProcessStreamedFile(streamedFileContent, ModelState);
if (!ModelState.IsValid || xdocument == null)
return UnprocessableEntity(ModelState);
//// 4. Stage: Is it a Hamann-Document? What kind?
var retdocs = await _xmlService.ProbeHamannFile(xdocument, ModelState);
if (!ModelState.IsValid || retdocs == null || !retdocs.Any())
return UnprocessableEntity(ModelState);
//// 5. Stage: Saving the File(s)
foreach (var doc in retdocs) {
await _xmlService.UpdateAvailableFiles(doc, _targetFilePath, ModelState);
if (!ModelState.IsValid) return StatusCode(500, ModelState);
if (docs == null) docs = new List<XMLRootDocument>();
docs.Add(doc);
}
}
try {
section = await reader.ReadNextSectionAsync();
} catch (Exception ex) {
ModelState.AddModelError("Error", "The Request is bad: " + ex.Message);
}
}
// 6. Stage: Success! Returning Ok, and redirecting
JsonSerializerOptions options = new() {
ReferenceHandler = ReferenceHandler.Preserve,
Converters = {
new IdentificationStringJSONConverter()
}
};
string json = JsonSerializer.Serialize(docs);
return Created(nameof(UploadController), json);
private IActionResult error404() {
Response.StatusCode = 404;
return Redirect("/Error404");
}
}