Files
LehrerApp/LehrerApp.Core/Importing/MarksPerLessonCsvImportHandler.cs
T

41 lines
2.1 KiB
C#

using System.Text;
namespace LehrerApp.Core.Importing;
/// <summary>Erkennt den Notenlistenexport und erklärt dessen fehlende Teilnehmerdaten.</summary>
public sealed class MarksPerLessonCsvImportHandler : IImportHandler<ImportedStudent>
{
private static readonly string[] SignatureHeaders =
["Datum", "Name", "Klasse", "Fach", "Prüfungsart", "Note", "Bemerkung", "Benutzer", "Schlüssel (extern)", "Gesamtnote"];
private static readonly UTF8Encoding StrictUtf8 = new(false, true);
public ImportFormatId FormatId => StudentImportFormats.MarksPerLessonCsv;
public string DisplayName => "Unterrichts-Notenliste";
public IReadOnlyCollection<string> SupportedExtensions { get; } = [".csv"];
public ValueTask<ImportDetection> DetectAsync(ImportFile file, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
string text;
try { text = StrictUtf8.GetString(file.Content.Span); }
catch (DecoderFallbackException) { return ValueTask.FromResult(ImportDetection.NoMatch()); }
var end = text.IndexOfAny(['\r', '\n']);
var firstLine = (end >= 0 ? text[..end] : text).TrimStart('\uFEFF');
var headers = firstLine.Split('\t').Select(x => x.Trim()).ToHashSet(StringComparer.OrdinalIgnoreCase);
return ValueTask.FromResult(SignatureHeaders.All(headers.Contains)
? ImportDetection.Match(file.Extension.Equals(".csv", StringComparison.OrdinalIgnoreCase) ? 100 : 95)
: ImportDetection.NoMatch());
}
public ValueTask<ImportParseResult<ImportedStudent>> ParseAsync(ImportFile file, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
IReadOnlyList<ImportMessage> messages =
[
new(ImportMessageSeverity.Error, "marks-per-lesson.no-participants",
"Die Notenliste enthält keine verlässlichen Teilnehmerdaten. Bitte exportiere die echte Kurs-/Teilnehmerliste.")
];
return ValueTask.FromResult(new ImportParseResult<ImportedStudent>([], messages));
}
}