QR-Generator, Ordner-Sharing, Baustellenschild weg, Button-Fix
This commit is contained in:
@@ -467,4 +467,41 @@ if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='lin
|
||||
}
|
||||
|
||||
|
||||
// ── QR-Codes ──────────────────────────────────────────────────────────────────
|
||||
if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='qr_codes'").get()) {
|
||||
db.exec(`
|
||||
CREATE TABLE qr_codes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
label TEXT NOT NULL DEFAULT '',
|
||||
url TEXT NOT NULL,
|
||||
size INTEGER NOT NULL DEFAULT 256,
|
||||
fg_color TEXT NOT NULL DEFAULT '#000000',
|
||||
bg_color TEXT NOT NULL DEFAULT '#ffffff',
|
||||
margin INTEGER NOT NULL DEFAULT 4,
|
||||
dot_style TEXT NOT NULL DEFAULT 'square',
|
||||
corner_style TEXT NOT NULL DEFAULT 'square',
|
||||
caption TEXT NOT NULL DEFAULT '',
|
||||
caption_pos TEXT NOT NULL DEFAULT 'bottom',
|
||||
caption_color TEXT NOT NULL DEFAULT '#000000',
|
||||
caption_size INTEGER NOT NULL DEFAULT 14,
|
||||
created_at DATETIME DEFAULT NULL
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
// ── Link-Folder Shares ────────────────────────────────────────────────────────
|
||||
if (!db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='link_folder_shares'").get()) {
|
||||
db.exec(`
|
||||
CREATE TABLE link_folder_shares (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
folder_id INTEGER NOT NULL REFERENCES link_list_folders(id) ON DELETE CASCADE,
|
||||
shared_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
shared_with INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
created_at DATETIME DEFAULT NULL,
|
||||
UNIQUE(folder_id, shared_with)
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
module.exports = db;
|
||||
|
||||
@@ -67,6 +67,7 @@ fs.readdirSync(toolsDir, { withFileTypes: true })
|
||||
});
|
||||
|
||||
app.use('/api/tools/snippets', require('./tools/snippets/routes'));
|
||||
app.use('/api/tools/qrcodes', require('./tools/qrcodes/routes'));
|
||||
|
||||
const PUBLIC = path.join(__dirname, '../public');
|
||||
|
||||
@@ -78,9 +79,7 @@ app.get('/manifest.json', (_req, res) => {
|
||||
app.get('/sw.js', (_req, res) => {
|
||||
res.setHeader('Content-Type', 'application/javascript');
|
||||
res.setHeader('Service-Worker-Allowed', '/');
|
||||
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
|
||||
res.setHeader('Pragma', 'no-cache');
|
||||
res.setHeader('Expires', '0');
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.sendFile(path.join(PUBLIC, 'sw.js'));
|
||||
});
|
||||
|
||||
|
||||
@@ -86,7 +86,32 @@ router.get('/', authenticate, (req, res) => {
|
||||
ORDER BY l.title ASC
|
||||
`).all(uid);
|
||||
|
||||
res.json({ own, folders, shared, sharedByMe });
|
||||
// Ordner die mit mir geteilt wurden (inkl. deren Links)
|
||||
const sharedFolders = db.prepare(`
|
||||
SELECT f.*, u.username as owner_name
|
||||
FROM link_list_folders f
|
||||
JOIN link_folder_shares s ON s.folder_id=f.id
|
||||
JOIN users u ON u.id=f.user_id
|
||||
WHERE s.shared_with=?
|
||||
ORDER BY f.name ASC
|
||||
`).all(uid);
|
||||
|
||||
const sharedFolderLinks = sharedFolders.map(folder => ({
|
||||
...folder,
|
||||
links: db.prepare('SELECT * FROM link_list WHERE folder_id=? ORDER BY sort_order,id').all(folder.id)
|
||||
}));
|
||||
|
||||
// Ordner die ich geteilt habe
|
||||
const sharedFoldersByMe = db.prepare(`
|
||||
SELECT f.*, u.username as shared_with_name
|
||||
FROM link_list_folders f
|
||||
JOIN link_folder_shares s ON s.folder_id=f.id
|
||||
JOIN users u ON u.id=s.shared_with
|
||||
WHERE f.user_id=?
|
||||
ORDER BY f.name ASC
|
||||
`).all(uid);
|
||||
|
||||
res.json({ own, folders, shared, sharedByMe, sharedFolders: sharedFolderLinks, sharedFoldersByMe });
|
||||
});
|
||||
|
||||
router.post('/', authenticate, (req, res) => {
|
||||
@@ -153,4 +178,35 @@ router.delete('/:id/share/:userId', authenticate, (req, res) => {
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
// ── Ordner-Shares ─────────────────────────────────────────────────────────────
|
||||
router.get('/folders/:id/shares', authenticate, (req, res) => {
|
||||
const f = db.prepare('SELECT * FROM link_list_folders WHERE id=? AND user_id=?').get(req.params.id, req.user.id);
|
||||
if (!f) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||
const shares = db.prepare(`
|
||||
SELECT u.id, u.username, s.created_at as shared_at
|
||||
FROM link_folder_shares s JOIN users u ON u.id=s.shared_with
|
||||
WHERE s.folder_id=?
|
||||
`).all(f.id);
|
||||
res.json(shares);
|
||||
});
|
||||
|
||||
router.post('/folders/:id/share', authenticate, (req, res) => {
|
||||
const f = db.prepare('SELECT * FROM link_list_folders WHERE id=? AND user_id=?').get(req.params.id, req.user.id);
|
||||
if (!f) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||
const target = db.prepare('SELECT * FROM users WHERE username=?').get(req.body.username);
|
||||
if (!target) return res.status(404).json({ error: 'Benutzer nicht gefunden' });
|
||||
if (target.id === req.user.id) return res.status(400).json({ error: 'Kann nicht mit dir selbst teilen' });
|
||||
db.prepare(`INSERT OR IGNORE INTO link_folder_shares (folder_id, shared_by, shared_with, created_at) VALUES (?,?,?,datetime('now','localtime'))`)
|
||||
.run(f.id, req.user.id, target.id);
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
router.delete('/folders/:id/share/:userId', authenticate, (req, res) => {
|
||||
const f = db.prepare('SELECT * FROM link_list_folders WHERE id=? AND user_id=?').get(req.params.id, req.user.id);
|
||||
if (!f) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||
db.prepare('DELETE FROM link_folder_shares WHERE folder_id=? AND shared_with=?').run(f.id, req.params.userId);
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
||||
41
backend/src/tools/qrcodes/routes.js
Normal file
41
backend/src/tools/qrcodes/routes.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const express = require('express');
|
||||
const db = require('../../db');
|
||||
const { authenticate } = require('../../middleware/auth');
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', authenticate, (req, res) => {
|
||||
res.json(db.prepare('SELECT * FROM qr_codes WHERE user_id=? ORDER BY created_at DESC').all(req.user.id));
|
||||
});
|
||||
|
||||
router.post('/', authenticate, (req, res) => {
|
||||
const uid = req.user.id;
|
||||
const { label='', url, size=256, fg_color='#000000', bg_color='#ffffff', margin=4,
|
||||
dot_style='square', corner_style='square', caption='', caption_pos='bottom',
|
||||
caption_color='#000000', caption_size=14 } = req.body;
|
||||
if (!url?.trim()) return res.status(400).json({ error: 'URL erforderlich' });
|
||||
const r = db.prepare(`
|
||||
INSERT INTO qr_codes (user_id,label,url,size,fg_color,bg_color,margin,dot_style,corner_style,caption,caption_pos,caption_color,caption_size,created_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,datetime('now','localtime'))
|
||||
`).run(uid, label.trim(), url.trim(), size, fg_color, bg_color, margin, dot_style, corner_style, caption.trim(), caption_pos, caption_color, caption_size);
|
||||
res.json(db.prepare('SELECT * FROM qr_codes WHERE id=?').get(r.lastInsertRowid));
|
||||
});
|
||||
|
||||
router.put('/:id', authenticate, (req, res) => {
|
||||
const qr = db.prepare('SELECT * FROM qr_codes WHERE id=? AND user_id=?').get(req.params.id, req.user.id);
|
||||
if (!qr) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||
const fields = ['label','url','size','fg_color','bg_color','margin','dot_style','corner_style','caption','caption_pos','caption_color','caption_size'];
|
||||
const updates = {};
|
||||
fields.forEach(f => { if (req.body[f] !== undefined) updates[f] = req.body[f]; });
|
||||
if (!Object.keys(updates).length) return res.json(qr);
|
||||
const sets = Object.keys(updates).map(f=>`${f}=?`).join(',');
|
||||
db.prepare(`UPDATE qr_codes SET ${sets} WHERE id=?`).run(...Object.values(updates), qr.id);
|
||||
res.json(db.prepare('SELECT * FROM qr_codes WHERE id=?').get(qr.id));
|
||||
});
|
||||
|
||||
router.delete('/:id', authenticate, (req, res) => {
|
||||
const r = db.prepare('DELETE FROM qr_codes WHERE id=? AND user_id=?').run(req.params.id, req.user.id);
|
||||
if (!r.changes) return res.status(404).json({ error: 'Nicht gefunden' });
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user