436 lines
17 KiB
C#
436 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Windows.Controls;
|
|
using Elwig.Models;
|
|
|
|
namespace Elwig.Helpers {
|
|
public static class Validator {
|
|
|
|
private static readonly Dictionary<string, string[][]> PHONE_NRS = new() {
|
|
{ "43", new string[][] {
|
|
Array.Empty<string>(),
|
|
new string[] { "57", "59" },
|
|
new string[] {
|
|
"50", "517", "718", "804", "720", "780", "800", "802", "810",
|
|
"820", "821", "828", "900", "901", "930", "931", "939",
|
|
"650", "651", "652", "653", "655", "657", "659", "660", "661",
|
|
"663", "664", "665", "666", "667", "668", "669", "67", "68", "69"
|
|
}
|
|
} },
|
|
{ "49", Array.Empty<string[]>() },
|
|
{ "48", Array.Empty<string[]>() },
|
|
{ "420", Array.Empty<string[]>() },
|
|
{ "421", Array.Empty<string[]>() },
|
|
{ "36", Array.Empty<string[]>() },
|
|
{ "386", Array.Empty<string[]>() },
|
|
{ "39", Array.Empty<string[]>() },
|
|
{ "33", Array.Empty<string[]>() },
|
|
{ "41", Array.Empty<string[]>() },
|
|
{ "423", Array.Empty<string[]>() },
|
|
};
|
|
|
|
public static ValidationResult CheckInteger(TextBox input, bool required) {
|
|
return CheckInteger(input, required, -1);
|
|
}
|
|
|
|
public static ValidationResult CheckInteger(TextBox input, bool required, int maxLen) {
|
|
string text = "";
|
|
int pos = input.CaretIndex;
|
|
for (int i = 0; i < input.Text.Length; i++) {
|
|
char ch = input.Text[i];
|
|
if (char.IsAsciiDigit(ch))
|
|
text += ch;
|
|
if (i == input.CaretIndex - 1)
|
|
pos = text.Length;
|
|
}
|
|
input.Text = text;
|
|
input.CaretIndex = pos;
|
|
|
|
if (text.Length == 0) {
|
|
return required ? new(false, "Wert ist nicht optional") : new(true, null);
|
|
}
|
|
|
|
if (maxLen >= 0 && input.Text.Length > maxLen) {
|
|
input.Text = input.Text[..maxLen];
|
|
input.CaretIndex = Math.Min(pos, maxLen);
|
|
}
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckPlz(TextBox input, bool required, AppDbContext ctx) {
|
|
CheckInteger(input, false, 4);
|
|
if (!required && input.Text.Length == 0) {
|
|
return new(true, null);
|
|
} else if (input.Text.Length != 4) {
|
|
return new(false, "PLZ zu kurz");
|
|
}
|
|
int plz = int.Parse(input.Text);
|
|
if (!ctx.Postleitzahlen.Any(p => p.Plz == plz)) {
|
|
return new(false, "Ungültige PLZ");
|
|
}
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckPhoneNumber(TextBox input, bool required) {
|
|
string text = "";
|
|
int pos = input.CaretIndex;
|
|
for (int i = 0, v = 0; i < input.Text.Length && v < 30; i++) {
|
|
char ch = input.Text[i];
|
|
if (v == 0 && input.Text.Length - i >= 2 && ch == '0' && input.Text[i + 1] == '0') {
|
|
v++; i++;
|
|
text += '+';
|
|
} else if (ch == '(' && input.Text.Length - i >= 3 && input.Text[i + 1] == '0' && input.Text[i + 2] == ')') {
|
|
i += 2;
|
|
} else if (v == 0 && ch == '0') {
|
|
v += 3;
|
|
text += "+43";
|
|
} else if (v == 0 && ch == '+') {
|
|
v++;
|
|
text += ch;
|
|
} else if (v > 0 && char.IsAsciiDigit(ch)) {
|
|
if (PHONE_NRS.Any(kv => text == "+" + kv.Key))
|
|
text += ' ';
|
|
if (text.StartsWith("+43 ")) {
|
|
var nr = text[4..];
|
|
var vws = PHONE_NRS["43"];
|
|
if (v >= 4 && v - 4 < vws.Length && vws[v - 4].Any(vw => nr.StartsWith(vw)))
|
|
text += ' ';
|
|
else if (nr == "1")
|
|
text += ' ';
|
|
else if (v == 7 && nr.Length == 4)
|
|
text += ' ';
|
|
}
|
|
v++;
|
|
text += ch;
|
|
}
|
|
if (i == input.CaretIndex - 1)
|
|
pos = text.Length;
|
|
}
|
|
input.Text = text;
|
|
input.CaretIndex = pos;
|
|
|
|
if (!required && text.Length == 0) {
|
|
return new(true, null);
|
|
} else if (text.Length < 10) {
|
|
return new(false, "Telefonnummer zu kurz");
|
|
}
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckEmailAddress(TextBox input, bool required) {
|
|
string text = "";
|
|
int pos = input.CaretIndex;
|
|
bool domain = false;
|
|
for (int i = 0; i < input.Text.Length && text.Length < 256; i++) {
|
|
char ch = input.Text[i];
|
|
if (domain) {
|
|
if ((char.IsAsciiLetterOrDigit(ch)) || ".-_öäüßÖÄÜẞ".Any(c => c == ch)) {
|
|
if (!(text.Last() == '.' && ch == '.'))
|
|
text += char.ToLower(ch);
|
|
}
|
|
} else {
|
|
if (ch == '@')
|
|
domain = true;
|
|
if (!char.IsControl(ch) && !char.IsWhiteSpace(ch))
|
|
text += ch;
|
|
}
|
|
|
|
if (i == input.CaretIndex - 1)
|
|
pos = text.Length;
|
|
}
|
|
input.Text = text;
|
|
input.CaretIndex = pos;
|
|
|
|
if (text.Length == 0) {
|
|
return required ? new(false, "E-Mail-Adresse ist nicht optional") : new(true, null);
|
|
} else if (text[0] == '@' || !domain) {
|
|
return new(false, "E-Mail-Adresse ungültig");
|
|
}
|
|
|
|
var last = text.Split(".").Last();
|
|
if (last.Length < 2 || !last.All(ch => char.IsAsciiLetterLower(ch)))
|
|
return new(false, "E-Mail-Adresse ungültig");
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckIban(TextBox input, bool required) {
|
|
string text = "";
|
|
int pos = input.CaretIndex;
|
|
int v = 0;
|
|
for (int i = 0; i < input.Text.Length && v < 34; i++) {
|
|
char ch = input.Text[i];
|
|
if (char.IsAsciiLetterOrDigit(ch)) {
|
|
if (((v < 2 && char.IsAsciiLetter(ch)) || (v >= 2 && v < 4 && char.IsAsciiDigit(ch)) || v >= 4) &&
|
|
((!text.StartsWith("AT") && !text.StartsWith("DE")) || char.IsAsciiDigit(ch)))
|
|
{
|
|
if (v != 0 && v % 4 == 0)
|
|
text += ' ';
|
|
v++;
|
|
text += char.ToUpper(ch);
|
|
}
|
|
}
|
|
if (i == input.CaretIndex - 1)
|
|
pos = text.Length;
|
|
if (text.StartsWith("AT") && v >= 20)
|
|
break;
|
|
else if (text.StartsWith("DE") && v >= 22)
|
|
break;
|
|
}
|
|
input.Text = text;
|
|
input.CaretIndex = pos;
|
|
|
|
if (!required && text.Length == 0) {
|
|
return new(true, null);
|
|
} else if (v < 5 || (text.StartsWith("AT") && v != 20) || (text.StartsWith("DE") && v != 22)) {
|
|
return new(false, "IBAN hat falsche Länge");
|
|
}
|
|
|
|
var validation = (text[4..] + text[..4]).Replace(" ", "")
|
|
.Select(ch => char.IsAsciiDigit(ch) ? ch.ToString() : (ch - 'A' + 10).ToString())
|
|
.Aggregate((a, b) => a + b);
|
|
if (Utils.Modulo(validation, 97) != 1)
|
|
return new(false, "Prüfsumme der IBAN ist falsch");
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckBic(TextBox input, bool required) {
|
|
string text = "";
|
|
int pos = input.CaretIndex;
|
|
for (int i = 0, v = 0; i < input.Text.Length; i++) {
|
|
char ch = input.Text[i];
|
|
if ((v < 4 || v >= 6) && char.IsAsciiLetterOrDigit(ch)) {
|
|
v++;
|
|
text += char.ToUpper(ch);
|
|
} else if (v >= 4 && v < 6 && char.IsAsciiLetter(ch)) {
|
|
v++;
|
|
text += char.ToUpper(ch);
|
|
}
|
|
|
|
if (i == input.CaretIndex - 1)
|
|
pos = text.Length;
|
|
}
|
|
|
|
if (text.Length == 0) {
|
|
return required ? new(false, "BIC ist nicht optional") : new(true, null);
|
|
}
|
|
|
|
if (text.Length > 11) {
|
|
text = text[..11];
|
|
pos = Math.Min(pos, 11);
|
|
}
|
|
|
|
if (text.Length == 11 && text.EndsWith("XXX"))
|
|
text = text[..8];
|
|
|
|
input.Text = text;
|
|
input.CaretIndex = pos;
|
|
|
|
if (text.Length != 11 && text.Length != 8)
|
|
return new(false, "BIC ist ungültig");
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckLfbisNr(TextBox input, bool required) {
|
|
var res = CheckInteger(input, false, 7);
|
|
if (!res.IsValid) {
|
|
return res;
|
|
} else if (!required && input.Text.Length == 0) {
|
|
return new(true, null);
|
|
} else if (input.Text.Length != 7) {
|
|
return new(false, "Betriebsnummer zu kurz");
|
|
}
|
|
|
|
// https://statistik.at/fileadmin/shared/QM/Standarddokumentationen/RW/std_r_land-forstw_register.pdf#page=41
|
|
int s = 0, v;
|
|
for (int i = 0; i < 6; i++)
|
|
s += (input.Text[i] - '0') * (7 - i);
|
|
v = (11 - (s % 11)) % 10;
|
|
|
|
if (v != (input.Text[6] - '0'))
|
|
return new(false, "Prüfsumme der Betriebsnummer ist falsch");
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckUstId(TextBox input, bool required) {
|
|
string text = "";
|
|
int pos = input.CaretIndex;
|
|
for (int i = 0, v = 0; i < input.Text.Length; i++) {
|
|
char ch = input.Text[i];
|
|
if (v < 2 && char.IsAsciiLetter(ch)) {
|
|
v++;
|
|
text += char.ToUpper(ch);
|
|
} else if (v >= 2 && char.IsAsciiLetterOrDigit(ch)) {
|
|
if (text.StartsWith("AT")) {
|
|
if (v == 2 && (ch == 'u' || ch == 'U')) {
|
|
v++;
|
|
text += 'U';
|
|
} else if (v > 2 && char.IsAsciiDigit(ch)) {
|
|
v++;
|
|
text += ch;
|
|
}
|
|
} else {
|
|
v++;
|
|
text += char.ToUpper(ch);
|
|
}
|
|
}
|
|
|
|
if (i == input.CaretIndex - 1) {
|
|
pos = text.Length;
|
|
} else if (v >= 14) {
|
|
break;
|
|
} else if (text.StartsWith("AT") && v >= 11) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
input.Text = text;
|
|
input.CaretIndex = pos;
|
|
|
|
if (text.Length == 0)
|
|
return required ? new(false, "UID ist nicht optional") : new(true, null);
|
|
|
|
if (text.StartsWith("AT")) {
|
|
if (text.Length != 11 || text[2] != 'U')
|
|
return new(false, "UID ist ungültig");
|
|
|
|
// http://www.pruefziffernberechnung.de/U/USt-IdNr.shtml
|
|
int s = 0, v = 0;
|
|
for (int i = 0; i < 7; i++)
|
|
s += ((text[i + 3] - '0') * (i % 2 + 1)).ToString().Select(ch => ch - '0').Sum();
|
|
v = (96 - s) % 10;
|
|
|
|
if (v != (text[10] - '0'))
|
|
return new(false, "Prüfsumme der UID ist falsch");
|
|
} else {
|
|
return new(false, "Not implemented yet");
|
|
}
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckMgNr(TextBox input, bool required, AppDbContext ctx, Member? m) {
|
|
var res = CheckInteger(input, required);
|
|
if (!res.IsValid) {
|
|
return res;
|
|
} else if (!required && input.Text.Length == 0) {
|
|
return new(true, null);
|
|
}
|
|
|
|
int nr = int.Parse(input.Text);
|
|
if (nr != m?.MgNr && ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
|
|
return new(false, "Mitgliedsnummer wird bereits verwendet");
|
|
}
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckPredecessorMgNr(TextBox input, bool required, AppDbContext ctx) {
|
|
var res = CheckInteger(input, required);
|
|
if (!res.IsValid) {
|
|
return res;
|
|
} else if (!required && input.Text.Length == 0) {
|
|
return new(true, null);
|
|
} else if (!ctx.MgNrExists(int.Parse(input.Text)).GetAwaiter().GetResult()) {
|
|
return new(false, "Ein Mitglied mit dieser Mitgliedsnummer existiert nicht");
|
|
}
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckDate(TextBox input, bool required) {
|
|
return CheckDate(input, required, false);
|
|
}
|
|
|
|
public static ValidationResult CheckPartialDate(TextBox input, bool required) {
|
|
return CheckDate(input, required, true);
|
|
}
|
|
|
|
private static ValidationResult CheckDate(TextBox input, bool required, bool partial) {
|
|
string text = "";
|
|
int pos = input.CaretIndex;
|
|
int p = 0;
|
|
var parts = new string?[3];
|
|
parts[0] = "";
|
|
for (int i = 0; i < input.Text.Length; i++) {
|
|
char ch = input.Text[i];
|
|
if (ch == '.') {
|
|
if (p < 2 && (parts[p]?.Length > 0 || pos == text.Length)) {
|
|
if (parts[p]?.Length == 1 && ((pos != text.Length && pos != text.Length - 1) || !input.IsFocused)) {
|
|
parts[p] = "0" + parts[p];
|
|
text = text[..(text.Length - 1)] + "0" + text[^1];
|
|
}
|
|
parts[++p] = "";
|
|
text += '.';
|
|
}
|
|
} else if (char.IsAsciiDigit(ch)) {
|
|
if ((partial && parts[p]?.Length < 4) || (!partial && ((p < 2 && parts[p]?.Length < 2) || (p == 2 && parts[2]?.Length < 4)))) {
|
|
parts[p] += ch;
|
|
text += ch;
|
|
}
|
|
if (p == 0 && pos == 1 && input.Text.Length >= 4 && input.Text.Length <= 9) {
|
|
parts[++p] = "";
|
|
text += '.';
|
|
continue; // skip caret update
|
|
}
|
|
}
|
|
|
|
if (i == input.CaretIndex - 1) {
|
|
pos = text.Length;
|
|
}
|
|
}
|
|
|
|
input.Text = text;
|
|
input.CaretIndex = pos;
|
|
|
|
if (text.Length == 0)
|
|
return required ? new(false, "Datum ist nicht optional") : new(true, null);
|
|
|
|
if (partial) {
|
|
if (p == 0) {
|
|
// only year provided
|
|
return (parts[0]?.Length == 4) ? new(true, null) : new(false, "Datum ist ungültig");
|
|
} else if (p == 1) {
|
|
// only month and year provided
|
|
int m = parts[0] != null && parts[0] != "" ? int.Parse(parts[0] ?? "0") : 0;
|
|
if (parts[1]?.Length != 4 || parts[0]?.Length != 2 || m < 1 || m > 12)
|
|
return new(false, "Datum ist ungültig");
|
|
return new(true, null);
|
|
}
|
|
}
|
|
|
|
if (!DateOnly.TryParseExact(text, "dd.MM.yyyy", out _))
|
|
return new(false, "Datum ist ungültig");
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckFbNr(TextBox input, bool required, AppDbContext ctx, AreaCom? c) {
|
|
var res = CheckInteger(input, required);
|
|
if (!res.IsValid) {
|
|
return res;
|
|
} else if (!required && input.Text.Length == 0) {
|
|
return new(true, null);
|
|
}
|
|
|
|
int nr = int.Parse(input.Text);
|
|
if (nr != c?.FbNr && ctx.FbNrExists(nr).GetAwaiter().GetResult()) {
|
|
return new(false, "Flächenbindungsnummer wird bereits verwendet");
|
|
}
|
|
|
|
return new(true, null);
|
|
}
|
|
|
|
public static ValidationResult CheckGstNr(TextBox input, bool required) {
|
|
// TODO
|
|
return new(true, "Not implemented yet");
|
|
}
|
|
}
|
|
}
|