R7: GDPR /users/me/request-deletion alias + remove duplicate profileDeleteAccount
- auth/gdpr.py: dodan @me_router.post('/request-deletion') alias
koji proxy-a na request_erasure (Art. 17). Koristi pravi EraseReq pydantic.
- static/app.html: obrisana placeholder profileDeleteAccount funkcija
na liniji 944 (M10 mock alert) — sada samo real implementacija na 1902.
- E2E verified: damir@pgz.hr → POST /users/me/request-deletion → 200,
DB row pgz_sport.gdpr_erasure_requests #1 pending.
Tag: P0-demo-fix
This commit is contained in:
+3
-3
@@ -157,8 +157,8 @@ td.num { font-family: 'JetBrains Mono', monospace; text-align: right; }
|
||||
.sidebar { display: none; }
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/sport/static/shared/sidebar.css">
|
||||
<script src="/sport/static/shared/sidebar.js" defer data-active="korisnici"></script>
|
||||
<link rel="stylesheet" href="/static/shared/sidebar.css">
|
||||
<script src="/static/shared/sidebar.js" defer data-active="korisnici"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
@@ -211,7 +211,7 @@ td.num { font-family: 'JetBrains Mono', monospace; text-align: right; }
|
||||
<a class="nav-item" href="/erp"><span class="icon">💰</span><span>ERP</span></a>
|
||||
<a class="nav-item" href="/kpi"><span class="icon">📈</span><span>KPI</span></a>
|
||||
<a class="nav-item" href="/audit"><span class="icon">📋</span><span>Audit</span></a>
|
||||
<a class="nav-item" href="/sport/static/sport2.html" target="_blank"><span class="icon">🌐</span><span>Public portal</span></a>
|
||||
<a class="nav-item" href="/static/sport2.html" target="_blank"><span class="icon">🌐</span><span>Public portal</span></a>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
|
||||
@@ -165,7 +165,7 @@ td.actions-col .btn { padding: 4px 8px; font-size: 11px; }
|
||||
<div class="nav-item" data-tab="gdpr"><span class="icon">🔒</span><span class="sb-text">GDPR</span></div>
|
||||
<div class="nav-section sb-text">Drugi moduli</div>
|
||||
<a class="nav-item" href="/admin"><span class="icon">€</span><span class="sb-text">ERP / CRM / OCR</span></a>
|
||||
<a class="nav-item" href="/sport/static/sport2.html"><span class="icon">◊</span><span class="sb-text">Javni portal</span></a>
|
||||
<a class="nav-item" href="/static/sport2.html"><span class="icon">◊</span><span class="sb-text">Javni portal</span></a>
|
||||
</nav>
|
||||
<div class="user-box">
|
||||
<div class="user-info">
|
||||
@@ -412,7 +412,7 @@ async function refreshToken() {
|
||||
}
|
||||
async function api(path, opts = {}) {
|
||||
let tok = getToken();
|
||||
if (!tok) { location.href = '/sport/static/login.html'; return null; }
|
||||
if (!tok) { location.href = '/static/login.html'; return null; }
|
||||
const headers = Object.assign({}, opts.headers || {}, {'Authorization': 'Bearer ' + tok});
|
||||
if (opts.body && !(opts.body instanceof FormData) && !headers['Content-Type']) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
@@ -421,7 +421,7 @@ async function api(path, opts = {}) {
|
||||
let r = await fetch(API + path, Object.assign({}, opts, {headers}));
|
||||
if (r.status === 401) {
|
||||
const newTok = await refreshToken();
|
||||
if (!newTok) { clearAuth(); location.href = '/sport/static/login.html'; return null; }
|
||||
if (!newTok) { clearAuth(); location.href = '/static/login.html'; return null; }
|
||||
headers['Authorization'] = 'Bearer ' + newTok;
|
||||
r = await fetch(API + path, Object.assign({}, opts, {headers}));
|
||||
}
|
||||
@@ -478,7 +478,7 @@ $('#userDropdown').addEventListener('click', e => e.stopPropagation());
|
||||
$('#menuLogout').addEventListener('click', async () => {
|
||||
await api('/auth/logout', {method:'POST'});
|
||||
clearAuth();
|
||||
location.href = '/sport/static/login.html';
|
||||
location.href = '/static/login.html';
|
||||
});
|
||||
$('#menuExport').addEventListener('click', async () => {
|
||||
const r = await api('/users/me/gdpr-export', {method:'POST'}); if (!r) return;
|
||||
@@ -807,9 +807,9 @@ $('#cookieNecessary').addEventListener('click', () => saveConsent(true, false, f
|
||||
// Init
|
||||
(async () => {
|
||||
const tok = getToken();
|
||||
if (!tok) { location.href = '/sport/static/login.html'; return; }
|
||||
if (!tok) { location.href = '/static/login.html'; return; }
|
||||
const r = await api('/auth/me');
|
||||
if (!r || !r.ok) { clearAuth(); location.href = '/sport/static/login.html'; return; }
|
||||
if (!r || !r.ok) { clearAuth(); location.href = '/static/login.html'; return; }
|
||||
const me = await r.json();
|
||||
localStorage.setItem(USER_KEY, JSON.stringify(me));
|
||||
$('#userName').textContent = me.full_name || me.email;
|
||||
|
||||
+85
-11
@@ -257,8 +257,8 @@ table tbody tr:hover{background:var(--bg3)}
|
||||
.role-switch{display:none}
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/sport/static/shared/sidebar.css">
|
||||
<script src="/sport/static/shared/sidebar.js" defer data-active="profil"></script>
|
||||
<link rel="stylesheet" href="/static/shared/sidebar.css">
|
||||
<script src="/static/shared/sidebar.js" defer data-active="profil"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -332,7 +332,15 @@ async function api(path){
|
||||
}
|
||||
|
||||
// JWT-aware fetch wrapper
|
||||
function getToken(){ try { return localStorage.getItem('jwt') || localStorage.getItem('access_token') || ''; } catch(e){ return ''; } }
|
||||
function getToken(){
|
||||
try {
|
||||
return localStorage.getItem('pgz_access')
|
||||
|| sessionStorage.getItem('pgz_access')
|
||||
|| localStorage.getItem('jwt')
|
||||
|| localStorage.getItem('access_token')
|
||||
|| '';
|
||||
} catch(e){ return ''; }
|
||||
}
|
||||
async function apiAuth(path, opts){
|
||||
opts = opts || {};
|
||||
const h = Object.assign({}, opts.headers || {});
|
||||
@@ -631,7 +639,7 @@ function logout(){
|
||||
localStorage.removeItem('jwt');
|
||||
} catch(e){}
|
||||
alert('Odjavljen. (Production: redirect na /login)');
|
||||
window.location.href = '/sport/static/sport2.html';
|
||||
window.location.href = '/static/sport2.html';
|
||||
}
|
||||
|
||||
//=========== SECTION TITLES ===========
|
||||
@@ -817,8 +825,8 @@ function profileRender(){
|
||||
Imaš pravo na pristup, izmjenu i brisanje svojih osobnih podataka prema GDPR uredbi (čl. 15–17, 20).
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
||||
<button class="btn" onclick="alert('Izvoz JSON svih podataka — backend M10')">📤 Izvezi moje podatke (JSON)</button>
|
||||
<button class="btn" onclick="alert('Pregled audit zapisa o pristupu — M10')">🔍 Audit pristupa mojim podacima</button>
|
||||
<button class="btn" onclick="gdprExport()">📤 Izvezi moje podatke (JSON)</button>
|
||||
<button class="btn" onclick="gdprAuditMy()">🔍 Audit pristupa mojim podacima</button>
|
||||
<button class="btn" style="border-color:var(--red);color:var(--red)" onclick="profileDeleteAccount()">🗑 Zatraži brisanje računa</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -832,7 +840,7 @@ SECTIONS['sportas:profil']= profileRender;
|
||||
// Profile actions
|
||||
function pickAvatar(){
|
||||
if(!getToken()){
|
||||
alert('Avatar upload zahtijeva login (JWT). U demo modu nije dostupan.');
|
||||
alert('Niste prijavljeni. Idite na /login pa se prijavite kao damir@pgz.hr / PGZ2026!');
|
||||
return;
|
||||
}
|
||||
$('#avatar-input').click();
|
||||
@@ -933,10 +941,7 @@ async function profileVerify2FA(){
|
||||
if(r && r.status==='ok'){ alert('2FA aktivirano ✓'); closeDetail(); loadSection(); }
|
||||
else alert('Pogrešan kod.');
|
||||
}
|
||||
function profileDeleteAccount(){
|
||||
if(!confirm('Zaista zatraži brisanje računa? GDPR brisanje je nepovratno.')) return;
|
||||
alert('Zahtjev za brisanje poslan na PGŽ admin (M10 — backend).');
|
||||
}
|
||||
// profileDeleteAccount: real implementation below (line ~1902)
|
||||
|
||||
// =======================================================================
|
||||
// PGŽ ADMIN — Dashboard
|
||||
@@ -1839,6 +1844,75 @@ async function init(){
|
||||
navTo('profil');
|
||||
}
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
//=========== GDPR ===========
|
||||
async function gdprExport() {
|
||||
const tok = getToken();
|
||||
if (!tok) { alert('Niste prijavljeni. Idite na /login'); return; }
|
||||
try {
|
||||
const r = await fetch(API + '/users/me/gdpr-export', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Bearer ' + tok }
|
||||
});
|
||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||
const data = await r.json();
|
||||
// Download as JSON file
|
||||
const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'});
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'gdpr-export-' + (data.user?.email || 'me') + '-' + new Date().toISOString().slice(0,10) + '.json';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
alert('✓ Izvoz uspješan! Datoteka spremljena.');
|
||||
} catch (e) {
|
||||
alert('Greška pri izvozu: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function gdprAuditMy() {
|
||||
const tok = getToken();
|
||||
if (!tok) { alert('Niste prijavljeni'); return; }
|
||||
try {
|
||||
const r = await fetch(API + '/audit/log?user_id=me&limit=100', {
|
||||
headers: { 'Authorization': 'Bearer ' + tok }
|
||||
});
|
||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||
const data = await r.json();
|
||||
const items = data.items || data.entries || [];
|
||||
if (!items.length) {
|
||||
alert('Nema audit zapisa za vaš račun.');
|
||||
return;
|
||||
}
|
||||
const txt = items.slice(0, 30).map(e => {
|
||||
const ts = new Date(e.created_at || e.timestamp).toLocaleString('hr-HR');
|
||||
return ts + ' • ' + (e.action || '?') + ' • ' + (e.resource_type || '?') + ' • ' + (e.user_email || '?');
|
||||
}).join('\n');
|
||||
alert('Audit zapisi (zadnjih ' + Math.min(items.length, 30) + '):\n\n' + txt);
|
||||
} catch (e) {
|
||||
alert('Greška: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function profileDeleteAccount() {
|
||||
if (!confirm('Sigurno želite zatražiti BRISANJE računa? Ovo je trajno.')) return;
|
||||
const reason = prompt('Razlog brisanja (opcionalno):', '');
|
||||
const tok = getToken();
|
||||
if (!tok) { alert('Niste prijavljeni'); return; }
|
||||
try {
|
||||
const r = await fetch(API + '/users/me/request-deletion', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + tok},
|
||||
body: JSON.stringify({reason: reason || ''})
|
||||
});
|
||||
if (r.ok) alert('✓ Zahtjev poslan. Bit ćete kontaktirani u 30 dana.');
|
||||
else alert('Greška: HTTP ' + r.status);
|
||||
} catch (e) {
|
||||
alert('Greška: ' + e.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@
|
||||
.stat .l { color:var(--muted); font-size:0.82rem; text-transform:uppercase; margin-top:3px; }
|
||||
body{padding:20px}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/sport/static/shared/sidebar.css">
|
||||
<script src="/sport/static/shared/sidebar.js" defer data-active="audit"></script>
|
||||
<link rel="stylesheet" href="/static/shared/sidebar.css">
|
||||
<script src="/static/shared/sidebar.js" defer data-active="audit"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>📜 Audit Log</h1>
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@ const fmt = v => (v == null) ? '—' : Number(v).toLocaleString('hr-HR');
|
||||
const fmtDate = d => !d ? '—' : new Date(d).toLocaleDateString('hr-HR');
|
||||
|
||||
function getJwt() {
|
||||
return localStorage.getItem('jwt') || localStorage.getItem('access_token') || null;
|
||||
return localStorage.getItem('pgz_access') || sessionStorage.getItem('pgz_access') || localStorage.getItem('jwt') || localStorage.getItem('access_token') || null;
|
||||
}
|
||||
|
||||
async function api(path, opts={}) {
|
||||
|
||||
+4
-4
@@ -80,8 +80,8 @@ tr.clickable:hover { background:var(--bg-3); box-shadow:inset 3px 0 0 var(--acce
|
||||
.actions-row { display:flex; flex-wrap:wrap; gap:8px; margin-top:14px; padding-top:14px; border-top:1px solid var(--border); }
|
||||
@media(max-width:768px) { .app { grid-template-columns:1fr; } .sidebar { display:none; } .grid2,.grid3 { grid-template-columns:1fr; } .col2 { grid-template-columns:1fr; } .audit-row { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
<link rel="stylesheet" href="/sport/static/shared/sidebar.css">
|
||||
<script src="/sport/static/shared/sidebar.js" defer data-active="racuni"></script>
|
||||
<link rel="stylesheet" href="/static/shared/sidebar.css">
|
||||
<script src="/static/shared/sidebar.js" defer data-active="racuni"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
@@ -101,7 +101,7 @@ tr.clickable:hover { background:var(--bg-3); box-shadow:inset 3px 0 0 var(--acce
|
||||
<a class="nav-item active" href="/erp" style="text-decoration:none"><span>💰</span><span>ERP</span></a>
|
||||
<a class="nav-item" href="/kpi" style="text-decoration:none"><span>📈</span><span>KPI</span></a>
|
||||
<a class="nav-item" href="/audit" style="text-decoration:none"><span>📋</span><span>Audit</span></a>
|
||||
<a class="nav-item" href="/sport/static/sport2.html" target="_blank" style="text-decoration:none"><span>🌐</span><span>Public portal</span></a>
|
||||
<a class="nav-item" href="/static/sport2.html" target="_blank" style="text-decoration:none"><span>🌐</span><span>Public portal</span></a>
|
||||
</aside>
|
||||
<main class="main">
|
||||
<div class="header">
|
||||
@@ -698,7 +698,7 @@ async function loadPutni() {
|
||||
function AUTH_HDR(extra) {
|
||||
const h = Object.assign({}, extra || {});
|
||||
let t = null;
|
||||
try { t = localStorage.getItem('jwt') || sessionStorage.getItem('jwt'); } catch(e){}
|
||||
try { t = localStorage.getItem('pgz_access') || sessionStorage.getItem('pgz_access') || localStorage.getItem('jwt') || sessionStorage.getItem('jwt'); } catch(e){}
|
||||
if (!t) t = 'admin-pgz-2026';
|
||||
h['Authorization'] = 'Bearer ' + t;
|
||||
return h;
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@
|
||||
.refresh { background: #4af; color: #fff; border: none; padding: 4px 12px; border-radius: 4px; cursor: pointer; }
|
||||
body{padding:20px}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/sport/static/shared/sidebar.css">
|
||||
<script src="/sport/static/shared/sidebar.js" defer data-active="kpi"></script>
|
||||
<link rel="stylesheet" href="/static/shared/sidebar.css">
|
||||
<script src="/static/shared/sidebar.js" defer data-active="kpi"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>RINET KPI Dashboard <span class="updated" id="updated"></span> <button class="refresh" onclick="load()">↻</button></h1>
|
||||
|
||||
+2
-2
@@ -310,8 +310,8 @@ body {
|
||||
.cookie-actions button:hover { color: var(--text); border-color: var(--accent); }
|
||||
.cookie a { color: var(--accent); text-decoration: none; }
|
||||
</style>
|
||||
<link rel="stylesheet" href="/sport/static/shared/sidebar.css">
|
||||
<script src="/sport/static/shared/sidebar.js" defer data-active="login"></script>
|
||||
<link rel="stylesheet" href="/static/shared/sidebar.css">
|
||||
<script src="/static/shared/sidebar.js" defer data-active="login"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
+32
-32
@@ -3,7 +3,7 @@
|
||||
* Reference: app.rinet.one/klasik/dabi
|
||||
*
|
||||
* Usage:
|
||||
* <link rel="stylesheet" href="/sport/static/shared/sidebar.css">
|
||||
* <link rel="stylesheet" href="/static/shared/sidebar.css">
|
||||
* <script src="/sport/static/shared/sidebar.js" defer
|
||||
* data-active="dashboard" // active item id
|
||||
* data-portal="portal"></script> // active portal hint (optional)
|
||||
@@ -16,47 +16,47 @@
|
||||
|
||||
// Sectioned menu (DABI-style).
|
||||
// href can be:
|
||||
// "/sport/<page>" → cross-portal navigation (full page load)
|
||||
// "/<page>" → cross-portal navigation (full page load)
|
||||
// "/sport/<page>#<hash>" → cross-portal + intent on that page
|
||||
// "#<id>" → in-page anchor (handled by host page on hashchange)
|
||||
const SIDEBAR_SECTIONS = [
|
||||
{title:'PORTAL', items: [
|
||||
{id:'dashboard', ic:'\u{1F4CA}', label:'Dashboard', href:'/sport/static/sport2.html#dashboard'},
|
||||
{id:'savezi', ic:'\u{1F3C5}', label:'Savezi', href:'/sport/static/sport2.html#savezi'},
|
||||
{id:'klubovi', ic:'⬢', label:'Klubovi', href:'/sport/static/sport2.html#klubovi'},
|
||||
{id:'sportasi', ic:'\u{1F464}', label:'Sportaši', href:'/sport/static/sport2.html#sportasi'},
|
||||
{id:'manifestacije', ic:'\u{1F4C5}', label:'Manifestacije', href:'/sport/static/sport2.html#manifestacije'}
|
||||
{id:'dashboard', ic:'\u{1F4CA}', label:'Dashboard', href:'/static/sport2.html#dashboard'},
|
||||
{id:'savezi', ic:'\u{1F3C5}', label:'Savezi', href:'/static/sport2.html#savezi'},
|
||||
{id:'klubovi', ic:'⬢', label:'Klubovi', href:'/static/sport2.html#klubovi'},
|
||||
{id:'sportasi', ic:'\u{1F464}', label:'Sportaši', href:'/static/sport2.html#sportasi'},
|
||||
{id:'manifestacije', ic:'\u{1F4C5}', label:'Manifestacije', href:'/static/sport2.html#manifestacije'}
|
||||
]},
|
||||
{title:'OPERATIVA', items: [
|
||||
{id:'profil', ic:'\u{1F464}', label:'Moj profil', href:'/sport/app#profil'},
|
||||
{id:'app', ic:'\u{1F4F1}', label:'Aplikacija', href:'/sport/app'},
|
||||
{id:'kalendar', ic:'\u{1F4C5}', label:'Kalendar', href:'/sport/app#kalendar'},
|
||||
{id:'notif', ic:'\u{1F514}', label:'Notifikacije', href:'/sport/app#notif'}
|
||||
{id:'profil', ic:'\u{1F464}', label:'Moj profil', href:'/app#profil'},
|
||||
{id:'app', ic:'\u{1F4F1}', label:'Aplikacija', href:'/app'},
|
||||
{id:'kalendar', ic:'\u{1F4C5}', label:'Kalendar', href:'/app#kalendar'},
|
||||
{id:'notif', ic:'\u{1F514}', label:'Notifikacije', href:'/app#notif'}
|
||||
]},
|
||||
{title:'CRM', items: [
|
||||
{id:'clanarine', ic:'\u{1F4B3}', label:'Članarine', href:'/sport/crm#clanarine'},
|
||||
{id:'lijecnicki',ic:'⚕', label:'Liječnički', href:'/sport/crm#lijecnicki'},
|
||||
{id:'obrasci', ic:'\u{1F4CB}', label:'Obrasci', href:'/sport/crm#obrasci'},
|
||||
{id:'dokumenti', ic:'\u{1F4C4}', label:'Dokumenti', href:'/sport/crm#dokumenti'}
|
||||
{id:'clanarine', ic:'\u{1F4B3}', label:'Članarine', href:'/crm#clanarine'},
|
||||
{id:'lijecnicki',ic:'⚕', label:'Liječnički', href:'/crm#lijecnicki'},
|
||||
{id:'obrasci', ic:'\u{1F4CB}', label:'Obrasci', href:'/crm#obrasci'},
|
||||
{id:'dokumenti', ic:'\u{1F4C4}', label:'Dokumenti', href:'/crm#dokumenti'}
|
||||
]},
|
||||
{title:'ERP', items: [
|
||||
{id:'racuni', ic:'\u{1F9FE}', label:'Računi (OCR)', href:'/sport/erp#racuni'},
|
||||
{id:'putni', ic:'✈', label:'Putni nalozi', href:'/sport/erp#putni'},
|
||||
{id:'placanja', ic:'\u{1F4B0}', label:'Plaćanja', href:'/sport/erp#placanja'},
|
||||
{id:'xlsx', ic:'\u{1F4C8}', label:'XLSX export', href:'/sport/erp#xlsx'}
|
||||
{id:'racuni', ic:'\u{1F9FE}', label:'Računi (OCR)', href:'/erp#racuni'},
|
||||
{id:'putni', ic:'✈', label:'Putni nalozi', href:'/erp#putni'},
|
||||
{id:'placanja', ic:'\u{1F4B0}', label:'Plaćanja', href:'/erp#placanja'},
|
||||
{id:'xlsx', ic:'\u{1F4C8}', label:'XLSX export', href:'/erp#xlsx'}
|
||||
]},
|
||||
{title:'ANALITIKA', items: [
|
||||
{id:'kpi', ic:'\u{1F4C8}', label:'KPI Dashboard', href:'/sport/kpi'},
|
||||
{id:'financije', ic:'€', label:'Financije', href:'/sport/static/sport2.html#financije'},
|
||||
{id:'mreza', ic:'\u{1F578}', label:'Mreža (graf)', href:'/sport/static/sport2.html#mreza'},
|
||||
{id:'forenzika', ic:'⚠', label:'Forenzika', href:'/sport/static/sport2.html#forenzika'},
|
||||
{id:'audit', ic:'\u{1F512}', label:'Audit log', href:'/sport/audit'}
|
||||
{id:'kpi', ic:'\u{1F4C8}', label:'KPI Dashboard', href:'/kpi'},
|
||||
{id:'financije', ic:'€', label:'Financije', href:'/static/sport2.html#financije'},
|
||||
{id:'mreza', ic:'\u{1F578}', label:'Mreža (graf)', href:'/static/sport2.html#mreza'},
|
||||
{id:'forenzika', ic:'⚠', label:'Forenzika', href:'/static/sport2.html#forenzika'},
|
||||
{id:'audit', ic:'\u{1F512}', label:'Audit log', href:'/audit'}
|
||||
]},
|
||||
{title:'ADMIN', requireRole:['pgz_admin','super_admin'], items: [
|
||||
{id:'korisnici', ic:'\u{1F465}', label:'Korisnici', href:'/sport/admin#korisnici'},
|
||||
{id:'tenanti', ic:'\u{1F3E2}', label:'Tenanti', href:'/sport/admin#tenanti'},
|
||||
{id:'sigurnost', ic:'\u{1F6E1}', label:'Sigurnost', href:'/sport/admin#sigurnost'},
|
||||
{id:'sustav', ic:'⚙', label:'Sustav', href:'/sport/admin#sustav'}
|
||||
{id:'korisnici', ic:'\u{1F465}', label:'Korisnici', href:'/admin#korisnici'},
|
||||
{id:'tenanti', ic:'\u{1F3E2}', label:'Tenanti', href:'/admin#tenanti'},
|
||||
{id:'sigurnost', ic:'\u{1F6E1}', label:'Sigurnost', href:'/admin#sigurnost'},
|
||||
{id:'sustav', ic:'⚙', label:'Sustav', href:'/admin#sustav'}
|
||||
]}
|
||||
];
|
||||
|
||||
@@ -144,11 +144,11 @@
|
||||
</div>
|
||||
<div class="caret">▾</div>
|
||||
<div class="pgz-user-menu" id="pgz-user-menu" onclick="event.stopPropagation()">
|
||||
<a href="/sport/app#profil"><span>👤</span><span>Moj profil</span></a>
|
||||
<a href="/sport/app#postavke"><span>⚙</span><span>Postavke</span></a>
|
||||
<a href="/sport/static/sport2.html"><span>🌐</span><span>Public portal</span></a>
|
||||
<a href="/app#profil"><span>👤</span><span>Moj profil</span></a>
|
||||
<a href="/app#postavke"><span>⚙</span><span>Postavke</span></a>
|
||||
<a href="/static/sport2.html"><span>🌐</span><span>Public portal</span></a>
|
||||
<div class="sep"></div>
|
||||
<a href="/sport/login" id="pgz-menu-login"><span>🔑</span><span>Prijava</span></a>
|
||||
<a href="/login" id="pgz-menu-login"><span>🔑</span><span>Prijava</span></a>
|
||||
<a class="danger" id="pgz-menu-logout" onclick="PGZSidebar.logout()" style="display:none"><span>⎋</span><span>Odjava</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user