fix: weitere fehlende Umlaute (Hinzufuegen, Eintraege, Passwoerter, erhaelt, enthaelt etc)
This commit is contained in:
@@ -2,7 +2,7 @@ import jwt from 'jsonwebtoken';
|
|||||||
import pool from '../config/database.js';
|
import pool from '../config/database.js';
|
||||||
|
|
||||||
// Verifiziert JWT und stellt req.user bereit
|
// Verifiziert JWT und stellt req.user bereit
|
||||||
// req.user enthaelt: { id, email, name, rolle, tenant_id }
|
// req.user enthält: { id, email, name, rolle, tenant_id }
|
||||||
// tenant_id ist NULL für SuperAdmins.
|
// tenant_id ist NULL für SuperAdmins.
|
||||||
export const authenticateToken = (req, res, next) => {
|
export const authenticateToken = (req, res, next) => {
|
||||||
const authHeader = req.headers['authorization'];
|
const authHeader = req.headers['authorization'];
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ router.post('/:kunde_id', upload.single('foto'), async (req, res) => {
|
|||||||
const [[k]] = await pool.query('SELECT id FROM kunden WHERE id=? AND tenant_id=?',
|
const [[k]] = await pool.query('SELECT id FROM kunden WHERE id=? AND tenant_id=?',
|
||||||
[req.params.kunde_id, req.user.tenant_id]);
|
[req.params.kunde_id, req.user.tenant_id]);
|
||||||
if (!k) {
|
if (!k) {
|
||||||
// Datei aufraeumen
|
// Datei aufräumen
|
||||||
try { fs.unlinkSync(req.file.path); } catch {}
|
try { fs.unlinkSync(req.file.path); } catch {}
|
||||||
return res.status(404).json({ error: 'Kunde nicht gefunden' });
|
return res.status(404).json({ error: 'Kunde nicht gefunden' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ router.post('/', upload.single('foto'), [
|
|||||||
if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });
|
if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });
|
||||||
const foto_url = req.file ? `/uploads/${req.file.filename}` : null;
|
const foto_url = req.file ? `/uploads/${req.file.filename}` : null;
|
||||||
try {
|
try {
|
||||||
// Sicherstellen: kunde_id + artikel_id gehoeren dem Tenant
|
// Sicherstellen: kunde_id + artikel_id gehören dem Tenant
|
||||||
const [[k]] = await pool.query('SELECT id FROM kunden WHERE id=? AND tenant_id=?',
|
const [[k]] = await pool.query('SELECT id FROM kunden WHERE id=? AND tenant_id=?',
|
||||||
[req.body.kunde_id, req.user.tenant_id]);
|
[req.body.kunde_id, req.user.tenant_id]);
|
||||||
const [[a]] = await pool.query('SELECT id FROM artikel WHERE id=? AND tenant_id=?',
|
const [[a]] = await pool.query('SELECT id FROM artikel WHERE id=? AND tenant_id=?',
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ router.put('/:id', [
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.delete('/:id', requireRole(['admin']), async (req, res) => {
|
router.delete('/:id', requireRole(['admin']), async (req, res) => {
|
||||||
if (req.params.id === req.user.id) return res.status(400).json({ error: 'Sie koennen sich nicht selbst löschen' });
|
if (req.params.id === req.user.id) return res.status(400).json({ error: 'Sie können sich nicht selbst löschen' });
|
||||||
try {
|
try {
|
||||||
const [r] = await pool.query('DELETE FROM mitarbeiter WHERE id=? AND tenant_id=?',
|
const [r] = await pool.query('DELETE FROM mitarbeiter WHERE id=? AND tenant_id=?',
|
||||||
[req.params.id, req.user.tenant_id]);
|
[req.params.id, req.user.tenant_id]);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ bootstrapSuperAdmin()
|
|||||||
.catch(err => console.error('Bootstrap-Fehler:', err))
|
.catch(err => console.error('Bootstrap-Fehler:', err))
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
app.listen(PORT, '0.0.0.0', () => {
|
app.listen(PORT, '0.0.0.0', () => {
|
||||||
console.log(`Backend laeuft auf Port ${PORT}`);
|
console.log(`Backend läuft auf Port ${PORT}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default function PasswordChange() {
|
|||||||
const submit = async (e) => {
|
const submit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (form.newPassword.length < 6) return setErr('Neues Passwort min. 6 Zeichen');
|
if (form.newPassword.length < 6) return setErr('Neues Passwort min. 6 Zeichen');
|
||||||
if (form.newPassword !== form.confirm) return setErr('Passwoerter stimmen nicht überein');
|
if (form.newPassword !== form.confirm) return setErr('Passwörter stimmen nicht überein');
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
try {
|
try {
|
||||||
await api.changePassword(form.currentPassword, form.newPassword);
|
await api.changePassword(form.currentPassword, form.newPassword);
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export default function AdminDashboard() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedKunde ? (
|
{selectedKunde ? (
|
||||||
rows.length === 0 ? <div className="card text-center text-slate-500">Keine Eintraege im Zeitraum.</div> : (
|
rows.length === 0 ? <div className="card text-center text-slate-500">Keine Einträge im Zeitraum.</div> : (
|
||||||
<div className="card overflow-x-auto p-0">
|
<div className="card overflow-x-auto p-0">
|
||||||
<table className="min-w-full text-sm">
|
<table className="min-w-full text-sm">
|
||||||
<thead className="bg-slate-50 text-xs uppercase text-slate-600">
|
<thead className="bg-slate-50 text-xs uppercase text-slate-600">
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export default function VorgangsListe({ refreshFlag, mode }) {
|
|||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="text-center text-slate-500 py-12">Lade…</div>
|
<div className="text-center text-slate-500 py-12">Lade…</div>
|
||||||
) : view.length === 0 ? (
|
) : view.length === 0 ? (
|
||||||
<div className="card text-center text-slate-500">Keine Eintraege.</div>
|
<div className="card text-center text-slate-500">Keine Einträge.</div>
|
||||||
) : (
|
) : (
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{view.map(item => (
|
{view.map(item => (
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default function MitarbeiterVerwaltung({ user }) {
|
|||||||
<option value="admin">Admin</option>
|
<option value="admin">Admin</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={add} className="btn-primary mt-3"><FaPlus /> Hinzufuegen</button>
|
<button onClick={add} className="btn-primary mt-3"><FaPlus /> Hinzufügen</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card overflow-x-auto p-0">
|
<div className="card overflow-x-auto p-0">
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ function CreatedInfoModal({ info, onClose }) {
|
|||||||
<div onClick={onClose} className="fixed inset-0 z-50 bg-slate-900/60 flex items-center justify-center p-4">
|
<div onClick={onClose} className="fixed inset-0 z-50 bg-slate-900/60 flex items-center justify-center p-4">
|
||||||
<div onClick={e => e.stopPropagation()} className="bg-white rounded-xl max-w-md w-full p-6 shadow-soft space-y-3">
|
<div onClick={e => e.stopPropagation()} className="bg-white rounded-xl max-w-md w-full p-6 shadow-soft space-y-3">
|
||||||
<h3 className="text-lg font-semibold text-emerald-700">Demo-Account angelegt</h3>
|
<h3 className="text-lg font-semibold text-emerald-700">Demo-Account angelegt</h3>
|
||||||
<p className="text-sm text-slate-600">Der Interessent erhaelt eine Einladungs-Mail. Hier zur Sicherheit die Daten:</p>
|
<p className="text-sm text-slate-600">Der Interessent erhält eine Einladungs-Mail. Hier zur Sicherheit die Daten:</p>
|
||||||
<dl className="bg-slate-50 rounded-lg p-3 text-sm space-y-1.5">
|
<dl className="bg-slate-50 rounded-lg p-3 text-sm space-y-1.5">
|
||||||
<div><dt className="inline text-slate-500">Slug: </dt><dd className="inline font-mono">{info.slug}</dd></div>
|
<div><dt className="inline text-slate-500">Slug: </dt><dd className="inline font-mono">{info.slug}</dd></div>
|
||||||
<div><dt className="inline text-slate-500">E-Mail: </dt><dd className="inline">{info.admin_email}</dd></div>
|
<div><dt className="inline text-slate-500">E-Mail: </dt><dd className="inline">{info.admin_email}</dd></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user