Changelog: Build-Zeitpunkt als Timestamp, Benutzer ausblenden Toggle
This commit is contained in:
@@ -252,6 +252,8 @@ if (!userCols2.includes('preferences'))
|
|||||||
db.exec("ALTER TABLE users ADD COLUMN preferences TEXT DEFAULT NULL");
|
db.exec("ALTER TABLE users ADD COLUMN preferences TEXT DEFAULT NULL");
|
||||||
if (!userCols2.includes('last_active_at'))
|
if (!userCols2.includes('last_active_at'))
|
||||||
db.exec("ALTER TABLE users ADD COLUMN last_active_at DATETIME DEFAULT NULL");
|
db.exec("ALTER TABLE users ADD COLUMN last_active_at DATETIME DEFAULT NULL");
|
||||||
|
if (!userCols2.includes('hidden'))
|
||||||
|
db.exec("ALTER TABLE users ADD COLUMN hidden INTEGER NOT NULL DEFAULT 0");
|
||||||
|
|
||||||
// ── Login-Sicherheit ──────────────────────────────────────────────────────────
|
// ── Login-Sicherheit ──────────────────────────────────────────────────────────
|
||||||
// Spalten für Account-Lockout in users-Tabelle
|
// Spalten für Account-Lockout in users-Tabelle
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ router.post('/restore', authenticate, requireAdmin, upload.single('database'), (
|
|||||||
// GET /api/admin/users – alle Benutzer mit Statistiken
|
// GET /api/admin/users – alle Benutzer mit Statistiken
|
||||||
router.get('/users', authenticate, requireAdmin, (req, res) => {
|
router.get('/users', authenticate, requireAdmin, (req, res) => {
|
||||||
const users = db.prepare(`
|
const users = db.prepare(`
|
||||||
SELECT u.id, u.username, u.role, u.created_at, u.last_active_at,
|
SELECT u.id, u.username, u.role, u.created_at, u.last_active_at, u.hidden,
|
||||||
CASE WHEN p.user_id IS NOT NULL THEN 1 ELSE 0 END as has_pushover
|
CASE WHEN p.user_id IS NOT NULL THEN 1 ELSE 0 END as has_pushover
|
||||||
FROM users u
|
FROM users u
|
||||||
LEFT JOIN pushover_settings p ON p.user_id = u.id
|
LEFT JOIN pushover_settings p ON p.user_id = u.id
|
||||||
@@ -160,4 +160,13 @@ router.get('/login-log', authenticate, requireAdmin, (req, res) => {
|
|||||||
`).all());
|
`).all());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Toggle hidden
|
||||||
|
router.put('/users/:id/hidden', authenticate, requireAdmin, (req, res) => {
|
||||||
|
const user = db.prepare('SELECT * FROM users WHERE id=?').get(req.params.id);
|
||||||
|
if (!user) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||||
|
const newHidden = user.hidden ? 0 : 1;
|
||||||
|
db.prepare('UPDATE users SET hidden=? WHERE id=?').run(newHidden, user.id);
|
||||||
|
res.json({ hidden: newHidden });
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -1259,7 +1259,7 @@ function ChangelogModal({ user, toast, onClose }) {
|
|||||||
</div>
|
</div>
|
||||||
<div style={{display:'flex',alignItems:'center',gap:6,flexShrink:0}}>
|
<div style={{display:'flex',alignItems:'center',gap:6,flexShrink:0}}>
|
||||||
<span style={{color:'rgba(255,255,255,0.2)',fontFamily:'monospace',fontSize:9}}>
|
<span style={{color:'rgba(255,255,255,0.2)',fontFamily:'monospace',fontSize:9}}>
|
||||||
{fmtDate(e.created_at)}
|
{typeof __BUILD_TIME__ !== 'undefined' && __BUILD_TIME__ ? __BUILD_TIME__ : fmtDate(e.created_at)}
|
||||||
</span>
|
</span>
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<button onClick={()=>del(e.id)}
|
<button onClick={()=>del(e.id)}
|
||||||
@@ -1681,6 +1681,15 @@ function UserManagement({ toast }) {
|
|||||||
borderRadius:4, padding:'1px 6px',
|
borderRadius:4, padding:'1px 6px',
|
||||||
}}>🔔 Push</span>
|
}}>🔔 Push</span>
|
||||||
)}
|
)}
|
||||||
|
{!!u.hidden && (
|
||||||
|
<span title="Für andere Benutzer unsichtbar" style={{
|
||||||
|
marginLeft:4, fontSize:9, fontFamily:'monospace',
|
||||||
|
color:'rgba(255,230,109,0.7)',
|
||||||
|
background:'rgba(255,230,109,0.08)',
|
||||||
|
border:'1px solid rgba(255,230,109,0.2)',
|
||||||
|
borderRadius:4, padding:'1px 6px',
|
||||||
|
}}>👁 versteckt</span>
|
||||||
|
)}
|
||||||
{u.last_active_at && (
|
{u.last_active_at && (
|
||||||
<span style={{
|
<span style={{
|
||||||
marginLeft:6, fontSize:9, fontFamily:'monospace',
|
marginLeft:6, fontSize:9, fontFamily:'monospace',
|
||||||
@@ -1701,6 +1710,20 @@ function UserManagement({ toast }) {
|
|||||||
<div style={{display:'flex',gap:5}}>
|
<div style={{display:'flex',gap:5}}>
|
||||||
<button onClick={()=>{setResetId(u.id);setResetPw('');}}
|
<button onClick={()=>{setResetId(u.id);setResetPw('');}}
|
||||||
style={{...S.btn('#ffe66d',true),fontSize:10}}>🔑 PW</button>
|
style={{...S.btn('#ffe66d',true),fontSize:10}}>🔑 PW</button>
|
||||||
|
<button
|
||||||
|
onClick={async ()=>{
|
||||||
|
try {
|
||||||
|
const r = await api(`/admin/users/${u.id}/hidden`,{method:'PUT'});
|
||||||
|
setUsers(p=>p.map(x=>x.id===u.id?{...x,hidden:r.hidden}:x));
|
||||||
|
toast(r.hidden ? 'Benutzer ausgeblendet' : 'Benutzer wieder sichtbar');
|
||||||
|
} catch(e){ toast(e.message,'error'); }
|
||||||
|
}}
|
||||||
|
title={u.hidden ? 'Für andere Benutzer unsichtbar – klicken zum Einblenden' : 'Für andere Benutzer sichtbar – klicken zum Ausblenden'}
|
||||||
|
style={{...S.btn(u.hidden?'#ffe66d':'rgba(255,255,255,0.3)',true),fontSize:10,
|
||||||
|
opacity: u.role==='admin'?0.4:1,
|
||||||
|
cursor: u.role==='admin'?'not-allowed':'pointer'}}>
|
||||||
|
{u.hidden ? '👁 einblenden' : '👁 ausblenden'}
|
||||||
|
</button>
|
||||||
<button onClick={()=>del(u.id)} style={{...S.btn('#ff6b9d',true)}}>
|
<button onClick={()=>del(u.id)} style={{...S.btn('#ff6b9d',true)}}>
|
||||||
<TrashIcon size={13} color="#ff6b9d"/>
|
<TrashIcon size={13} color="#ff6b9d"/>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user