Fix sites freeze bug, add features and shorten README
Bug fixes: - UniFiController: add CURLOPT_TIMEOUT (10s) and CURLOPT_CONNECTTIMEOUT (5s) to login() and apiRequest() — prevents page freeze when controller unreachable - UniFiController: fix login response validation for UniFi OS API which returns a user object instead of meta.rc=ok - admin/sites.php: add JS loading state on form submit to give visual feedback - login.php: handle new 'rate_limited' return value from Auth::login() New features: - Database: in-memory settings cache eliminates redundant DB queries per request - Auth: login rate limiting (10 attempts per 10 min per IP/email) via login_attempts table - admin/vouchers.php: CSV export with UTF-8 BOM for Excel compatibility - admin/vouchers.php: client-side pagination (50 per page) - index.php: QR code display after voucher creation (qrcodejs CDN) - Mailer: sendTestEmail() method - admin/settings.php: SMTP test button with AJAX handler - database.sql: add login_attempts and audit_log tables Readme: condensed from ~420 to ~220 lines, removed duplicated sections, M365 Azure Portal walkthrough, contribution guidelines, update/migration section https://claude.ai/code/session_01UsuvFAmmeagtQa14QA4iaq
This commit is contained in:
parent
3fd9b2190a
commit
73967caefa
11 changed files with 460 additions and 450 deletions
35
index.php
35
index.php
|
|
@ -173,6 +173,9 @@ $autoSelectSite = (count($sites) === 1) ? $sites[0]['id'] : 0;
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= htmlspecialchars($appTitle) ?></title>
|
||||
<?php if ($voucherCreated): ?>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" integrity="sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSe2keRB6Q5pBUtIxCY7bQMsVB0ANBpd6JDg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<?php endif; ?>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
|
|
@ -431,6 +434,21 @@ $autoSelectSite = (count($sites) === 1) ? $sites[0]['id'] : 0;
|
|||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.qr-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 20px 0 0;
|
||||
}
|
||||
.qr-wrapper canvas, .qr-wrapper img {
|
||||
border: 6px solid white;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.qr-label {
|
||||
font-size: 12px;
|
||||
opacity: 0.8;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Print Styles */
|
||||
@media print {
|
||||
|
|
@ -492,6 +510,10 @@ $autoSelectSite = (count($sites) === 1) ? $sites[0]['id'] : 0;
|
|||
<div class="voucher-info">
|
||||
Der Code ist 8 Stunden ab Erstellung gültig
|
||||
</div>
|
||||
<div class="qr-wrapper no-print">
|
||||
<div id="qrcode"></div>
|
||||
<div class="qr-label">QR-Code scannen zum Verbinden</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($instructionHeader || $instructionText): ?>
|
||||
|
|
@ -603,6 +625,19 @@ $autoSelectSite = (count($sites) === 1) ? $sites[0]['id'] : 0;
|
|||
</div>
|
||||
|
||||
<script>
|
||||
<?php if ($voucherCreated): ?>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
new QRCode(document.getElementById('qrcode'), {
|
||||
text: '<?= addslashes($voucherCode) ?>',
|
||||
width: 160,
|
||||
height: 160,
|
||||
colorDark: '#ffffff',
|
||||
colorLight: 'transparent',
|
||||
correctLevel: QRCode.CorrectLevel.M
|
||||
});
|
||||
});
|
||||
<?php endif; ?>
|
||||
|
||||
function toggleEmailField() {
|
||||
const checkbox = document.getElementById('send_email');
|
||||
const emailField = document.getElementById('email_field');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue