feat(logging): implement centralized logging system and replace console errors with structured logs
Some checks failed
Build & Push Docker Image / build (push) Has been cancelled
Build & Push Docker Image / build (release) Successful in 7m27s

feat(federation): add room sync and deletion notification endpoints for federated instances

fix(federation): handle room deletion and update settings during sync process

feat(federation): enhance FederatedRoomCard and FederatedRoomDetail components to display deleted rooms

i18n: add translations for room deletion messages in English and German
This commit is contained in:
2026-03-01 12:20:14 +01:00
parent 89b2a853d3
commit 57bb1fb696
22 changed files with 674 additions and 269 deletions

View File

@@ -11,9 +11,10 @@ import { getDb } from '../config/database.js';
import redis from '../config/redis.js';
import { authenticateToken, generateToken } from '../middleware/auth.js';
import { isMailerConfigured, sendVerificationEmail } from '../config/mailer.js';
import { log } from '../config/logger.js';
if (!process.env.JWT_SECRET) {
console.error('FATAL: JWT_SECRET environment variable is not set.');
log.auth.error('FATAL: JWT_SECRET environment variable is not set.');
process.exit(1);
}
const JWT_SECRET = process.env.JWT_SECRET;
@@ -174,7 +175,7 @@ router.post('/register', registerLimiter, async (req, res) => {
try {
await sendVerificationEmail(email.toLowerCase(), display_name, verifyUrl, appName);
} catch (mailErr) {
console.error('Verification mail failed:', mailErr.message);
log.auth.error(`Verification mail failed: ${mailErr.message}`);
// Account is created but email failed — user can resend from login page
return res.status(201).json({ needsVerification: true, emailFailed: true, message: 'Account created but verification email could not be sent. Please try resending.' });
}
@@ -193,7 +194,7 @@ router.post('/register', registerLimiter, async (req, res) => {
res.status(201).json({ token, user });
} catch (err) {
console.error('Register error:', err);
log.auth.error(`Register error: ${err.message}`);
res.status(500).json({ error: 'Registration failed' });
}
});
@@ -227,7 +228,7 @@ router.get('/verify-email', async (req, res) => {
res.json({ verified: true, message: 'Email verified successfully' });
} catch (err) {
console.error('Verify email error:', err);
log.auth.error(`Verify email error: ${err.message}`);
res.status(500).json({ error: 'Verification failed' });
}
});
@@ -282,13 +283,13 @@ router.post('/resend-verification', resendVerificationLimiter, async (req, res)
try {
await sendVerificationEmail(email.toLowerCase(), user.display_name || user.name, verifyUrl, appName);
} catch (mailErr) {
console.error('Resend verification mail failed:', mailErr.message);
log.auth.error(`Resend verification mail failed: ${mailErr.message}`);
return res.status(502).json({ error: 'Email could not be sent. Please check your SMTP configuration.' });
}
res.json({ message: 'If an account exists, a new email has been sent.' });
} catch (err) {
console.error('Resend verification error:', err);
log.auth.error(`Resend verification error: ${err.message}`);
res.status(500).json({ error: 'Internal server error' });
}
});
@@ -323,7 +324,7 @@ router.post('/login', loginLimiter, async (req, res) => {
res.json({ token, user: safeUser });
} catch (err) {
console.error('Login error:', err);
log.auth.error(`Login error: ${err.message}`);
res.status(500).json({ error: 'Login failed' });
}
});
@@ -341,14 +342,14 @@ router.post('/logout', authenticateToken, async (req, res) => {
try {
await redis.setex(`blacklist:${decoded.jti}`, ttl, '1');
} catch (redisErr) {
console.warn('Redis blacklist write failed:', redisErr.message);
log.auth.warn(`Redis blacklist write failed: ${redisErr.message}`);
}
}
}
res.json({ message: 'Logged out successfully' });
} catch (err) {
console.error('Logout error:', err);
log.auth.error(`Logout error: ${err.message}`);
res.status(500).json({ error: 'Logout failed' });
}
});
@@ -422,7 +423,7 @@ router.put('/profile', authenticateToken, profileLimiter, async (req, res) => {
const updated = await db.get('SELECT id, name, display_name, email, role, theme, language, avatar_color, avatar_image, email_verified FROM users WHERE id = ?', [req.user.id]);
res.json({ user: updated });
} catch (err) {
console.error('Profile update error:', err);
log.auth.error(`Profile update error: ${err.message}`);
res.status(500).json({ error: 'Profile could not be updated' });
}
});
@@ -457,7 +458,7 @@ router.put('/password', authenticateToken, passwordLimiter, async (req, res) =>
res.json({ message: 'Password changed successfully' });
} catch (err) {
console.error('Password change error:', err);
log.auth.error(`Password change error: ${err.message}`);
res.status(500).json({ error: 'Password could not be changed' });
}
});
@@ -514,7 +515,7 @@ router.post('/avatar', authenticateToken, avatarLimiter, async (req, res) => {
const updated = await db.get('SELECT id, name, display_name, email, role, theme, language, avatar_color, avatar_image, email_verified FROM users WHERE id = ?', [req.user.id]);
res.json({ user: updated });
} catch (err) {
console.error('Avatar upload error:', err);
log.auth.error(`Avatar upload error: ${err.message}`);
res.status(500).json({ error: 'Avatar could not be uploaded' });
}
});
@@ -533,7 +534,7 @@ router.delete('/avatar', authenticateToken, avatarLimiter, async (req, res) => {
const updated = await db.get('SELECT id, name, display_name, email, role, theme, language, avatar_color, avatar_image, email_verified FROM users WHERE id = ?', [req.user.id]);
res.json({ user: updated });
} catch (err) {
console.error('Avatar delete error:', err);
log.auth.error(`Avatar delete error: ${err.message}`);
res.status(500).json({ error: 'Avatar could not be removed' });
}
});