Extend public upload with personal friendship codes

This commit is contained in:
Terranom674
2026-09-05 17:29:44 +02:00
parent 839683a260
commit a0fa4dfd1a

View File

@@ -15,6 +15,7 @@ if (!defined('BRATONIEN_TOOLS_PATH'))
} }
require_once(BRATONIEN_TOOLS_PATH.'include/customer_qr_upload.inc.php'); require_once(BRATONIEN_TOOLS_PATH.'include/customer_qr_upload.inc.php');
require_once(BRATONIEN_TOOLS_PATH.'include/friendship_code_upload.inc.php');
$settings = bratonien_tools_customer_qr_settings(); $settings = bratonien_tools_customer_qr_settings();
if (empty($settings['enabled'])) if (empty($settings['enabled']))
@@ -26,9 +27,11 @@ if (empty($settings['enabled']))
} }
bratonien_tools_customer_qr_ensure_storage(); bratonien_tools_customer_qr_ensure_storage();
bratonien_tools_friendship_code_ensure_storage();
$year_limits = bratonien_tools_customer_qr_year_limits(); $year_limits = bratonien_tools_customer_qr_year_limits();
$action = (string)($_GET['action'] ?? '');
if ((string)($_GET['action'] ?? '') === 'check') if ($action === 'check')
{ {
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, max-age=0'); header('Cache-Control: no-store, max-age=0');
@@ -57,10 +60,37 @@ if ((string)($_GET['action'] ?? '') === 'check')
exit; exit;
} }
if ($action === 'check_friendship')
{
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, max-age=0');
try
{
$name = bratonien_tools_friendship_code_name($_GET['name'] ?? '');
$exists = bratonien_tools_friendship_code_exists_for_name($name);
echo json_encode(array(
'ok' => true,
'available' => !$exists,
'name' => $name,
'message' => $exists
? 'Für diesen Namen ist bereits ein Freundschaftscode hinterlegt.'
: 'Für diesen Namen kann ein Freundschaftscode hinterlegt werden.',
), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
catch (Throwable $e)
{
http_response_code(400);
echo json_encode(array('ok' => false, 'message' => $e->getMessage()), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') if ($_SERVER['REQUEST_METHOD'] === 'POST')
{ {
$results = array(); $results = array();
$year = bratonien_tools_customer_qr_default_year(); $year = bratonien_tools_customer_qr_default_year();
$upload_type = (string)($_POST['upload_type'] ?? 'qr');
try try
{ {
@@ -78,24 +108,40 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST')
check_pwg_token(); check_pwg_token();
} }
$year = bratonien_tools_customer_qr_year($_POST['upload_year'] ?? ''); if ($upload_type === 'friendship')
if (empty($_FILES['qr_files']))
{ {
throw new RuntimeException('Es wurden keine QR-Code-Dateien ausgewählt.'); $name = bratonien_tools_friendship_code_name($_POST['friend_name'] ?? '');
if (empty($_FILES['friend_file']))
{
throw new RuntimeException('Es wurde keine Freundschaftscode-Datei ausgewählt.');
}
$results[] = bratonien_tools_friendship_code_process_upload($name, $_FILES['friend_file']);
} }
else
{
$upload_type = 'qr';
$year = bratonien_tools_customer_qr_year($_POST['upload_year'] ?? '');
$numbers = isset($_POST['qr_numbers']) && is_array($_POST['qr_numbers']) if (empty($_FILES['qr_files']))
? array_values($_POST['qr_numbers']) {
: array(); throw new RuntimeException('Es wurden keine QR-Code-Dateien ausgewählt.');
}
$results = bratonien_tools_customer_qr_process_uploads($year, $_FILES['qr_files'], $numbers); $numbers = isset($_POST['qr_numbers']) && is_array($_POST['qr_numbers'])
? array_values($_POST['qr_numbers'])
: array();
$results = bratonien_tools_customer_qr_process_uploads($year, $_FILES['qr_files'], $numbers);
}
} }
catch (Throwable $e) catch (Throwable $e)
{ {
$results[] = array( $results[] = array(
'status' => 'error', 'status' => 'error',
'kind' => $upload_type === 'friendship' ? 'friendship' : 'qr',
'file' => '', 'file' => '',
'name' => $upload_type === 'friendship' ? trim((string)($_POST['friend_name'] ?? '')) : '',
'year' => $year, 'year' => $year,
'number' => '', 'number' => '',
'message' => $e->getMessage(), 'message' => $e->getMessage(),
@@ -103,6 +149,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST')
} }
$_SESSION['bratonien_customer_qr_flash'] = array( $_SESSION['bratonien_customer_qr_flash'] = array(
'type' => $upload_type,
'year' => $year, 'year' => $year,
'results' => $results, 'results' => $results,
); );
@@ -169,18 +216,25 @@ header('Cache-Control: no-store, max-age=0');
<main> <main>
<header> <header>
<h1>QR-Code Upload</h1> <h1>QR-Code Upload</h1>
<p class="muted">Lade einen oder mehrere QR-Codes hoch und ordne jedem Code eine eindeutige Nummer zu.</p> <p class="muted">QR-Codes und persönliche Freundschaftscodes hochladen.</p>
</header> </header>
<?php if (!empty($results)): ?> <?php if (!empty($results)): ?>
<section class="card" aria-labelledby="upload-result-title"> <section class="card" aria-labelledby="upload-result-title">
<h2 id="upload-result-title">Ergebnis</h2> <h2 id="upload-result-title">Ergebnis</h2>
<?php foreach ($results as $result): ?> <?php foreach ($results as $result): ?>
<?php $status = in_array(($result['status'] ?? ''), array('ok','duplicate','error'), true) ? $result['status'] : 'error'; ?> <?php
$status = in_array(($result['status'] ?? ''), array('ok','duplicate','error'), true) ? $result['status'] : 'error';
$kind = (string)($result['kind'] ?? 'qr');
if ($status === 'ok') $headline = 'Gespeichert';
elseif ($status === 'duplicate') $headline = $kind === 'friendship' ? 'Nicht gespeichert: bereits vorhanden' : 'Nicht gespeichert: Nummer bereits vergeben';
else $headline = 'Nicht gespeichert';
?>
<div class="result <?php echo htmlspecialchars($status, ENT_QUOTES, 'UTF-8'); ?>"> <div class="result <?php echo htmlspecialchars($status, ENT_QUOTES, 'UTF-8'); ?>">
<strong><?php echo $status === 'ok' ? 'Gespeichert' : ($status === 'duplicate' ? 'Nicht gespeichert: Nummer bereits vergeben' : 'Nicht gespeichert'); ?></strong> <strong><?php echo htmlspecialchars($headline, ENT_QUOTES, 'UTF-8'); ?></strong>
<?php if (!empty($result['file'])): ?><div><?php echo htmlspecialchars($result['file'], ENT_QUOTES, 'UTF-8'); ?></div><?php endif; ?> <?php if (!empty($result['file'])): ?><div><?php echo htmlspecialchars($result['file'], ENT_QUOTES, 'UTF-8'); ?></div><?php endif; ?>
<?php if (!empty($result['number'])): ?><div class="meta">Jahr <?php echo (int)$result['year']; ?> · QR-Code #<?php echo htmlspecialchars($result['number'], ENT_QUOTES, 'UTF-8'); ?></div><?php endif; ?> <?php if ($kind === 'friendship' && !empty($result['name'])): ?><div class="meta">Name: <?php echo htmlspecialchars($result['name'], ENT_QUOTES, 'UTF-8'); ?></div><?php endif; ?>
<?php if ($kind !== 'friendship' && !empty($result['number'])): ?><div class="meta">Jahr <?php echo (int)$result['year']; ?> · QR-Code #<?php echo htmlspecialchars($result['number'], ENT_QUOTES, 'UTF-8'); ?></div><?php endif; ?>
<div class="meta"><?php echo htmlspecialchars((string)($result['message'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></div> <div class="meta"><?php echo htmlspecialchars((string)($result['message'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></div>
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>
@@ -189,6 +243,8 @@ header('Cache-Control: no-store, max-age=0');
<form class="card" method="post" enctype="multipart/form-data" id="qr-upload-form" novalidate> <form class="card" method="post" enctype="multipart/form-data" id="qr-upload-form" novalidate>
<input type="hidden" name="pwg_token" value="<?php echo htmlspecialchars($token, ENT_QUOTES, 'UTF-8'); ?>"> <input type="hidden" name="pwg_token" value="<?php echo htmlspecialchars($token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="upload_type" value="qr">
<h2>QR-Code</h2>
<div class="grid"> <div class="grid">
<label for="upload-year">Jahr</label> <label for="upload-year">Jahr</label>
@@ -215,6 +271,31 @@ header('Cache-Control: no-store, max-age=0');
<span class="muted">Eine Nummer kann innerhalb eines Jahres nur einmal verwendet werden.</span> <span class="muted">Eine Nummer kann innerhalb eines Jahres nur einmal verwendet werden.</span>
</div> </div>
</form> </form>
<form class="card" method="post" enctype="multipart/form-data" id="friendship-upload-form" novalidate>
<input type="hidden" name="pwg_token" value="<?php echo htmlspecialchars($token, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="upload_type" value="friendship">
<h2>Persönlicher Freundschaftscode</h2>
<div class="grid">
<label for="friend-name">Name</label>
<div class="control">
<input id="friend-name" name="friend_name" type="text" maxlength="120" autocomplete="name" required>
<div id="friend-name-status" class="status" style="margin-top:6px">Bitte Namen eingeben.</div>
</div>
<label for="friend-file">Freundschaftscode</label>
<div class="control">
<input id="friend-file" name="friend_file" type="file" accept="image/png,image/jpeg,image/webp,image/gif" required>
<div class="muted" style="margin-top:6px">Ein Bild pro Person. PNG, JPG, WEBP oder GIF.</div>
</div>
</div>
<div class="actions">
<button id="friend-submit-button" type="submit" disabled>Freundschaftscode hochladen</button>
<span class="muted">Pro Name wird genau ein persönlicher Freundschaftscode gespeichert.</span>
</div>
</form>
</main> </main>
<script> <script>
@@ -327,6 +408,55 @@ header('Cache-Control: no-store, max-age=0');
else{submit.disabled=true;submit.textContent='Upload läuft …';} else{submit.disabled=true;submit.textContent='Upload läuft …';}
}); });
})(); })();
(function(){
'use strict';
var form=document.getElementById('friendship-upload-form');
var nameInput=document.getElementById('friend-name');
var fileInput=document.getElementById('friend-file');
var status=document.getElementById('friend-name-status');
var submit=document.getElementById('friend-submit-button');
var endpoint=<?php echo json_encode($endpoint, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); ?>;
var timer=null;
var nameValid=false;
function updateSubmit(){
submit.disabled=!nameValid||!fileInput.files||fileInput.files.length!==1;
}
function setStatus(text,kind){
status.textContent=text;
status.className='status'+(kind?' '+kind:'');
nameValid=kind==='ok';
updateSubmit();
}
function checkName(){
var name=String(nameInput.value||'').trim().replace(/\s+/g,' ');
if(!name){setStatus('Bitte Namen eingeben.','bad');return;}
setStatus('Name wird geprüft …','wait');
var url=endpoint+'?action=check_friendship&name='+encodeURIComponent(name)+'&_='+Date.now();
fetch(url,{credentials:'same-origin',cache:'no-store',headers:{'Accept':'application/json'}})
.then(function(response){return response.json().then(function(data){return {response:response,data:data};});})
.then(function(result){
if(!result.response.ok||!result.data.ok)throw new Error(result.data.message||'Prüfung fehlgeschlagen.');
if(result.data.available)setStatus(result.data.message,'ok');
else setStatus(result.data.message,'bad');
})
.catch(function(error){setStatus(error.message||'Prüfung fehlgeschlagen.','bad');});
}
nameInput.addEventListener('input',function(){
nameValid=false;updateSubmit();
if(timer)window.clearTimeout(timer);
timer=window.setTimeout(checkName,250);
});
fileInput.addEventListener('change',updateSubmit);
form.addEventListener('submit',function(event){
if(!nameValid||!fileInput.files||fileInput.files.length!==1){event.preventDefault();checkName();return;}
submit.disabled=true;submit.textContent='Upload läuft …';
});
})();
</script> </script>
</body> </body>
</html> </html>