Whiteboard: Name beim Erstellen eingeben, Pushover bei neuen Berechtigungen
This commit is contained in:
@@ -125,7 +125,7 @@ router.get('/users-list', authenticate, (req, res) => {
|
||||
});
|
||||
|
||||
// ── Berechtigungen setzen ─────────────────────────────────────────────────────
|
||||
router.put('/:id/permissions', authenticate, (req, res) => {
|
||||
router.put('/:id/permissions', authenticate, async (req, res) => {
|
||||
const me = uid(req);
|
||||
const wb = db.prepare('SELECT * FROM whiteboards WHERE id=?').get(req.params.id);
|
||||
if (!wb) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||
@@ -133,16 +133,41 @@ router.put('/:id/permissions', authenticate, (req, res) => {
|
||||
const { permissions } = req.body; // [{user_id, role: 'edit'|'view'|null}]
|
||||
if (!Array.isArray(permissions)) return res.status(400).json({ error: 'permissions fehlt' });
|
||||
|
||||
const upsert = db.prepare("INSERT INTO whiteboard_permissions (whiteboard_id,user_id,role) VALUES (?,?,?) ON CONFLICT(whiteboard_id,user_id) DO UPDATE SET role=excluded.role");
|
||||
const remove = db.prepare("DELETE FROM whiteboard_permissions WHERE whiteboard_id=? AND user_id=?");
|
||||
const tx = db.transaction(() => {
|
||||
// Vorherigen Stand merken um neue User zu erkennen
|
||||
const before = db.prepare('SELECT user_id FROM whiteboard_permissions WHERE whiteboard_id=?').all(req.params.id).map(r => r.user_id);
|
||||
|
||||
const upsert = db.prepare("INSERT INTO whiteboard_permissions (whiteboard_id,user_id,role) VALUES (?,?,?) ON CONFLICT(whiteboard_id,user_id) DO UPDATE SET role=excluded.role");
|
||||
const remove = db.prepare("DELETE FROM whiteboard_permissions WHERE whiteboard_id=? AND user_id=?");
|
||||
db.transaction(() => {
|
||||
for (const p of permissions) {
|
||||
if (!p.user_id) continue;
|
||||
if (p.role === null || p.role === 'none') remove.run(req.params.id, p.user_id);
|
||||
else upsert.run(req.params.id, p.user_id, p.role);
|
||||
}
|
||||
});
|
||||
tx();
|
||||
})();
|
||||
|
||||
// Pushover an neu hinzugekommene User (fire & forget)
|
||||
const owner = db.prepare('SELECT username FROM users WHERE id=?').get(me);
|
||||
const newlyAdded = permissions.filter(p => p.role && p.role !== 'none' && !before.includes(p.user_id));
|
||||
for (const p of newlyAdded) {
|
||||
try {
|
||||
const poCfg = db.prepare('SELECT user_key, app_token FROM pushover_settings WHERE user_id=?').get(p.user_id);
|
||||
if (!poCfg?.app_token || !poCfg?.user_key) continue;
|
||||
const roleLabel = p.role === 'edit' ? 'bearbeiten' : 'ansehen';
|
||||
fetch('https://api.pushover.net/1/messages.json', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
token: poCfg.app_token,
|
||||
user: poCfg.user_key,
|
||||
title: '🖊 Whiteboard geteilt',
|
||||
message: `${owner.username} hat das Whiteboard "${wb.title}" mit dir geteilt (${roleLabel}).`,
|
||||
priority: 0,
|
||||
}),
|
||||
}).catch(() => {});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const updated = db.prepare(`
|
||||
SELECT p.*, u.username FROM whiteboard_permissions p
|
||||
JOIN users u ON u.id=p.user_id WHERE p.whiteboard_id=?
|
||||
|
||||
@@ -186,6 +186,8 @@ export default function Whiteboard({ toast, mobile }) {
|
||||
const [boards, setBoards] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [current, setCurrent] = useState(null); // { id, title, role }
|
||||
const [creating, setCreating] = useState(false);
|
||||
const [newTitle, setNewTitle] = useState('');
|
||||
|
||||
// ── Canvas-State ──────────────────────────────────────────────────────────
|
||||
const [elements, setElements] = useState([]);
|
||||
@@ -516,12 +518,36 @@ export default function Whiteboard({ toast, mobile }) {
|
||||
WHITEBOARD
|
||||
</h2>
|
||||
<div style={{ flex:1 }}/>
|
||||
<button onClick={async () => {
|
||||
try {
|
||||
const wb = await api('/tools/whiteboard', { body: { title: 'Neues Whiteboard' } });
|
||||
await openBoard(wb);
|
||||
} catch(e) { toast(e.message, 'error'); }
|
||||
}} style={S.btn('#4ECDC4')}>+ Neu</button>
|
||||
{creating ? (
|
||||
<div style={{ display:'flex', gap:6 }}>
|
||||
<input autoFocus value={newTitle} onChange={e=>setNewTitle(e.target.value)}
|
||||
onKeyDown={async e => {
|
||||
if (e.key === 'Enter') {
|
||||
if (!newTitle.trim()) return;
|
||||
try {
|
||||
const wb = await api('/tools/whiteboard', { body: { title: newTitle.trim() } });
|
||||
setCreating(false); setNewTitle('');
|
||||
await openBoard(wb);
|
||||
} catch(err) { toast(err.message, 'error'); }
|
||||
}
|
||||
if (e.key === 'Escape') { setCreating(false); setNewTitle(''); }
|
||||
}}
|
||||
placeholder="Name des Whiteboards"
|
||||
style={{ ...S.inp, width: mobile ? 160 : 220, fontSize:12 }}
|
||||
/>
|
||||
<button onClick={async () => {
|
||||
if (!newTitle.trim()) return;
|
||||
try {
|
||||
const wb = await api('/tools/whiteboard', { body: { title: newTitle.trim() } });
|
||||
setCreating(false); setNewTitle('');
|
||||
await openBoard(wb);
|
||||
} catch(err) { toast(err.message, 'error'); }
|
||||
}} style={S.btn('#4ECDC4', true)}>Erstellen</button>
|
||||
<button onClick={() => { setCreating(false); setNewTitle(''); }} style={S.btn('#888888', true)}>✕</button>
|
||||
</div>
|
||||
) : (
|
||||
<button onClick={() => setCreating(true)} style={S.btn('#4ECDC4')}>+ Neu</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{loading && <div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:12 }}>Lädt…</div>}
|
||||
|
||||
Reference in New Issue
Block a user