feat: add catalogue check by creating a small service runner
This commit is contained in:
@@ -24,5 +24,8 @@ define('MAIL_TO', getenv('MAIL_TO') ?: 'semesterapparate@ph-freiburg.de');
|
||||
define('BASE_PATH', __DIR__);
|
||||
define('STATIC_PATH', '/static');
|
||||
|
||||
// Signature validation API (optional Python service)
|
||||
define('SIGNATURE_API_URL', getenv('SIGNATURE_API_URL') ?: 'http://localhost:8001');
|
||||
|
||||
// Email regex pattern
|
||||
define('EMAIL_REGEX', '/^[^@\s]+@[^@\s]+\.[^@\s]+$/');
|
||||
|
||||
200
php/elsa.php
200
php/elsa.php
@@ -34,7 +34,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form method="post" action="submit_elsa.php" class="request-form">
|
||||
<form method="post" action="submit_elsa.php" class="request-form" data-api-url="<?php echo SIGNATURE_API_URL; ?>">
|
||||
<h2>Allgemeine Informationen</h2>
|
||||
<div class="grid-form">
|
||||
<div class="form-field">
|
||||
@@ -137,6 +137,16 @@
|
||||
};
|
||||
|
||||
let sectionCounter = 0;
|
||||
|
||||
// Track signature validations
|
||||
let signatureTracking = {};
|
||||
let validationTimers = {};
|
||||
|
||||
// Get API URL from form data attribute
|
||||
const getApiUrl = () => {
|
||||
const form = document.querySelector('.request-form');
|
||||
return form ? form.dataset.apiUrl : 'http://localhost:8001';
|
||||
};
|
||||
|
||||
// Theme toggle functionality
|
||||
(function() {
|
||||
@@ -271,6 +281,7 @@
|
||||
'<td><input type="number" name="monografie_pages_from[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><input type="number" name="monografie_pages_to[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><button type="button" class="btn-icon" onclick="removeRow(\'' + rowId + '\')" title="Zeile entfernen"><span class="mdi mdi-delete"></span></button></td>';
|
||||
attachSignatureListeners(row);
|
||||
} else if (type === 'zeitschriftenartikel') {
|
||||
row.innerHTML = '<td><input type="text" name="zeitschrift_author[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="zeitschrift_year[]" data-section="' + sectionId + '" required></td>' +
|
||||
@@ -291,6 +302,7 @@
|
||||
'<td><input type="text" name="herausgeber_signature[]" data-section="' + sectionId + '" placeholder="Optional"></td>' +
|
||||
'<td><input type="number" name="herausgeber_pages_from[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><input type="number" name="herausgeber_pages_to[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
attachSignatureListeners(row);
|
||||
'<td><button type="button" class="btn-icon" onclick="removeRow(\'' + rowId + '\')" title="Zeile entfernen"><span class="mdi mdi-delete"></span></button></td>';
|
||||
}
|
||||
}
|
||||
@@ -298,21 +310,203 @@
|
||||
function removeRow(rowId) {
|
||||
const row = document.getElementById(rowId);
|
||||
if (row) {
|
||||
const signatureInput = row.querySelector('input[name*="_signature"]');
|
||||
if (signatureInput) {
|
||||
cleanupSignatureTracking(signatureInput);
|
||||
}
|
||||
row.remove();
|
||||
updateSubmitButton();
|
||||
}
|
||||
}
|
||||
|
||||
function validateSignature(signatureInput, pagesFromInput, pagesToInput) {
|
||||
const signature = signatureInput.value.trim();
|
||||
|
||||
if (!signature) {
|
||||
signatureInput.classList.remove('signature-validating', 'signature-valid', 'signature-invalid');
|
||||
return;
|
||||
}
|
||||
|
||||
const inputId = signatureInput.id || signatureInput.name;
|
||||
if (validationTimers[inputId]) {
|
||||
clearTimeout(validationTimers[inputId]);
|
||||
}
|
||||
|
||||
signatureInput.classList.add('signature-validating');
|
||||
signatureInput.classList.remove('signature-valid', 'signature-invalid');
|
||||
|
||||
validationTimers[inputId] = setTimeout(async () => {
|
||||
try {
|
||||
const apiUrl = getApiUrl();
|
||||
const response = await fetch(apiUrl + '/api/validate-signature?signature=' + encodeURIComponent(signature));
|
||||
const data = await response.json();
|
||||
|
||||
if (data.valid) {
|
||||
if (!signatureTracking[signature]) {
|
||||
signatureTracking[signature] = {
|
||||
totalPages: data.total_pages,
|
||||
inputs: []
|
||||
};
|
||||
} else {
|
||||
signatureTracking[signature].totalPages = data.total_pages;
|
||||
}
|
||||
|
||||
const existingIndex = signatureTracking[signature].inputs.findIndex(
|
||||
item => item.signature === signatureInput
|
||||
);
|
||||
if (existingIndex === -1) {
|
||||
signatureTracking[signature].inputs.push({
|
||||
signature: signatureInput,
|
||||
pagesFrom: pagesFromInput,
|
||||
pagesTo: pagesToInput
|
||||
});
|
||||
}
|
||||
|
||||
signatureInput.classList.remove('signature-validating');
|
||||
signatureInput.classList.add('signature-valid');
|
||||
signatureInput.title = 'Signatur gefunden: ' + data.total_pages + ' Seiten';
|
||||
|
||||
checkSignatureThreshold(signature);
|
||||
} else {
|
||||
signatureInput.classList.remove('signature-validating');
|
||||
signatureInput.classList.add('signature-invalid');
|
||||
signatureInput.title = data.error || 'Signatur nicht gefunden';
|
||||
updateSubmitButton();
|
||||
}
|
||||
} catch (error) {
|
||||
signatureInput.classList.remove('signature-validating');
|
||||
signatureInput.classList.add('signature-invalid');
|
||||
signatureInput.title = 'Validierungsfehler - API nicht erreichbar';
|
||||
updateSubmitButton();
|
||||
}
|
||||
}, 800);
|
||||
}
|
||||
|
||||
function checkSignatureThreshold(signature) {
|
||||
const tracking = signatureTracking[signature];
|
||||
if (!tracking) return;
|
||||
|
||||
let totalRequestedPages = 0;
|
||||
const threshold = Math.ceil(tracking.totalPages * 0.15);
|
||||
|
||||
tracking.inputs.forEach(item => {
|
||||
const from = parseInt(item.pagesFrom.value) || 0;
|
||||
const to = parseInt(item.pagesTo.value) || 0;
|
||||
if (from > 0 && to > 0 && to >= from) {
|
||||
totalRequestedPages += (to - from + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const isOverThreshold = totalRequestedPages > threshold;
|
||||
|
||||
tracking.inputs.forEach(item => {
|
||||
const row = item.signature.closest('tr');
|
||||
if (row) {
|
||||
if (isOverThreshold) {
|
||||
row.classList.add('threshold-exceeded');
|
||||
item.signature.title = 'Warnung: Gesamtanzahl der Seiten (' + totalRequestedPages + ') überschreitet 15% (' + threshold + ' Seiten)';
|
||||
} else {
|
||||
row.classList.remove('threshold-exceeded');
|
||||
item.signature.title = 'Signatur gefunden: ' + tracking.totalPages + ' Seiten (Aktuell: ' + totalRequestedPages + '/' + threshold + ')';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateSubmitButton();
|
||||
}
|
||||
|
||||
function cleanupSignatureTracking(signatureInput) {
|
||||
const signature = signatureInput.value.trim();
|
||||
if (signature && signatureTracking[signature]) {
|
||||
signatureTracking[signature].inputs = signatureTracking[signature].inputs.filter(
|
||||
item => item.signature !== signatureInput
|
||||
);
|
||||
|
||||
if (signatureTracking[signature].inputs.length === 0) {
|
||||
delete signatureTracking[signature];
|
||||
} else {
|
||||
checkSignatureThreshold(signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateSubmitButton() {
|
||||
const submitButton = document.querySelector('button[type="submit"]');
|
||||
const hasInvalidSignatures = document.querySelectorAll('.signature-invalid').length > 0;
|
||||
const hasThresholdExceeded = document.querySelectorAll('.threshold-exceeded').length > 0;
|
||||
|
||||
if (hasInvalidSignatures || hasThresholdExceeded) {
|
||||
submitButton.disabled = true;
|
||||
if (hasThresholdExceeded) {
|
||||
submitButton.title = 'Formular kann nicht abgesendet werden: 15%-Grenze überschritten';
|
||||
} else {
|
||||
submitButton.title = 'Formular kann nicht abgesendet werden: Ungültige Signaturen';
|
||||
}
|
||||
} else {
|
||||
submitButton.disabled = false;
|
||||
submitButton.title = '';
|
||||
}
|
||||
}
|
||||
|
||||
function attachSignatureListeners(row) {
|
||||
const signatureInput = row.querySelector('input[name*="_signature"]');
|
||||
const pagesFromInput = row.querySelector('input[name*="_pages_from"]');
|
||||
const pagesToInput = row.querySelector('input[name*="_pages_to"]');
|
||||
|
||||
if (signatureInput && pagesFromInput && pagesToInput) {
|
||||
if (!signatureInput.id) {
|
||||
signatureInput.id = 'sig-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
signatureInput.addEventListener('input', () => {
|
||||
const oldSignature = signatureInput.dataset.lastSignature || '';
|
||||
const newSignature = signatureInput.value.trim();
|
||||
|
||||
if (oldSignature && oldSignature !== newSignature) {
|
||||
const tempInput = document.createElement('input');
|
||||
tempInput.value = oldSignature;
|
||||
cleanupSignatureTracking(tempInput);
|
||||
}
|
||||
|
||||
signatureInput.dataset.lastSignature = newSignature;
|
||||
validateSignature(signatureInput, pagesFromInput, pagesToInput);
|
||||
});
|
||||
|
||||
pagesFromInput.addEventListener('input', () => {
|
||||
const signature = signatureInput.value.trim();
|
||||
if (signature && signatureTracking[signature]) {
|
||||
checkSignatureThreshold(signature);
|
||||
}
|
||||
});
|
||||
|
||||
pagesToInput.addEventListener('input', () => {
|
||||
const signature = signatureInput.value.trim();
|
||||
if (signature && signatureTracking[signature]) {
|
||||
checkSignatureThreshold(signature);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function removeMediaSection(sectionId) {
|
||||
const section = document.getElementById(sectionId);
|
||||
if (section) {
|
||||
if (confirm('Möchten Sie diese Sektion wirklich entfernen?')) {
|
||||
const type = section.getAttribute('data-type');
|
||||
if (const rows = section.querySelectorAll('tr[id]');
|
||||
rows.forEach(row => {
|
||||
const signatureInput = row.querySelector('input[name*="_signature"]');
|
||||
if (signatureInput) {
|
||||
cleanupSignatureTracking(signatureInput);
|
||||
}
|
||||
});
|
||||
section.remove();
|
||||
const btn = document.getElementById('btn-' + type);
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.title = 'Sektion hinzufügen';
|
||||
}
|
||||
updateSubmitButton(); btn.disabled = false;
|
||||
btn.title = 'Sektion hinzufügen';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user