Add public availability API and settings panel

Public saatavuus endpoint with API key + CORS protection for
cuitunet.fi website integration. Admin settings tab for API key
management and testing. Includes standalone widget page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 01:50:52 +02:00
parent 8ba925d3dc
commit 14707b9616
5 changed files with 341 additions and 0 deletions

View File

@@ -169,6 +169,7 @@ async function showDashboard() {
document.getElementById('user-info').textContent = currentUser.nimi || currentUser.username;
// Näytä Käyttäjät-tab vain adminille
document.getElementById('tab-users').style.display = currentUser.role === 'admin' ? '' : 'none';
document.getElementById('tab-settings').style.display = currentUser.role === 'admin' ? '' : 'none';
await loadCustomers();
}
@@ -186,6 +187,7 @@ document.querySelectorAll('.tab').forEach(tab => {
if (target === 'archive') loadArchive();
if (target === 'changelog') loadChangelog();
if (target === 'users') loadUsers();
if (target === 'settings') loadSettings();
});
});
@@ -818,6 +820,7 @@ const actionLabels = {
lead_update: 'Muokkasi liidiä',
lead_delete: 'Poisti liidin',
lead_to_customer: 'Muutti liidin asiakkaaksi',
config_update: 'Päivitti asetukset',
};
async function loadChangelog() {
@@ -917,6 +920,52 @@ document.getElementById('user-form').addEventListener('submit', async (e) => {
} catch (e) { alert(e.message); }
});
// ==================== SETTINGS ====================
async function loadSettings() {
try {
const config = await apiCall('config');
document.getElementById('settings-api-key').value = config.api_key || '';
document.getElementById('settings-cors').value = (config.cors_origins || ['https://cuitunet.fi', 'https://www.cuitunet.fi']).join('\n');
const key = config.api_key || 'AVAIN';
document.getElementById('api-example-url').textContent = `api.php?action=saatavuus&key=${key}&osoite=Kauppakatu+5`;
} catch (e) { console.error(e); }
}
document.getElementById('btn-generate-key').addEventListener('click', async () => {
try {
const config = await apiCall('generate_api_key', 'POST');
document.getElementById('settings-api-key').value = config.api_key || '';
document.getElementById('api-example-url').textContent = `api.php?action=saatavuus&key=${config.api_key}&osoite=Kauppakatu+5`;
} catch (e) { alert(e.message); }
});
document.getElementById('btn-save-settings').addEventListener('click', async () => {
try {
const config = await apiCall('config_update', 'POST', {
api_key: document.getElementById('settings-api-key').value,
cors_origins: document.getElementById('settings-cors').value,
});
alert('Asetukset tallennettu!');
} catch (e) { alert(e.message); }
});
document.getElementById('btn-test-api').addEventListener('click', async () => {
const address = document.getElementById('test-api-address').value.trim();
const apiKey = document.getElementById('settings-api-key').value;
if (!address) { alert('Anna osoite tai postinumero'); return; }
const result = document.getElementById('test-api-result');
result.style.display = 'block';
result.textContent = 'Haetaan...';
try {
const isZip = /^\d{5}$/.test(address);
const param = isZip ? `postinumero=${encodeURIComponent(address)}` : `osoite=${encodeURIComponent(address)}`;
const res = await fetch(`${API}?action=saatavuus&key=${encodeURIComponent(apiKey)}&${param}`);
const data = await res.json();
result.textContent = JSON.stringify(data, null, 2);
} catch (e) { result.textContent = 'Virhe: ' + e.message; }
});
// ==================== MODALS ====================
customerModal.addEventListener('click', (e) => { if (e.target === customerModal) customerModal.style.display = 'none'; });