diff --git a/backend/src/controllers/settings.controller.js b/backend/src/controllers/settings.controller.js index f3d7ebb..1b7ed72 100644 --- a/backend/src/controllers/settings.controller.js +++ b/backend/src/controllers/settings.controller.js @@ -1,6 +1,7 @@ -const { Settings } = require('../models'); +const { Settings, AdminUser } = require('../models'); const mailService = require('../services/mail.service'); const telegramService = require('../services/telegram.service'); +const bcrypt = require('bcrypt'); // Get all settings exports.getAllSettings = async (req, res, next) => { @@ -208,5 +209,147 @@ exports.testTelegram = async (req, res, next) => { } }; +// Get admin user info (current logged in user) +exports.getAdminInfo = async (req, res, next) => { + try { + const userId = req.session.userId; + + if (!userId) { + return res.status(401).json({ + success: false, + error: 'Authentication required', + }); + } + + const admin = await AdminUser.findByPk(userId, { + attributes: ['id', 'username', 'email', 'full_name', 'created_at', 'updated_at'], + }); + + if (!admin) { + return res.status(404).json({ + success: false, + error: 'Admin user not found', + }); + } + + res.json({ + success: true, + data: admin, + }); + } catch (error) { + next(error); + } +}; + +// Update admin user info (username and/or password) +exports.updateAdminInfo = async (req, res, next) => { + try { + const userId = req.session.userId; + + if (!userId) { + return res.status(401).json({ + success: false, + error: 'Authentication required', + }); + } + + const { username, current_password, new_password, confirm_password } = req.body; + + const admin = await AdminUser.findByPk(userId); + + if (!admin) { + return res.status(404).json({ + success: false, + error: 'Admin user not found', + }); + } + + // Update username if provided + if (username && username.trim() !== '') { + const newUsername = username.trim(); + + // Validate username + if (newUsername.length < 3) { + return res.status(400).json({ + success: false, + error: 'Kullanıcı adı en az 3 karakter olmalıdır', + }); + } + + // Check if username is already taken by another user + const existingUser = await AdminUser.findOne({ + where: { + username: newUsername, + id: { [require('sequelize').Op.ne]: userId }, + }, + }); + + if (existingUser) { + return res.status(400).json({ + success: false, + error: 'Bu kullanıcı adı zaten kullanılıyor', + }); + } + + admin.username = newUsername; + } + + // Update password if provided + if (new_password) { + // Validate password + if (new_password.length < 8) { + return res.status(400).json({ + success: false, + error: 'Şifre en az 8 karakter olmalıdır', + }); + } + + // Check password confirmation + if (new_password !== confirm_password) { + return res.status(400).json({ + success: false, + error: 'Yeni şifreler eşleşmiyor', + }); + } + + // Verify current password + if (!current_password) { + return res.status(400).json({ + success: false, + error: 'Mevcut şifre gereklidir', + }); + } + + const isPasswordValid = await bcrypt.compare(current_password, admin.password); + + if (!isPasswordValid) { + return res.status(400).json({ + success: false, + error: 'Mevcut şifre yanlış', + }); + } + + // Hash new password + const hashedPassword = await bcrypt.hash(new_password, 10); + admin.password = hashedPassword; + } + + await admin.save(); + + res.json({ + success: true, + message: 'Admin bilgileri başarıyla güncellendi', + data: { + id: admin.id, + username: admin.username, + email: admin.email, + full_name: admin.full_name, + }, + }); + } catch (error) { + next(error); + } +}; + module.exports = exports; diff --git a/backend/src/routes/settings.routes.js b/backend/src/routes/settings.routes.js index 9f3b42c..f2b99c5 100644 --- a/backend/src/routes/settings.routes.js +++ b/backend/src/routes/settings.routes.js @@ -13,5 +13,9 @@ router.put('/system', settingsController.updateSystemSettings); router.post('/test-gmail', settingsController.testGmail); router.post('/test-telegram', settingsController.testTelegram); +// Admin user management +router.get('/admin', settingsController.getAdminInfo); +router.put('/admin', settingsController.updateAdminInfo); + module.exports = router; diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index 2b1e5a6..b48b076 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -30,13 +30,21 @@ function Settings() { ollama_server_url: '', ollama_model: '', }); + const [adminInfo, setAdminInfo] = useState({ + username: '', + current_password: '', + new_password: '', + confirm_password: '', + }); const [loading, setLoading] = useState(true); const [testLoading, setTestLoading] = useState({ mail: false, telegram: false, ollama: false }); - const [alerts, setAlerts] = useState({ mail: null, telegram: null, ollama: null }); + const [alerts, setAlerts] = useState({ mail: null, telegram: null, ollama: null, admin: null }); const [ollamaModels, setOllamaModels] = useState([]); + const [adminSaving, setAdminSaving] = useState(false); useEffect(() => { loadSettings(); + loadAdminInfo(); }, []); const loadSettings = async () => { @@ -73,6 +81,24 @@ function Settings() { } }; + const loadAdminInfo = async () => { + try { + const response = await axios.get(`${API_URL}/api/settings/admin`, { + withCredentials: true, + }); + if (response.data.success && response.data.data) { + setAdminInfo({ + username: response.data.data.username || '', + current_password: '', + new_password: '', + confirm_password: '', + }); + } + } catch (error) { + console.error('Failed to load admin info:', error); + } + }; + const handleSave = async () => { try { await Promise.all([ @@ -189,6 +215,60 @@ function Settings() { } }; + const handleSaveAdmin = async () => { + setAdminSaving(true); + setAlerts({ ...alerts, admin: null }); + + try { + const updateData = {}; + + // Only include fields that are being changed + if (adminInfo.username && adminInfo.username.trim() !== '') { + updateData.username = adminInfo.username.trim(); + } + + if (adminInfo.new_password) { + updateData.new_password = adminInfo.new_password; + updateData.confirm_password = adminInfo.confirm_password; + updateData.current_password = adminInfo.current_password; + } + + const response = await axios.put( + `${API_URL}/api/settings/admin`, + updateData, + { withCredentials: true } + ); + + if (response.data.success) { + setAlerts({ + ...alerts, + admin: { severity: 'success', message: response.data.message || 'Admin bilgileri güncellendi' }, + }); + + // Clear password fields + setAdminInfo({ + ...adminInfo, + current_password: '', + new_password: '', + confirm_password: '', + }); + + // Reload admin info to get updated username + await loadAdminInfo(); + } + } catch (error) { + setAlerts({ + ...alerts, + admin: { + severity: 'error', + message: error.response?.data?.error || 'Admin bilgileri güncellenemedi', + }, + }); + } finally { + setAdminSaving(false); + } + }; + if (loading) { return ( @@ -389,6 +469,87 @@ function Settings() { + {/* Admin User Settings */} + + + + 🔐 Admin Kullanıcı Bilgileri + + + Kullanıcı adı ve şifrenizi değiştirebilirsiniz + + + + setAdminInfo({ ...adminInfo, username: e.target.value }) + } + helperText="En az 3 karakter olmalıdır" + /> + + + + Şifre Değiştir (Opsiyonel) + + + + setAdminInfo({ ...adminInfo, current_password: e.target.value }) + } + helperText="Yeni şifre belirlemek için mevcut şifrenizi girin" + /> + + + setAdminInfo({ ...adminInfo, new_password: e.target.value }) + } + helperText="En az 8 karakter olmalıdır" + /> + + + setAdminInfo({ ...adminInfo, confirm_password: e.target.value }) + } + helperText="Yeni şifreyi tekrar girin" + /> + + {alerts.admin && ( + + {alerts.admin.message} + + )} + + + + + + + {/* Ollama Settings */}