Behoerde oder Organisation und Funktion oder Dienststelle sind optional, in beiden Sprachen mit Hinweis am Feld. Pflicht bleiben Name, dienstliche E-Mail und die Einwilligung. Dabei aufgefallen, das Formular traegt novalidate, damit die Browsermeldungen die eigene Pruefung nicht ueberlagern. Die Pflichtfelder wurden dadurch bisher gar nicht erzwungen, ein leerer Name waere durchgegangen. Die Pruefung liegt jetzt im Skript, mit Meldung und Fokus auf dem betroffenen Feld. Der Name steht ausserdem mit in der Anfrage-Mail, da die Organisation leer bleiben kann.
243 Zeilen
11 KiB
JavaScript
243 Zeilen
11 KiB
JavaScript
/* ==================================================================
|
|
AegisSight Testzugang-Formular
|
|
Liegt im Anfrage-Popup der Startseite, deutsch und englisch.
|
|
Sprache wird aus <html lang> gelesen, wie in lagebild.js und
|
|
cookie-consent.js auch.
|
|
================================================================== */
|
|
(function () {
|
|
'use strict';
|
|
|
|
var LANG = (document.documentElement.lang || 'de').toLowerCase().indexOf('en') === 0 ? 'en' : 'de';
|
|
|
|
/* ---------- Texte ---------- */
|
|
var T = {
|
|
de: {
|
|
sending: 'Wird gesendet...',
|
|
send: 'Testzugang anfragen',
|
|
nameFehlt: 'Bitte geben Sie Ihren Namen an.',
|
|
freemail: 'Bitte geben Sie Ihre dienstliche E-Mail-Adresse an. Adressen bei Freemail-Anbietern wie Gmail, GMX oder web.de können wir für einen Testzugang nicht berücksichtigen.',
|
|
invalidMail: 'Diese E-Mail-Adresse sieht nicht vollständig aus. Bitte prüfen Sie Ihre Eingabe.',
|
|
consent: 'Bitte bestätigen Sie die Datenschutzhinweise, damit wir Ihre Anfrage bearbeiten dürfen.',
|
|
tooFast: 'Bitte nehmen Sie sich einen Moment für das Formular. Versuchen Sie es gleich noch einmal.',
|
|
sendError: 'Die Anfrage konnte nicht gesendet werden.',
|
|
netError: 'Verbindungsfehler. Bitte versuchen Sie es erneut.',
|
|
hintOfficial: 'Dienstliche Adresse erkannt.',
|
|
labels: {
|
|
head: 'ANFRAGE TESTZUGANG AEGISSIGHT MONITOR',
|
|
name: 'Name',
|
|
org: 'Behörde oder Organisation',
|
|
role: 'Funktion oder Dienststelle',
|
|
mail: 'Dienstliche E-Mail',
|
|
phone: 'Telefon',
|
|
domain: 'Domain-Einstufung',
|
|
domainOk: 'Behörden- oder Organisationsdomain erkannt',
|
|
domainCheck: 'nicht eindeutig, bitte manuell prüfen',
|
|
empty: 'keine Angabe'
|
|
}
|
|
},
|
|
en: {
|
|
sending: 'Sending...',
|
|
send: 'Request trial access',
|
|
nameFehlt: 'Please enter your name.',
|
|
freemail: 'Please enter your official work email address. Addresses from free providers such as Gmail, GMX or web.de cannot be accepted for trial access.',
|
|
invalidMail: 'This email address looks incomplete. Please check your entry.',
|
|
consent: 'Please confirm the privacy notice so that we may process your request.',
|
|
tooFast: 'Please take a moment to fill in the form, then try again.',
|
|
sendError: 'The request could not be sent.',
|
|
netError: 'Connection error. Please try again.',
|
|
hintOfficial: 'Official address recognised.',
|
|
labels: {
|
|
head: 'TRIAL ACCESS REQUEST AEGISSIGHT MONITOR',
|
|
name: 'Name',
|
|
org: 'Authority or organisation',
|
|
role: 'Role or department',
|
|
mail: 'Work email',
|
|
phone: 'Phone',
|
|
domain: 'Domain assessment',
|
|
domainOk: 'official domain recognised',
|
|
domainCheck: 'not conclusive, please review manually',
|
|
empty: 'not provided'
|
|
}
|
|
}
|
|
}[LANG];
|
|
|
|
/* ---------- Freemail- und Wegwerf-Anbieter ----------
|
|
Diese Adressen werden abgewiesen. Alles andere kommt durch,
|
|
damit Landkreise, Hochschulen und Rettungsdienste mit eigener
|
|
Domain nicht ausgesperrt werden. */
|
|
var BLOCKED = [
|
|
'gmail.com', 'googlemail.com', 'gmx.de', 'gmx.net', 'gmx.at', 'gmx.ch', 'gmx.com',
|
|
'web.de', 't-online.de', 'freenet.de', 'arcor.de', 'online.de',
|
|
'outlook.com', 'outlook.de', 'hotmail.com', 'hotmail.de', 'live.com', 'live.de', 'msn.com',
|
|
'yahoo.com', 'yahoo.de', 'yahoo.co.uk', 'ymail.com', 'aol.com',
|
|
'icloud.com', 'me.com', 'mac.com',
|
|
'proton.me', 'protonmail.com', 'pm.me', 'posteo.de', 'posteo.net', 'mailbox.org',
|
|
'mail.de', 'mail.com', 'email.de', 'firemail.de', 'unitybox.de', 'vodafone.de', 'vodafonemail.de',
|
|
'zoho.com', 'fastmail.com', 'hey.com', 'tutanota.com', 'tutanota.de', 'tuta.io',
|
|
'yandex.com', 'yandex.ru', 'mail.ru', 'qq.com', '163.com', '126.com', 'sina.com',
|
|
'mailinator.com', 'guerrillamail.com', '10minutemail.com', 'temp-mail.org', 'tempmail.com',
|
|
'trashmail.com', 'trashmail.de', 'wegwerfmail.de', 'yopmail.com', 'sharklasers.com',
|
|
'getnada.com', 'dispostable.com', 'maildrop.cc', 'throwawaymail.com', 'moakt.com',
|
|
'emailondeck.com', 'spam4.me', 'byom.de', 'einrot.com', 'mytemp.email'
|
|
];
|
|
|
|
/* ---------- Muster typischer Behörden- und Organisationsdomains ----------
|
|
Nur zur Kennzeichnung in der Anfrage-Mail, keine Sperre. */
|
|
var OFFICIAL_SUFFIX = [
|
|
'.bund.de', '.bundeswehr.org', '.bundestag.de', '.bundesrat.de',
|
|
'.bayern.de', '.nrw.de', '.berlin.de', '.hamburg.de', '.bremen.de',
|
|
'.niedersachsen.de', '.hessen.de', '.rlp.de', '.saarland.de', '.sachsen.de',
|
|
'.sachsen-anhalt.de', '.thueringen.de', '.brandenburg.de', '.schleswig-holstein.de',
|
|
'.mv-regierung.de', '.bwl.de', '.baden-wuerttemberg.de',
|
|
'.europa.eu', '.europarl.europa.eu', '.gv.at', '.bmi.gv.at', '.admin.ch',
|
|
'.gov', '.gov.uk', '.mil', '.gouv.fr', '.overheid.nl', '.edu'
|
|
];
|
|
var OFFICIAL_PART = [
|
|
'polizei.', 'bundeswehr.', 'bundespolizei.', 'zoll.', 'thw.', 'feuerwehr.',
|
|
'stadt-', 'stadt.', 'kreis-', 'landkreis-', 'kreis.', 'bezirk-', 'gemeinde-',
|
|
'uni-', 'universitaet', 'university', 'hochschule', 'fh-', 'hs-',
|
|
'landtag', 'ministerium', 'verfassungsschutz', 'bka.', 'bfv.', 'lka.'
|
|
];
|
|
|
|
function domainOf(mail) {
|
|
var at = (mail || '').lastIndexOf('@');
|
|
return at === -1 ? '' : mail.slice(at + 1).trim().toLowerCase();
|
|
}
|
|
|
|
function isBlocked(mail) {
|
|
return BLOCKED.indexOf(domainOf(mail)) !== -1;
|
|
}
|
|
|
|
function looksOfficial(mail) {
|
|
var d = domainOf(mail);
|
|
if (!d) return false;
|
|
var i;
|
|
for (i = 0; i < OFFICIAL_SUFFIX.length; i++) {
|
|
if (d === OFFICIAL_SUFFIX[i].slice(1) || d.slice(-OFFICIAL_SUFFIX[i].length) === OFFICIAL_SUFFIX[i]) return true;
|
|
}
|
|
for (i = 0; i < OFFICIAL_PART.length; i++) {
|
|
if (d.indexOf(OFFICIAL_PART[i]) !== -1) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function plausibleMail(mail) {
|
|
return /^[^\s@]+@[^\s@.]+(\.[^\s@.]+)+$/.test(mail || '');
|
|
}
|
|
|
|
/* ---------- Initialisierung ---------- */
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
var form = document.getElementById('trial-form');
|
|
if (!form) return;
|
|
|
|
var loadedAt = Date.now();
|
|
var mailField = document.getElementById('tf-email');
|
|
var mailNote = document.getElementById('tf-email-note');
|
|
|
|
/* Live-Rueckmeldung am E-Mail-Feld */
|
|
if (mailField && mailNote) {
|
|
mailField.addEventListener('blur', function () {
|
|
var v = mailField.value.trim();
|
|
mailNote.className = 'tf-note';
|
|
if (!v) { mailNote.textContent = ''; return; }
|
|
if (isBlocked(v)) {
|
|
mailNote.textContent = T.freemail;
|
|
mailNote.className = 'tf-note tf-note-error';
|
|
mailField.setAttribute('aria-invalid', 'true');
|
|
} else if (looksOfficial(v)) {
|
|
mailNote.textContent = T.hintOfficial;
|
|
mailNote.className = 'tf-note tf-note-ok';
|
|
mailField.removeAttribute('aria-invalid');
|
|
} else {
|
|
mailNote.textContent = '';
|
|
mailField.removeAttribute('aria-invalid');
|
|
}
|
|
});
|
|
}
|
|
|
|
form.addEventListener('submit', function (e) {
|
|
e.preventDefault();
|
|
|
|
var val = function (id) {
|
|
var el = document.getElementById(id);
|
|
return el ? el.value.trim() : '';
|
|
};
|
|
|
|
var email = val('tf-email');
|
|
var honey = val('tf-website');
|
|
var consent = document.getElementById('tf-consent');
|
|
var errorBox = document.getElementById('tf-error');
|
|
var btn = form.querySelector('button[type="submit"]');
|
|
|
|
var fail = function (msg, feldId) {
|
|
if (errorBox) {
|
|
errorBox.textContent = msg;
|
|
errorBox.style.display = 'block';
|
|
errorBox.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
}
|
|
var feld = feldId && document.getElementById(feldId);
|
|
if (feld) { feld.focus(); }
|
|
if (btn) { btn.disabled = false; btn.textContent = T.send; }
|
|
};
|
|
|
|
if (errorBox) errorBox.style.display = 'none';
|
|
|
|
/* Honeypot. Echte Nutzer sehen dieses Feld nicht. */
|
|
if (honey) return false;
|
|
|
|
/* Zeitfalle gegen Bots */
|
|
if (Date.now() - loadedAt < 4000) return fail(T.tooFast);
|
|
|
|
/* Das Formular traegt novalidate, damit die Browsermeldungen die
|
|
eigene Pruefung nicht ueberlagern. Pflichtfelder deshalb hier. */
|
|
if (!val('tf-name')) return fail(T.nameFehlt, 'tf-name');
|
|
if (!plausibleMail(email)) return fail(T.invalidMail, 'tf-email');
|
|
if (isBlocked(email)) return fail(T.freemail, 'tf-email');
|
|
if (consent && !consent.checked) return fail(T.consent, 'tf-consent');
|
|
|
|
if (btn) { btn.disabled = true; btn.textContent = T.sending; }
|
|
|
|
var L = T.labels;
|
|
var e_ = L.empty;
|
|
var zeilen = [
|
|
L.head,
|
|
'',
|
|
L.name + ' = ' + val('tf-name'),
|
|
L.org + ' = ' + (val('tf-org') || e_),
|
|
L.role + ' = ' + (val('tf-role') || e_),
|
|
L.mail + ' = ' + email,
|
|
L.phone + ' = ' + (val('tf-phone') || e_),
|
|
'',
|
|
L.domain + ' = ' + (looksOfficial(email) ? L.domainOk : L.domainCheck)
|
|
];
|
|
var body = zeilen.join('\n');
|
|
|
|
fetch('/api/contact', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
name: val('tf-name'),
|
|
organisation: val('tf-org'),
|
|
email: email,
|
|
message: body,
|
|
lang: LANG
|
|
})
|
|
})
|
|
.then(function (r) { return r.json().then(function (d) { return { ok: r.ok, data: d }; }); })
|
|
.then(function (res) {
|
|
if (res.ok) {
|
|
form.style.display = 'none';
|
|
var ok = document.getElementById('tf-success');
|
|
if (ok) { ok.style.display = 'block'; ok.scrollIntoView({ behavior: 'smooth', block: 'center' }); }
|
|
if (window.umami) umami.track('trial_request_success');
|
|
} else {
|
|
fail((res.data && res.data.error) || T.sendError);
|
|
}
|
|
})
|
|
.catch(function () { fail(T.netError); });
|
|
|
|
return false;
|
|
});
|
|
});
|
|
})();
|